diff options
Diffstat (limited to 'shared')
129 files changed, 20703 insertions, 16983 deletions
diff --git a/shared/c-siphash/src/c-siphash.c b/shared/c-siphash/src/c-siphash.c index fae3abad..720e403a 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/meson.build b/shared/meson.build index 48880ec4..0f46a00c 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 43dd344c..2a5c6451 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 af3328c1..c1d92865 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/util/timer.c b/shared/n-acd/src/util/timer.c index 3c9570a1..af2a887c 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 701df1f6..31235253 100644 --- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c +++ b/shared/n-dhcp4/src/n-dhcp4-c-connection.c @@ -1231,7 +1231,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 695a112a..515814d4 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) { @@ -242,6 +242,32 @@ _c_public_ void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint } /** + * n_dhcp4_client_lease_get_server_identifier() - get the server identifier + * @lease: the lease to operate on + * @addr: return argument for the server identifier + * + * Gets the address contained in the server-identifier DHCP option, in network + * byte order. + * + * Return: 0 on success, negative error code on failure. + */ +_c_public_ int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr) { + uint8_t *data; + size_t n_data; + int r; + + r = n_dhcp4_incoming_query(lease->message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &data, &n_data); + if (r) + return r; + if (n_data < sizeof(struct in_addr)) + return N_DHCP4_E_MALFORMED; + + memcpy(addr, data, sizeof(struct in_addr)); + + return 0; +} + +/** * n_dhcp4_client_lease_query() - query the lease for an option * @lease: the lease to operate on * @option: the DHCP4 option code diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c index f3d4f265..7f20ac05 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 403a6932..1dedbf30 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 90f8f0c3..db7b24ff 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-socket.c b/shared/n-dhcp4/src/n-dhcp4-socket.c index 7291c780..3e703b4f 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/n-dhcp4.h b/shared/n-dhcp4/src/n-dhcp4.h index 81452848..435c5600 100644 --- a/shared/n-dhcp4/src/n-dhcp4.h +++ b/shared/n-dhcp4/src/n-dhcp4.h @@ -171,6 +171,7 @@ void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *s void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep); void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep); int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap); +int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr); int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease); int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease); diff --git a/shared/n-dhcp4/src/util/packet.c b/shared/n-dhcp4/src/util/packet.c index 95e65940..ef18b0b4 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 ace6ede1..6338c8b8 100644 --- a/shared/nm-default.h +++ b/shared/nm-default.h @@ -1,82 +1,81 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2015 Red Hat, Inc. */ +/* With autotools (and also meson), all our source files are expected to include <config.h>. + * as very first header. Then they are expected to include "config-extra.h" and a small set + * of headers that we always want to have included (depending on what sources we compile + * (as determined by NETWORKMANAGER_COMPILATION define) that can be "nm-glib-aux/nm-macros-internal.h" + * and similar. + * + * To simplify that, all our source files are only expected to include "nm-default.h" as first, + * and thereby rely on getting a basic set of headers already. + */ + #ifndef __NM_DEFAULT_H__ #define __NM_DEFAULT_H__ -#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB (1 << 0) -#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB (1 << 1) -#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG (1 << 2) -#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM (1 << 3) -#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE (1 << 4) -#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE (1 << 5) -#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL (1 << 6) -#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE (1 << 7) -#define NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON (1 << 10) -#define NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD (1 << 11) - -#define NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL \ - ) - -#define NM_NETWORKMANAGER_COMPILATION_LIBNM ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL \ - ) - -#define NM_NETWORKMANAGER_COMPILATION_CLIENT ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ - ) - -#define NM_NETWORKMANAGER_COMPILATION_DAEMON ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ - | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL \ - | NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON \ - ) - -#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ - | NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD \ - ) - -#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_DAEMON \ - | NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED \ - ) - -#define NM_NETWORKMANAGER_COMPILATION_GLIB ( 0 \ - | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ - ) +#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB (1 << 0) +#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB (1 << 1) +#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG (1 << 2) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM (1 << 3) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE (1 << 4) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE (1 << 5) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL (1 << 6) +#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE (1 << 7) +#define NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON (1 << 10) +#define NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD (1 << 11) + +#define NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + +#define NM_NETWORKMANAGER_COMPILATION_LIBNM \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + +#define NM_NETWORKMANAGER_COMPILATION_CLIENT \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE) + +#define NM_NETWORKMANAGER_COMPILATION_DAEMON \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB \ + | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL \ + | NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) + +#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED \ + (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB | NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD) + +#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD \ + (0 | NM_NETWORKMANAGER_COMPILATION_DAEMON | NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED) + +#define NM_NETWORKMANAGER_COMPILATION_GLIB (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB) #ifndef NETWORKMANAGER_COMPILATION -#error Define NETWORKMANAGER_COMPILATION accordingly + #error Define NETWORKMANAGER_COMPILATION accordingly #endif #ifndef G_LOG_DOMAIN -#if defined(NETWORKMANAGER_COMPILATION_TEST) -#define G_LOG_DOMAIN "test" -#elif NETWORKMANAGER_COMPILATION & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON -#define G_LOG_DOMAIN "NetworkManager" -#else -#error Need to define G_LOG_DOMAIN -#endif -#elif defined (NETWORKMANAGER_COMPILATION_TEST) || (NETWORKMANAGER_COMPILATION & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) -#error Do not define G_LOG_DOMAIN with NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON + #if defined(NETWORKMANAGER_COMPILATION_TEST) + #define G_LOG_DOMAIN "test" + #elif NETWORKMANAGER_COMPILATION & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON + #define G_LOG_DOMAIN "NetworkManager" + #else + #error Need to define G_LOG_DOMAIN + #endif +#elif defined(NETWORKMANAGER_COMPILATION_TEST) \ + || (NETWORKMANAGER_COMPILATION & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) + #error Do not define G_LOG_DOMAIN with NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON #endif /*****************************************************************************/ @@ -84,8 +83,8 @@ /* always include these headers for our internal source files. */ #ifndef ___CONFIG_H__ -#define ___CONFIG_H__ -#include <config.h> + #define ___CONFIG_H__ + #include <config.h> #endif #include "config-extra.h" @@ -93,14 +92,14 @@ /* for internal compilation we don't want the deprecation macros * to be in effect. Define the widest range of versions to effectively * disable deprecation checks */ -#define NM_VERSION_MIN_REQUIRED NM_VERSION_0_9_8 +#define NM_VERSION_MIN_REQUIRED NM_VERSION_0_9_8 #ifndef NM_MORE_ASSERTS -#define NM_MORE_ASSERTS 0 + #define NM_MORE_ASSERTS 0 #endif #if NM_MORE_ASSERTS == 0 -/* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST() + /* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST() * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type * by calling g_type_check_instance_cast(). * This check has a certain overhead without being helpful. @@ -147,14 +146,14 @@ * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless. * Disable them for our production builds. */ -#ifndef G_DISABLE_CAST_CHECKS -#define G_DISABLE_CAST_CHECKS -#endif + #ifndef G_DISABLE_CAST_CHECKS + #define G_DISABLE_CAST_CHECKS + #endif #endif #if NM_MORE_ASSERTS == 0 -#ifndef G_DISABLE_CAST_CHECKS -/* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking + #ifndef G_DISABLE_CAST_CHECKS + /* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary * because commonly this cast is needed during something like * @@ -176,9 +175,9 @@ * * Just patch G_VARIANT_TYPE() to perform no check. */ -#undef G_VARIANT_TYPE -#define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string)) -#endif + #undef G_VARIANT_TYPE + #define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string)) + #endif #endif #include <stdlib.h> @@ -187,20 +186,20 @@ #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB -#include <glib.h> + #include <glib.h> -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB -#error Cannot define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG and NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB -#endif -#include <glib/gi18n.h> -#elif (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB -#include <glib/gi18n-lib.h> -#endif + #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG + #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB + #error Cannot define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG and NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB + #endif + #include <glib/gi18n.h> + #elif (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB + #include <glib/gi18n-lib.h> + #endif -/*****************************************************************************/ + /*****************************************************************************/ -#if NM_MORE_ASSERTS == 0 + #if NM_MORE_ASSERTS == 0 /* glib assertions (g_return_*(), g_assert*()) contain a textual representation * of the checked statement. This part of the assertion blows up the size of the @@ -209,84 +208,95 @@ * assertion fails. That shall suffice. */ static inline void -_nm_g_return_if_fail_warning (const char *log_domain, - const char *file, - int line) +_nm_g_return_if_fail_warning(const char *log_domain, const char *file, int line) { - char file_buf[256 + 15]; + char file_buf[256 + 15]; - g_snprintf (file_buf, sizeof (file_buf), "((%s:%d))", file, line); - g_return_if_fail_warning (log_domain, file_buf, "<dropped>"); + g_snprintf(file_buf, sizeof(file_buf), "((%s:%d))", file, line); + g_return_if_fail_warning(log_domain, file_buf, "<dropped>"); } -#define g_return_if_fail_warning(log_domain, pretty_function, expression) \ - _nm_g_return_if_fail_warning (log_domain, __FILE__, __LINE__) - -#define g_assertion_message_expr(domain, file, line, func, expr) \ - g_assertion_message_expr(domain, file, line, "<unknown-fcn>", (expr) ? "<dropped>" : NULL) - -#undef g_return_val_if_reached -#define g_return_val_if_reached(val) \ - G_STMT_START { \ - g_log (G_LOG_DOMAIN, \ - G_LOG_LEVEL_CRITICAL, \ - "file %s: line %d (%s): should not be reached", \ - __FILE__, \ - __LINE__, \ - "<dropped>"); \ - return (val); \ - } G_STMT_END - -#undef g_return_if_reached -#define g_return_if_reached() \ - G_STMT_START { \ - g_log (G_LOG_DOMAIN, \ - G_LOG_LEVEL_CRITICAL, \ - "file %s: line %d (%s): should not be reached", \ - __FILE__, \ - __LINE__, \ - "<dropped>"); \ - return; \ - } G_STMT_END - -#define NM_ASSERT_G_RETURN_EXPR(expr) "<dropped>" -#define NM_ASSERT_NO_MSG 1 - -#else - -#define NM_ASSERT_G_RETURN_EXPR(expr) ""expr"" -#define NM_ASSERT_NO_MSG 0 - -#endif - -/*****************************************************************************/ - -#include "nm-glib-aux/nm-macros-internal.h" -#include "nm-glib-aux/nm-shared-utils.h" -#include "nm-glib-aux/nm-errno.h" -#include "nm-glib-aux/nm-hash-utils.h" - -/*****************************************************************************/ - -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE -#include "nm-version.h" -#endif - -/*****************************************************************************/ - -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON -#include "nm-core-types.h" -#include "nm-types.h" -#include "nm-logging.h" -#endif - -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE -#include "nm-libnm-utils.h" -#endif - -#if ((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM) && !((NETWORKMANAGER_COMPILATION) & (NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL)) -#include "NetworkManager.h" -#endif + #define g_return_if_fail_warning(log_domain, pretty_function, expression) \ + _nm_g_return_if_fail_warning(log_domain, __FILE__, __LINE__) + + #define g_assertion_message_expr(domain, file, line, func, expr) \ + g_assertion_message_expr(domain, \ + file, \ + line, \ + "<unknown-fcn>", \ + (expr) ? "<dropped>" : NULL) + + #undef g_return_val_if_reached + #define g_return_val_if_reached(val) \ + G_STMT_START \ + { \ + g_log(G_LOG_DOMAIN, \ + G_LOG_LEVEL_CRITICAL, \ + "file %s: line %d (%s): should not be reached", \ + __FILE__, \ + __LINE__, \ + "<dropped>"); \ + return (val); \ + } \ + G_STMT_END + + #undef g_return_if_reached + #define g_return_if_reached() \ + G_STMT_START \ + { \ + g_log(G_LOG_DOMAIN, \ + G_LOG_LEVEL_CRITICAL, \ + "file %s: line %d (%s): should not be reached", \ + __FILE__, \ + __LINE__, \ + "<dropped>"); \ + return; \ + } \ + G_STMT_END + + #define NM_ASSERT_G_RETURN_EXPR(expr) "<dropped>" + #define NM_ASSERT_NO_MSG 1 + + #else + + #define NM_ASSERT_G_RETURN_EXPR(expr) "" expr "" + #define NM_ASSERT_NO_MSG 0 + + #endif + + /*****************************************************************************/ + + #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" + #include "nm-glib-aux/nm-hash-utils.h" + + /*****************************************************************************/ + + #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE + #include "nm-version.h" + #endif + + /*****************************************************************************/ + + #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON + #include "nm-core-types.h" + #include "nm-types.h" + #include "nm-logging.h" + #endif + + #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE + #include "nm-libnm-utils.h" + #endif + + #if ((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM) \ + && !((NETWORKMANAGER_COMPILATION) \ + & (NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE \ + | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL)) + #include "NetworkManager.h" + #endif #endif /* NM_NETWORKMANAGER_COMPILATION_WITH_GLIB */ diff --git a/shared/nm-glib-aux/nm-c-list.h b/shared/nm-glib-aux/nm-c-list.h index 256dda74..e19774dd 100644 --- a/shared/nm-glib-aux/nm-c-list.h +++ b/shared/nm-glib-aux/nm-c-list.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2014 Red Hat, Inc. */ @@ -10,91 +10,90 @@ /*****************************************************************************/ -#define nm_c_list_contains_entry(list, what, member) \ - ({ \ - typeof (what) _what = (what); \ - \ - _what && c_list_contains (list, &_what->member); \ - }) +#define nm_c_list_contains_entry(list, what, member) \ + ({ \ + typeof(what) _what = (what); \ + \ + _what &&c_list_contains(list, &_what->member); \ + }) /* iterate over the list backwards. */ -#define nm_c_list_for_each_entry_prev(_iter, _list, _m) \ - for (_iter = c_list_entry ((_list)->prev, __typeof__ (*_iter), _m); \ - &(_iter)->_m != (_list); \ - _iter = c_list_entry ((_iter)->_m.prev, __typeof__ (*_iter), _m)) +#define nm_c_list_for_each_entry_prev(_iter, _list, _m) \ + for (_iter = c_list_entry((_list)->prev, __typeof__(*_iter), _m); &(_iter)->_m != (_list); \ + _iter = c_list_entry((_iter)->_m.prev, __typeof__(*_iter), _m)) /*****************************************************************************/ typedef struct { - CList lst; - void *data; + CList lst; + void *data; } NMCListElem; static inline NMCListElem * -nm_c_list_elem_new_stale (void *data) +nm_c_list_elem_new_stale(void *data) { - NMCListElem *elem; + NMCListElem *elem; - elem = g_slice_new (NMCListElem); - elem->data = data; - return elem; + elem = g_slice_new(NMCListElem); + elem->data = data; + return elem; } static inline gboolean -nm_c_list_elem_free_full (NMCListElem *elem, GDestroyNotify free_fcn) +nm_c_list_elem_free_full(NMCListElem *elem, GDestroyNotify free_fcn) { - if (!elem) - return FALSE; - c_list_unlink_stale (&elem->lst); - if (free_fcn) - free_fcn (elem->data); - g_slice_free (NMCListElem, elem); - return TRUE; + if (!elem) + return FALSE; + c_list_unlink_stale(&elem->lst); + if (free_fcn) + free_fcn(elem->data); + g_slice_free(NMCListElem, elem); + return TRUE; } static inline gboolean -nm_c_list_elem_free (NMCListElem *elem) +nm_c_list_elem_free(NMCListElem *elem) { - return nm_c_list_elem_free_full (elem, NULL); + return nm_c_list_elem_free_full(elem, NULL); } static inline void * -nm_c_list_elem_free_steal (NMCListElem *elem) +nm_c_list_elem_free_steal(NMCListElem *elem) { - gpointer data; + gpointer data; - if (!elem) - return NULL; - data = elem->data; - nm_c_list_elem_free_full (elem, NULL); - return data; + if (!elem) + return NULL; + data = elem->data; + nm_c_list_elem_free_full(elem, NULL); + return data; } static inline void -nm_c_list_elem_free_all (CList *head, GDestroyNotify free_fcn) +nm_c_list_elem_free_all(CList *head, GDestroyNotify free_fcn) { - NMCListElem *elem; + NMCListElem *elem; - while ((elem = c_list_first_entry (head, NMCListElem, lst))) - nm_c_list_elem_free_full (elem, free_fcn); + while ((elem = c_list_first_entry(head, NMCListElem, lst))) + nm_c_list_elem_free_full(elem, free_fcn); } #define nm_c_list_elem_find_first(head, arg, predicate) \ - ({ \ - CList *const _head = (head); \ - NMCListElem *_result = NULL; \ - NMCListElem *_elem; \ - \ - c_list_for_each_entry (_elem, _head, lst) { \ - void *const arg = _elem->data; \ - \ - if (predicate) { \ - _result = _elem; \ - break; \ - } \ - } \ - _result; \ - }) + ({ \ + CList *const _head = (head); \ + NMCListElem *_result = NULL; \ + NMCListElem *_elem; \ + \ + c_list_for_each_entry (_elem, _head, lst) { \ + void *const arg = _elem->data; \ + \ + if (predicate) { \ + _result = _elem; \ + break; \ + } \ + } \ + _result; \ + }) /** * nm_c_list_elem_find_first_ptr: @@ -108,9 +107,9 @@ nm_c_list_elem_free_all (CList *head, GDestroyNotify free_fcn) * Returns: the found list element or %NULL if not found. */ static inline NMCListElem * -nm_c_list_elem_find_first_ptr (CList *head, gconstpointer needle) +nm_c_list_elem_find_first_ptr(CList *head, gconstpointer needle) { - return nm_c_list_elem_find_first (head, x, x == needle); + return nm_c_list_elem_find_first(head, x, x == needle); } /*****************************************************************************/ @@ -129,20 +128,19 @@ nm_c_list_elem_find_first_ptr (CList *head, gconstpointer needle) * linked at the right place. */ static inline gboolean -nm_c_list_move_before (CList *lst, CList *elem) +nm_c_list_move_before(CList *lst, CList *elem) { - nm_assert (lst); - nm_assert (elem); - - if ( lst != elem - && lst->prev != elem) { - c_list_unlink_stale (elem); - c_list_link_before (lst, elem); - return TRUE; - } - return FALSE; + nm_assert(lst); + nm_assert(elem); + + if (lst != elem && lst->prev != elem) { + c_list_unlink_stale(elem); + c_list_link_before(lst, elem); + return TRUE; + } + return FALSE; } -#define nm_c_list_move_tail(lst, elem) nm_c_list_move_before (lst, elem) +#define nm_c_list_move_tail(lst, elem) nm_c_list_move_before(lst, elem) /** * nm_c_list_move_after: @@ -158,29 +156,30 @@ nm_c_list_move_before (CList *lst, CList *elem) * linked at the right place. */ static inline gboolean -nm_c_list_move_after (CList *lst, CList *elem) +nm_c_list_move_after(CList *lst, CList *elem) { - nm_assert (lst); - nm_assert (elem); - - if ( lst != elem - && lst->next != elem) { - c_list_unlink_stale (elem); - c_list_link_after (lst, elem); - return TRUE; - } - return FALSE; + nm_assert(lst); + nm_assert(elem); + + if (lst != elem && lst->next != elem) { + c_list_unlink_stale(elem); + c_list_link_after(lst, elem); + return TRUE; + } + return FALSE; } -#define nm_c_list_move_front(lst, elem) nm_c_list_move_after (lst, elem) - -#define nm_c_list_free_all(lst, type, member, destroy_fcn) \ - G_STMT_START { \ - CList *const _lst = (lst); \ - type *_elem; \ - \ - while ((_elem = c_list_first_entry (_lst, type, member))) { \ - destroy_fcn (_elem); \ - } \ - } G_STMT_END +#define nm_c_list_move_front(lst, elem) nm_c_list_move_after(lst, elem) + +#define nm_c_list_free_all(lst, type, member, destroy_fcn) \ + G_STMT_START \ + { \ + CList *const _lst = (lst); \ + type * _elem; \ + \ + while ((_elem = c_list_first_entry(_lst, type, member))) { \ + destroy_fcn(_elem); \ + } \ + } \ + G_STMT_END #endif /* __NM_C_LIST_H__ */ diff --git a/shared/nm-glib-aux/nm-dbus-aux.c b/shared/nm-glib-aux/nm-dbus-aux.c index 54e54ca7..e47797a8 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.c +++ b/shared/nm-glib-aux/nm-dbus-aux.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2019 Red Hat, Inc. */ @@ -10,207 +10,201 @@ /*****************************************************************************/ static void -_nm_dbus_connection_call_get_name_owner_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) +_nm_dbus_connection_call_get_name_owner_cb(GObject *source, GAsyncResult *res, gpointer user_data) { - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - const char *owner = NULL; - gpointer orig_user_data; - NMDBusConnectionCallGetNameOwnerCb callback; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError * error = NULL; + const char * owner = NULL; + gpointer orig_user_data; + NMDBusConnectionCallGetNameOwnerCb callback; - nm_utils_user_data_unpack (user_data, &orig_user_data, &callback); + nm_utils_user_data_unpack(user_data, &orig_user_data, &callback); - ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); - if (ret) - g_variant_get (ret, "(&s)", &owner); + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); + if (ret) + g_variant_get(ret, "(&s)", &owner); - callback (owner, error, orig_user_data); + callback(owner, error, orig_user_data); } void -nm_dbus_connection_call_get_name_owner (GDBusConnection *dbus_connection, - const char *service_name, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallGetNameOwnerCb callback, - gpointer user_data) +nm_dbus_connection_call_get_name_owner(GDBusConnection * dbus_connection, + const char * service_name, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallGetNameOwnerCb callback, + gpointer user_data) { - nm_assert (callback); - - g_dbus_connection_call (dbus_connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetNameOwner", - g_variant_new ("(s)", service_name), - G_VARIANT_TYPE ("(s)"), - G_DBUS_CALL_FLAGS_NONE, - timeout_msec, - cancellable, - _nm_dbus_connection_call_get_name_owner_cb, - nm_utils_user_data_pack (user_data, callback)); + nm_assert(callback); + + g_dbus_connection_call(dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetNameOwner", + g_variant_new("(s)", service_name), + G_VARIANT_TYPE("(s)"), + G_DBUS_CALL_FLAGS_NONE, + timeout_msec, + cancellable, + _nm_dbus_connection_call_get_name_owner_cb, + nm_utils_user_data_pack(user_data, callback)); } /*****************************************************************************/ static void -_nm_dbus_connection_call_default_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) +_nm_dbus_connection_call_default_cb(GObject *source, GAsyncResult *res, gpointer user_data) { - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - gpointer orig_user_data; - NMDBusConnectionCallDefaultCb callback; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError * error = NULL; + gpointer orig_user_data; + NMDBusConnectionCallDefaultCb callback; - nm_utils_user_data_unpack (user_data, &orig_user_data, &callback); + nm_utils_user_data_unpack(user_data, &orig_user_data, &callback); - ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); - nm_assert ((!!ret) != (!!error)); + nm_assert((!!ret) != (!!error)); - callback (ret, error, orig_user_data); + callback(ret, error, orig_user_data); } void -nm_dbus_connection_call_get_all (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - const char *interface_name, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallDefaultCb callback, - gpointer user_data) +nm_dbus_connection_call_get_all(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + const char * interface_name, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data) { - nm_assert (callback); - - g_dbus_connection_call (dbus_connection, - bus_name, - object_path, - DBUS_INTERFACE_PROPERTIES, - "GetAll", - g_variant_new ("(s)", interface_name), - G_VARIANT_TYPE ("(a{sv})"), - G_DBUS_CALL_FLAGS_NONE, - timeout_msec, - cancellable, - _nm_dbus_connection_call_default_cb, - nm_utils_user_data_pack (user_data, callback)); + nm_assert(callback); + + g_dbus_connection_call(dbus_connection, + bus_name, + object_path, + DBUS_INTERFACE_PROPERTIES, + "GetAll", + g_variant_new("(s)", interface_name), + G_VARIANT_TYPE("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + timeout_msec, + cancellable, + _nm_dbus_connection_call_default_cb, + nm_utils_user_data_pack(user_data, callback)); } -void nm_dbus_connection_call_set (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - const char *interface_name, - const char *property_name, - GVariant *value, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallDefaultCb callback, - gpointer user_data) +void +nm_dbus_connection_call_set(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + const char * interface_name, + const char * property_name, + GVariant * value, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data) { - g_dbus_connection_call (dbus_connection, - bus_name, - object_path, - DBUS_INTERFACE_PROPERTIES, - "Set", - g_variant_new ("(ssv)", - interface_name, - property_name, - value), - G_VARIANT_TYPE ("()"), - G_DBUS_CALL_FLAGS_NONE, - timeout_msec, - cancellable, - callback ? _nm_dbus_connection_call_default_cb : NULL, - callback ? nm_utils_user_data_pack (user_data, callback) : NULL); + g_dbus_connection_call(dbus_connection, + bus_name, + object_path, + DBUS_INTERFACE_PROPERTIES, + "Set", + g_variant_new("(ssv)", interface_name, property_name, value), + G_VARIANT_TYPE("()"), + G_DBUS_CALL_FLAGS_NONE, + timeout_msec, + cancellable, + callback ? _nm_dbus_connection_call_default_cb : NULL, + callback ? nm_utils_user_data_pack(user_data, callback) : NULL); } /*****************************************************************************/ static void -_nm_dbus_connection_call_get_managed_objects_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) +_nm_dbus_connection_call_get_managed_objects_cb(GObject * source, + GAsyncResult *res, + gpointer user_data) { - gs_unref_variant GVariant *ret = NULL; - gs_unref_variant GVariant *arg = NULL; - gs_free_error GError *error = NULL; - gpointer orig_user_data; - NMDBusConnectionCallDefaultCb callback; + gs_unref_variant GVariant *ret = NULL; + gs_unref_variant GVariant *arg = NULL; + gs_free_error GError * error = NULL; + gpointer orig_user_data; + NMDBusConnectionCallDefaultCb callback; - nm_utils_user_data_unpack (user_data, &orig_user_data, &callback); + nm_utils_user_data_unpack(user_data, &orig_user_data, &callback); - ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error); - nm_assert ((!!ret) != (!!error)); + nm_assert((!!ret) != (!!error)); - if (ret) { - nm_assert (g_variant_is_of_type (ret, G_VARIANT_TYPE ("(a{oa{sa{sv}}})"))); - arg = g_variant_get_child_value (ret, 0); - } + if (ret) { + nm_assert(g_variant_is_of_type(ret, G_VARIANT_TYPE("(a{oa{sa{sv}}})"))); + arg = g_variant_get_child_value(ret, 0); + } - callback (arg, error, orig_user_data); + callback(arg, error, orig_user_data); } void -nm_dbus_connection_call_get_managed_objects (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - GDBusCallFlags flags, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallDefaultCb callback, - gpointer user_data) +nm_dbus_connection_call_get_managed_objects(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + GDBusCallFlags flags, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data) { - nm_assert (callback); - - g_dbus_connection_call (dbus_connection, - bus_name, - object_path, - DBUS_INTERFACE_OBJECT_MANAGER, - "GetManagedObjects", - NULL, - G_VARIANT_TYPE ("(a{oa{sa{sv}}})"), - flags, - timeout_msec, - cancellable, - _nm_dbus_connection_call_get_managed_objects_cb, - nm_utils_user_data_pack (user_data, callback)); + nm_assert(callback); + + g_dbus_connection_call(dbus_connection, + bus_name, + object_path, + DBUS_INTERFACE_OBJECT_MANAGER, + "GetManagedObjects", + NULL, + G_VARIANT_TYPE("(a{oa{sa{sv}}})"), + flags, + timeout_msec, + cancellable, + _nm_dbus_connection_call_get_managed_objects_cb, + nm_utils_user_data_pack(user_data, callback)); } /*****************************************************************************/ static void -_call_finish_cb (GObject *source, - GAsyncResult *result, - gpointer user_data, - gboolean return_void, - gboolean strip_dbus_error) +_call_finish_cb(GObject * source, + GAsyncResult *result, + gpointer user_data, + gboolean return_void, + gboolean strip_dbus_error) { - gs_unref_object GTask *task = user_data; - gs_unref_variant GVariant *ret = NULL; - GError *error = NULL; - - nm_assert (G_IS_DBUS_CONNECTION (source)); - nm_assert (G_IS_TASK (user_data)); - - ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - if (!ret) { - if (strip_dbus_error) - g_dbus_error_strip_remote_error (error); - g_task_return_error (task, error); - return; - } - - if (!return_void) - g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify) g_variant_unref); - else { - nm_assert (g_variant_is_of_type (ret, G_VARIANT_TYPE ("()"))); - g_task_return_boolean (task, TRUE); - } + gs_unref_object GTask *task = user_data; + gs_unref_variant GVariant *ret = NULL; + GError * error = NULL; + + nm_assert(G_IS_DBUS_CONNECTION(source)); + nm_assert(G_IS_TASK(user_data)); + + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); + if (!ret) { + if (strip_dbus_error) + g_dbus_error_strip_remote_error(error); + g_task_return_error(task, error); + return; + } + + if (!return_void) + g_task_return_pointer(task, g_steal_pointer(&ret), (GDestroyNotify) g_variant_unref); + else { + nm_assert(g_variant_is_of_type(ret, G_VARIANT_TYPE("()"))); + g_task_return_boolean(task, TRUE); + } } /** @@ -224,11 +218,9 @@ _call_finish_cb (GObject *source, * - the GTask is returned either with error or TRUE boolean. */ void -nm_dbus_connection_call_finish_void_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +nm_dbus_connection_call_finish_void_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - _call_finish_cb (source, result, user_data, TRUE, FALSE); + _call_finish_cb(source, result, user_data, TRUE, FALSE); } /** @@ -238,11 +230,11 @@ nm_dbus_connection_call_finish_void_cb (GObject *source, * is that on error this will first call g_dbus_error_strip_remote_error() on the error. */ void -nm_dbus_connection_call_finish_void_strip_dbus_error_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +nm_dbus_connection_call_finish_void_strip_dbus_error_cb(GObject * source, + GAsyncResult *result, + gpointer user_data) { - _call_finish_cb (source, result, user_data, TRUE, TRUE); + _call_finish_cb(source, result, user_data, TRUE, TRUE); } /** @@ -255,11 +247,9 @@ nm_dbus_connection_call_finish_void_strip_dbus_error_cb (GObject *source, * - the GTask is returned either with error or with a pointer containing the GVariant. */ void -nm_dbus_connection_call_finish_variant_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +nm_dbus_connection_call_finish_variant_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - _call_finish_cb (source, result, user_data, FALSE, FALSE); + _call_finish_cb(source, result, user_data, FALSE, FALSE); } /** @@ -269,34 +259,34 @@ nm_dbus_connection_call_finish_variant_cb (GObject *source, * is that on error this will first call g_dbus_error_strip_remote_error() on the error. */ void -nm_dbus_connection_call_finish_variant_strip_dbus_error_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) +nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject * source, + GAsyncResult *result, + gpointer user_data) { - _call_finish_cb (source, result, user_data, FALSE, TRUE); + _call_finish_cb(source, result, user_data, FALSE, TRUE); } /*****************************************************************************/ gboolean -_nm_dbus_error_is (GError *error, ...) +_nm_dbus_error_is(GError *error, ...) { - gs_free char *dbus_error = NULL; - const char *name; - va_list ap; - - dbus_error = g_dbus_error_get_remote_error (error); - if (!dbus_error) - return FALSE; - - va_start (ap, error); - while ((name = va_arg (ap, const char *))) { - if (nm_streq (dbus_error, name)) { - va_end (ap); - return TRUE; - } - } - va_end (ap); - - return FALSE; + gs_free char *dbus_error = NULL; + const char * name; + va_list ap; + + dbus_error = g_dbus_error_get_remote_error(error); + if (!dbus_error) + return FALSE; + + va_start(ap, error); + while ((name = va_arg(ap, const char *))) { + if (nm_streq(dbus_error, name)) { + va_end(ap); + return TRUE; + } + } + va_end(ap); + + return FALSE; } diff --git a/shared/nm-glib-aux/nm-dbus-aux.h b/shared/nm-glib-aux/nm-dbus-aux.h index fcf394d1..7b0b008d 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.h +++ b/shared/nm-glib-aux/nm-dbus-aux.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2019 Red Hat, Inc. */ @@ -11,194 +11,189 @@ /*****************************************************************************/ static inline gboolean -nm_clear_g_dbus_connection_signal (GDBusConnection *dbus_connection, - guint *id) +nm_clear_g_dbus_connection_signal(GDBusConnection *dbus_connection, guint *id) { - guint v; - - if ( id - && (v = *id)) { - *id = 0; - g_dbus_connection_signal_unsubscribe (dbus_connection, v); - return TRUE; - } - return FALSE; + guint v; + + if (id && (v = *id)) { + *id = 0; + g_dbus_connection_signal_unsubscribe(dbus_connection, v); + return TRUE; + } + return FALSE; } /*****************************************************************************/ -typedef void (*NMDBusConnectionCallDefaultCb) (GVariant *result, - GError *error, - gpointer user_data); +typedef void (*NMDBusConnectionCallDefaultCb)(GVariant *result, GError *error, gpointer user_data); /*****************************************************************************/ static inline void -nm_dbus_connection_call_start_service_by_name (GDBusConnection *dbus_connection, - const char *name, - int timeout_msec, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +nm_dbus_connection_call_start_service_by_name(GDBusConnection * dbus_connection, + const char * name, + int timeout_msec, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - g_dbus_connection_call (dbus_connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "StartServiceByName", - g_variant_new ("(su)", name, 0u), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - timeout_msec, - cancellable, - callback, - user_data); + g_dbus_connection_call(dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName", + g_variant_new("(su)", name, 0u), + G_VARIANT_TYPE("(u)"), + G_DBUS_CALL_FLAGS_NONE, + timeout_msec, + cancellable, + callback, + user_data); } /*****************************************************************************/ static inline guint -nm_dbus_connection_signal_subscribe_name_owner_changed (GDBusConnection *dbus_connection, - const char *service_name, - GDBusSignalCallback callback, - gpointer user_data, - GDestroyNotify user_data_free_func) +nm_dbus_connection_signal_subscribe_name_owner_changed(GDBusConnection * dbus_connection, + const char * service_name, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) { - return g_dbus_connection_signal_subscribe (dbus_connection, - DBUS_SERVICE_DBUS, - DBUS_INTERFACE_DBUS, - "NameOwnerChanged", - DBUS_PATH_DBUS, - service_name, - G_DBUS_SIGNAL_FLAGS_NONE, - callback, - user_data, - user_data_free_func); + return g_dbus_connection_signal_subscribe(dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged", + DBUS_PATH_DBUS, + service_name, + G_DBUS_SIGNAL_FLAGS_NONE, + callback, + user_data, + user_data_free_func); } -typedef void (*NMDBusConnectionCallGetNameOwnerCb) (const char *name_owner, - GError *error, - gpointer user_data); +typedef void (*NMDBusConnectionCallGetNameOwnerCb)(const char *name_owner, + GError * error, + gpointer user_data); -void nm_dbus_connection_call_get_name_owner (GDBusConnection *dbus_connection, - const char *service_name, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallGetNameOwnerCb callback, - gpointer user_data); +void nm_dbus_connection_call_get_name_owner(GDBusConnection * dbus_connection, + const char * service_name, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallGetNameOwnerCb callback, + gpointer user_data); static inline guint -nm_dbus_connection_signal_subscribe_properties_changed (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - const char *interface_name, - GDBusSignalCallback callback, - gpointer user_data, - GDestroyNotify user_data_free_func) +nm_dbus_connection_signal_subscribe_properties_changed(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + const char * interface_name, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) { - nm_assert (bus_name); - - /* it seems that using a non-unique name causes problems that we get signals - * also from unrelated senders. Usually, you are anyway monitoring the name-owner, - * so you should have the unique name at hand. - * - * If not, investigate this, ensure that it works, and lift this restriction. */ - nm_assert (g_dbus_is_unique_name (bus_name)); - - return g_dbus_connection_signal_subscribe (dbus_connection, - bus_name, - DBUS_INTERFACE_PROPERTIES, - "PropertiesChanged", - object_path, - interface_name, - G_DBUS_SIGNAL_FLAGS_NONE, - callback, - user_data, - user_data_free_func); + nm_assert(bus_name); + + /* it seems that using a non-unique name causes problems that we get signals + * also from unrelated senders. Usually, you are anyway monitoring the name-owner, + * so you should have the unique name at hand. + * + * If not, investigate this, ensure that it works, and lift this restriction. */ + nm_assert(g_dbus_is_unique_name(bus_name)); + + return g_dbus_connection_signal_subscribe(dbus_connection, + bus_name, + DBUS_INTERFACE_PROPERTIES, + "PropertiesChanged", + object_path, + interface_name, + G_DBUS_SIGNAL_FLAGS_NONE, + callback, + user_data, + user_data_free_func); } -void nm_dbus_connection_call_get_all (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - const char *interface_name, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallDefaultCb callback, - gpointer user_data); - -void nm_dbus_connection_call_set (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - const char *interface_name, - const char *property_name, - GVariant *value, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallDefaultCb callback, - gpointer user_data); +void nm_dbus_connection_call_get_all(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + const char * interface_name, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data); + +void nm_dbus_connection_call_set(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + const char * interface_name, + const char * property_name, + GVariant * value, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data); /*****************************************************************************/ static inline guint -nm_dbus_connection_signal_subscribe_object_manager (GDBusConnection *dbus_connection, - const char *service_name, - const char *object_path, - const char *signal_name, - GDBusSignalCallback callback, - gpointer user_data, - GDestroyNotify user_data_free_func) +nm_dbus_connection_signal_subscribe_object_manager(GDBusConnection * dbus_connection, + const char * service_name, + const char * object_path, + const char * signal_name, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) { - return g_dbus_connection_signal_subscribe (dbus_connection, - service_name, - DBUS_INTERFACE_OBJECT_MANAGER, - signal_name, - object_path, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - callback, - user_data, - user_data_free_func); + return g_dbus_connection_signal_subscribe(dbus_connection, + service_name, + DBUS_INTERFACE_OBJECT_MANAGER, + signal_name, + object_path, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + callback, + user_data, + user_data_free_func); } -void nm_dbus_connection_call_get_managed_objects (GDBusConnection *dbus_connection, - const char *bus_name, - const char *object_path, - GDBusCallFlags flags, - int timeout_msec, - GCancellable *cancellable, - NMDBusConnectionCallDefaultCb callback, - gpointer user_data); +void nm_dbus_connection_call_get_managed_objects(GDBusConnection * dbus_connection, + const char * bus_name, + const char * object_path, + GDBusCallFlags flags, + int timeout_msec, + GCancellable * cancellable, + NMDBusConnectionCallDefaultCb callback, + gpointer user_data); /*****************************************************************************/ -void nm_dbus_connection_call_finish_void_cb (GObject *source, - GAsyncResult *result, - gpointer user_data); +void +nm_dbus_connection_call_finish_void_cb(GObject *source, GAsyncResult *result, gpointer user_data); -void nm_dbus_connection_call_finish_void_strip_dbus_error_cb (GObject *source, - GAsyncResult *result, - gpointer user_data); +void nm_dbus_connection_call_finish_void_strip_dbus_error_cb(GObject * source, + GAsyncResult *result, + gpointer user_data); -void nm_dbus_connection_call_finish_variant_cb (GObject *source, - GAsyncResult *result, - gpointer user_data); +void nm_dbus_connection_call_finish_variant_cb(GObject * source, + GAsyncResult *result, + gpointer user_data); -void nm_dbus_connection_call_finish_variant_strip_dbus_error_cb (GObject *source, - GAsyncResult *result, - gpointer user_data); +void nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject * source, + GAsyncResult *result, + gpointer user_data); /*****************************************************************************/ -gboolean _nm_dbus_error_is (GError *error, ...) G_GNUC_NULL_TERMINATED; +gboolean _nm_dbus_error_is(GError *error, ...) G_GNUC_NULL_TERMINATED; -#define nm_dbus_error_is(error, ...) \ - ({ \ - GError *const _error = (error); \ - \ - _error && _nm_dbus_error_is (_error, __VA_ARGS__, NULL); \ - }) +#define nm_dbus_error_is(error, ...) \ + ({ \ + GError *const _error = (error); \ + \ + _error &&_nm_dbus_error_is(_error, __VA_ARGS__, NULL); \ + }) #define NM_DBUS_ERROR_NAME_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" diff --git a/shared/nm-glib-aux/nm-dedup-multi.c b/shared/nm-glib-aux/nm-dedup-multi.c index 6e23228e..4a16f850 100644 --- a/shared/nm-glib-aux/nm-dedup-multi.c +++ b/shared/nm-glib-aux/nm-dedup-multi.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -13,383 +13,379 @@ /*****************************************************************************/ typedef struct { - /* the stack-allocated lookup entry. It has a compatible - * memory layout with NMDedupMultiEntry and NMDedupMultiHeadEntry. - * - * It is recognizable by having lst_entries_sentinel.next set to NULL. - * Contrary to the other entries, which have lst_entries.next - * always non-NULL. - * */ - CList lst_entries_sentinel; - const NMDedupMultiObj *obj; - const NMDedupMultiIdxType *idx_type; - bool lookup_head; + /* the stack-allocated lookup entry. It has a compatible + * memory layout with NMDedupMultiEntry and NMDedupMultiHeadEntry. + * + * It is recognizable by having lst_entries_sentinel.next set to NULL. + * Contrary to the other entries, which have lst_entries.next + * always non-NULL. + * */ + CList lst_entries_sentinel; + const NMDedupMultiObj * obj; + const NMDedupMultiIdxType *idx_type; + bool lookup_head; } LookupEntry; struct _NMDedupMultiIndex { - int ref_count; - GHashTable *idx_entries; - GHashTable *idx_objs; + int ref_count; + GHashTable *idx_entries; + GHashTable *idx_objs; }; /*****************************************************************************/ static void -ASSERT_idx_type (const NMDedupMultiIdxType *idx_type) +ASSERT_idx_type(const NMDedupMultiIdxType *idx_type) { - nm_assert (idx_type); + nm_assert(idx_type); #if NM_MORE_ASSERTS > 10 - nm_assert (idx_type->klass); - nm_assert (idx_type->klass->idx_obj_id_hash_update); - nm_assert (idx_type->klass->idx_obj_id_equal); - nm_assert (!!idx_type->klass->idx_obj_partition_hash_update == !!idx_type->klass->idx_obj_partition_equal); - nm_assert (idx_type->lst_idx_head.next); + nm_assert(idx_type->klass); + nm_assert(idx_type->klass->idx_obj_id_hash_update); + nm_assert(idx_type->klass->idx_obj_id_equal); + nm_assert(!!idx_type->klass->idx_obj_partition_hash_update + == !!idx_type->klass->idx_obj_partition_equal); + nm_assert(idx_type->lst_idx_head.next); #endif } void -nm_dedup_multi_idx_type_init (NMDedupMultiIdxType *idx_type, - const NMDedupMultiIdxTypeClass *klass) +nm_dedup_multi_idx_type_init(NMDedupMultiIdxType *idx_type, const NMDedupMultiIdxTypeClass *klass) { - nm_assert (idx_type); - nm_assert (klass); + nm_assert(idx_type); + nm_assert(klass); - memset (idx_type, 0, sizeof (*idx_type)); - idx_type->klass = klass; - c_list_init (&idx_type->lst_idx_head); + *idx_type = (NMDedupMultiIdxType){ + .klass = klass, + .lst_idx_head = C_LIST_INIT(idx_type->lst_idx_head), + }; - ASSERT_idx_type (idx_type); + ASSERT_idx_type(idx_type); } /*****************************************************************************/ static NMDedupMultiEntry * -_entry_lookup_obj (const NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj) +_entry_lookup_obj(const NMDedupMultiIndex * self, + const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj) { - const LookupEntry stack_entry = { - .obj = obj, - .idx_type = idx_type, - .lookup_head = FALSE, - }; - - ASSERT_idx_type (idx_type); - return g_hash_table_lookup (self->idx_entries, &stack_entry); + const LookupEntry stack_entry = { + .obj = obj, + .idx_type = idx_type, + .lookup_head = FALSE, + }; + + ASSERT_idx_type(idx_type); + return g_hash_table_lookup(self->idx_entries, &stack_entry); } static NMDedupMultiHeadEntry * -_entry_lookup_head (const NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj) +_entry_lookup_head(const NMDedupMultiIndex * self, + const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj) { - NMDedupMultiHeadEntry *head_entry; - const LookupEntry stack_entry = { - .obj = obj, - .idx_type = idx_type, - .lookup_head = TRUE, - }; - - ASSERT_idx_type (idx_type); - - if (!idx_type->klass->idx_obj_partition_equal) { - if (c_list_is_empty (&idx_type->lst_idx_head)) - head_entry = NULL; - else { - nm_assert (c_list_length (&idx_type->lst_idx_head) == 1); - head_entry = c_list_entry (idx_type->lst_idx_head.next, NMDedupMultiHeadEntry, lst_idx); - } - nm_assert (head_entry == g_hash_table_lookup (self->idx_entries, &stack_entry)); - return head_entry; - } - - return g_hash_table_lookup (self->idx_entries, &stack_entry); + NMDedupMultiHeadEntry *head_entry; + const LookupEntry stack_entry = { + .obj = obj, + .idx_type = idx_type, + .lookup_head = TRUE, + }; + + ASSERT_idx_type(idx_type); + + if (!idx_type->klass->idx_obj_partition_equal) { + if (c_list_is_empty(&idx_type->lst_idx_head)) + head_entry = NULL; + else { + nm_assert(c_list_length(&idx_type->lst_idx_head) == 1); + head_entry = c_list_entry(idx_type->lst_idx_head.next, NMDedupMultiHeadEntry, lst_idx); + } + nm_assert(head_entry == g_hash_table_lookup(self->idx_entries, &stack_entry)); + return head_entry; + } + + return g_hash_table_lookup(self->idx_entries, &stack_entry); } static void -_entry_unpack (const NMDedupMultiEntry *entry, - const NMDedupMultiIdxType **out_idx_type, - const NMDedupMultiObj **out_obj, - gboolean *out_lookup_head) +_entry_unpack(const NMDedupMultiEntry * entry, + const NMDedupMultiIdxType **out_idx_type, + const NMDedupMultiObj ** out_obj, + gboolean * out_lookup_head) { - const NMDedupMultiHeadEntry *head_entry; - const LookupEntry *lookup_entry; - - nm_assert (entry); - - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (LookupEntry, lst_entries_sentinel) == G_STRUCT_OFFSET (NMDedupMultiEntry, lst_entries)); - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, lst_entries) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, lst_entries_head)); - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, obj) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, idx_type)); - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, is_head) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, is_head)); - - if (!entry->lst_entries.next) { - /* the entry is stack-allocated by _entry_lookup(). */ - lookup_entry = (LookupEntry *) entry; - *out_obj = lookup_entry->obj; - *out_idx_type = lookup_entry->idx_type; - *out_lookup_head = lookup_entry->lookup_head; - } else if (entry->is_head) { - head_entry = (NMDedupMultiHeadEntry *) entry; - nm_assert (!c_list_is_empty (&head_entry->lst_entries_head)); - *out_obj = c_list_entry (head_entry->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj; - *out_idx_type = head_entry->idx_type; - *out_lookup_head = TRUE; - } else { - *out_obj = entry->obj; - *out_idx_type = entry->head->idx_type; - *out_lookup_head = FALSE; - } - - nm_assert (NM_IN_SET (*out_lookup_head, FALSE, TRUE)); - ASSERT_idx_type (*out_idx_type); - - /* for lookup of the head, we allow to omit object, but only - * if the idx_type does not partition the objects. Otherwise, we - * require a obj to compare. */ - nm_assert ( !*out_lookup_head - || ( *out_obj - || !(*out_idx_type)->klass->idx_obj_partition_equal)); - - /* lookup of the object requires always an object. */ - nm_assert ( *out_lookup_head - || *out_obj); + const NMDedupMultiHeadEntry *head_entry; + const LookupEntry * lookup_entry; + + nm_assert(entry); + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(LookupEntry, lst_entries_sentinel) + == G_STRUCT_OFFSET(NMDedupMultiEntry, lst_entries)); + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDedupMultiEntry, lst_entries) + == G_STRUCT_OFFSET(NMDedupMultiHeadEntry, lst_entries_head)); + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDedupMultiEntry, obj) + == G_STRUCT_OFFSET(NMDedupMultiHeadEntry, idx_type)); + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDedupMultiEntry, is_head) + == G_STRUCT_OFFSET(NMDedupMultiHeadEntry, is_head)); + + if (!entry->lst_entries.next) { + /* the entry is stack-allocated by _entry_lookup(). */ + lookup_entry = (LookupEntry *) entry; + *out_obj = lookup_entry->obj; + *out_idx_type = lookup_entry->idx_type; + *out_lookup_head = lookup_entry->lookup_head; + } else if (entry->is_head) { + head_entry = (NMDedupMultiHeadEntry *) entry; + nm_assert(!c_list_is_empty(&head_entry->lst_entries_head)); + *out_obj = + c_list_entry(head_entry->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj; + *out_idx_type = head_entry->idx_type; + *out_lookup_head = TRUE; + } else { + *out_obj = entry->obj; + *out_idx_type = entry->head->idx_type; + *out_lookup_head = FALSE; + } + + nm_assert(NM_IN_SET(*out_lookup_head, FALSE, TRUE)); + ASSERT_idx_type(*out_idx_type); + + /* for lookup of the head, we allow to omit object, but only + * if the idx_type does not partition the objects. Otherwise, we + * require a obj to compare. */ + nm_assert(!*out_lookup_head || (*out_obj || !(*out_idx_type)->klass->idx_obj_partition_equal)); + + /* lookup of the object requires always an object. */ + nm_assert(*out_lookup_head || *out_obj); } static guint -_dict_idx_entries_hash (const NMDedupMultiEntry *entry) +_dict_idx_entries_hash(const NMDedupMultiEntry *entry) { - const NMDedupMultiIdxType *idx_type; - const NMDedupMultiObj *obj; - gboolean lookup_head; - NMHashState h; + const NMDedupMultiIdxType *idx_type; + const NMDedupMultiObj * obj; + gboolean lookup_head; + NMHashState h; - _entry_unpack (entry, &idx_type, &obj, &lookup_head); + _entry_unpack(entry, &idx_type, &obj, &lookup_head); - nm_hash_init (&h, 1914869417u); - if (idx_type->klass->idx_obj_partition_hash_update) { - nm_assert (obj); - idx_type->klass->idx_obj_partition_hash_update (idx_type, obj, &h); - } + nm_hash_init(&h, 1914869417u); + if (idx_type->klass->idx_obj_partition_hash_update) { + nm_assert(obj); + idx_type->klass->idx_obj_partition_hash_update(idx_type, obj, &h); + } - if (!lookup_head) - idx_type->klass->idx_obj_id_hash_update (idx_type, obj, &h); + if (!lookup_head) + idx_type->klass->idx_obj_id_hash_update(idx_type, obj, &h); - nm_hash_update_val (&h, idx_type); - return nm_hash_complete (&h); + nm_hash_update_val(&h, idx_type); + return nm_hash_complete(&h); } static gboolean -_dict_idx_entries_equal (const NMDedupMultiEntry *entry_a, - const NMDedupMultiEntry *entry_b) +_dict_idx_entries_equal(const NMDedupMultiEntry *entry_a, const NMDedupMultiEntry *entry_b) { - const NMDedupMultiIdxType *idx_type_a, *idx_type_b; - const NMDedupMultiObj *obj_a, *obj_b; - gboolean lookup_head_a, lookup_head_b; - - _entry_unpack (entry_a, &idx_type_a, &obj_a, &lookup_head_a); - _entry_unpack (entry_b, &idx_type_b, &obj_b, &lookup_head_b); - - if ( idx_type_a != idx_type_b - || lookup_head_a != lookup_head_b) - return FALSE; - if (!nm_dedup_multi_idx_type_partition_equal (idx_type_a, obj_a, obj_b)) - return FALSE; - if ( !lookup_head_a - && !nm_dedup_multi_idx_type_id_equal (idx_type_a, obj_a, obj_b)) - return FALSE; - return TRUE; + const NMDedupMultiIdxType *idx_type_a, *idx_type_b; + const NMDedupMultiObj * obj_a, *obj_b; + gboolean lookup_head_a, lookup_head_b; + + _entry_unpack(entry_a, &idx_type_a, &obj_a, &lookup_head_a); + _entry_unpack(entry_b, &idx_type_b, &obj_b, &lookup_head_b); + + if (idx_type_a != idx_type_b || lookup_head_a != lookup_head_b) + return FALSE; + if (!nm_dedup_multi_idx_type_partition_equal(idx_type_a, obj_a, obj_b)) + return FALSE; + if (!lookup_head_a && !nm_dedup_multi_idx_type_id_equal(idx_type_a, obj_a, obj_b)) + return FALSE; + return TRUE; } /*****************************************************************************/ static gboolean -_add (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj, - NMDedupMultiEntry *entry, - NMDedupMultiIdxMode mode, - const NMDedupMultiEntry *entry_order, - NMDedupMultiHeadEntry *head_existing, - const NMDedupMultiEntry **out_entry, - const NMDedupMultiObj **out_obj_old) +_add(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + const NMDedupMultiObj * obj, + NMDedupMultiEntry * entry, + NMDedupMultiIdxMode mode, + const NMDedupMultiEntry * entry_order, + NMDedupMultiHeadEntry * head_existing, + const NMDedupMultiEntry **out_entry, + const NMDedupMultiObj ** out_obj_old) { - NMDedupMultiHeadEntry *head_entry; - const NMDedupMultiObj *obj_new, *obj_old; - gboolean add_head_entry = FALSE; - - nm_assert (self); - ASSERT_idx_type (idx_type); - nm_assert (obj); - nm_assert (NM_IN_SET (mode, - NM_DEDUP_MULTI_IDX_MODE_PREPEND, - NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, - NM_DEDUP_MULTI_IDX_MODE_APPEND, - NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE)); - nm_assert (!head_existing || head_existing->idx_type == idx_type); - nm_assert (({ - const NMDedupMultiHeadEntry *_h; - gboolean _ok = TRUE; - if (head_existing) { - _h = nm_dedup_multi_index_lookup_head (self, idx_type, obj); - if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING) - _ok = (_h == NULL); - else - _ok = (_h == head_existing); - } - _ok; - })); - - if (entry) { - gboolean changed = FALSE; - - nm_dedup_multi_entry_set_dirty (entry, FALSE); - - nm_assert (!head_existing || entry->head == head_existing); - nm_assert (!entry_order || entry_order->head == entry->head); - nm_assert (!entry_order || c_list_contains (&entry->lst_entries, &entry_order->lst_entries)); - nm_assert (!entry_order || c_list_contains (&entry_order->lst_entries, &entry->lst_entries)); - - switch (mode) { - case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE: - if (entry_order) { - if (nm_c_list_move_before ((CList *) &entry_order->lst_entries, &entry->lst_entries)) - changed = TRUE; - } else { - if (nm_c_list_move_front ((CList *) &entry->head->lst_entries_head, &entry->lst_entries)) - changed = TRUE; - } - break; - case NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE: - if (entry_order) { - if (nm_c_list_move_after ((CList *) &entry_order->lst_entries, &entry->lst_entries)) - changed = TRUE; - } else { - if (nm_c_list_move_tail ((CList *) &entry->head->lst_entries_head, &entry->lst_entries)) - changed = TRUE; - } - break; - case NM_DEDUP_MULTI_IDX_MODE_PREPEND: - case NM_DEDUP_MULTI_IDX_MODE_APPEND: - break; - }; - - nm_assert (obj->klass == ((const NMDedupMultiObj *) entry->obj)->klass); - if ( obj == entry->obj - || obj->klass->obj_full_equal (obj, - entry->obj)) { - NM_SET_OUT (out_entry, entry); - NM_SET_OUT (out_obj_old, nm_dedup_multi_obj_ref (entry->obj)); - return changed; - } - - obj_new = nm_dedup_multi_index_obj_intern (self, obj); - - obj_old = entry->obj; - entry->obj = obj_new; - - NM_SET_OUT (out_entry, entry); - if (out_obj_old) - *out_obj_old = obj_old; - else - nm_dedup_multi_obj_unref (obj_old); - return TRUE; - } - - if ( idx_type->klass->idx_obj_partitionable - && !idx_type->klass->idx_obj_partitionable (idx_type, obj)) { - /* this object cannot be partitioned by this idx_type. */ - nm_assert (!head_existing || head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING); - NM_SET_OUT (out_entry, NULL); - NM_SET_OUT (out_obj_old, NULL); - return FALSE; - } - - obj_new = nm_dedup_multi_index_obj_intern (self, obj); - - if (!head_existing) - head_entry = _entry_lookup_head (self, idx_type, obj_new); - else if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING) - head_entry = NULL; - else - head_entry = head_existing; - - if (!head_entry) { - head_entry = g_slice_new0 (NMDedupMultiHeadEntry); - head_entry->is_head = TRUE; - head_entry->idx_type = idx_type; - c_list_init (&head_entry->lst_entries_head); - c_list_link_tail (&idx_type->lst_idx_head, &head_entry->lst_idx); - add_head_entry = TRUE; - } else - nm_assert (c_list_contains (&idx_type->lst_idx_head, &head_entry->lst_idx)); - - if (entry_order) { - nm_assert (!add_head_entry); - nm_assert (entry_order->head == head_entry); - nm_assert (c_list_contains (&head_entry->lst_entries_head, &entry_order->lst_entries)); - nm_assert (c_list_contains (&entry_order->lst_entries, &head_entry->lst_entries_head)); - } - - entry = g_slice_new0 (NMDedupMultiEntry); - entry->obj = obj_new; - entry->head = head_entry; - - switch (mode) { - case NM_DEDUP_MULTI_IDX_MODE_PREPEND: - case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE: - if (entry_order) - c_list_link_before ((CList *) &entry_order->lst_entries, &entry->lst_entries); - else - c_list_link_front (&head_entry->lst_entries_head, &entry->lst_entries); - break; - default: - if (entry_order) - c_list_link_after ((CList *) &entry_order->lst_entries, &entry->lst_entries); - else - c_list_link_tail (&head_entry->lst_entries_head, &entry->lst_entries); - break; - }; - - idx_type->len++; - head_entry->len++; - - if ( add_head_entry - && !g_hash_table_add (self->idx_entries, head_entry)) - nm_assert_not_reached (); - - if (!g_hash_table_add (self->idx_entries, entry)) - nm_assert_not_reached (); - - NM_SET_OUT (out_entry, entry); - NM_SET_OUT (out_obj_old, NULL); - return TRUE; + NMDedupMultiHeadEntry *head_entry; + const NMDedupMultiObj *obj_new, *obj_old; + gboolean add_head_entry = FALSE; + + nm_assert(self); + ASSERT_idx_type(idx_type); + nm_assert(obj); + nm_assert(NM_IN_SET(mode, + NM_DEDUP_MULTI_IDX_MODE_PREPEND, + NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE)); + nm_assert(!head_existing || head_existing->idx_type == idx_type); + nm_assert(({ + const NMDedupMultiHeadEntry *_h; + gboolean _ok = TRUE; + if (head_existing) { + _h = nm_dedup_multi_index_lookup_head(self, idx_type, obj); + if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING) + _ok = (_h == NULL); + else + _ok = (_h == head_existing); + } + _ok; + })); + + if (entry) { + gboolean changed = FALSE; + + nm_dedup_multi_entry_set_dirty(entry, FALSE); + + nm_assert(!head_existing || entry->head == head_existing); + nm_assert(!entry_order || entry_order->head == entry->head); + nm_assert(!entry_order || c_list_contains(&entry->lst_entries, &entry_order->lst_entries)); + nm_assert(!entry_order || c_list_contains(&entry_order->lst_entries, &entry->lst_entries)); + + switch (mode) { + case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE: + if (entry_order) { + if (nm_c_list_move_before((CList *) &entry_order->lst_entries, &entry->lst_entries)) + changed = TRUE; + } else { + if (nm_c_list_move_front((CList *) &entry->head->lst_entries_head, + &entry->lst_entries)) + changed = TRUE; + } + break; + case NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE: + if (entry_order) { + if (nm_c_list_move_after((CList *) &entry_order->lst_entries, &entry->lst_entries)) + changed = TRUE; + } else { + if (nm_c_list_move_tail((CList *) &entry->head->lst_entries_head, + &entry->lst_entries)) + changed = TRUE; + } + break; + case NM_DEDUP_MULTI_IDX_MODE_PREPEND: + case NM_DEDUP_MULTI_IDX_MODE_APPEND: + break; + }; + + nm_assert(obj->klass == ((const NMDedupMultiObj *) entry->obj)->klass); + if (obj == entry->obj || obj->klass->obj_full_equal(obj, entry->obj)) { + NM_SET_OUT(out_entry, entry); + NM_SET_OUT(out_obj_old, nm_dedup_multi_obj_ref(entry->obj)); + return changed; + } + + obj_new = nm_dedup_multi_index_obj_intern(self, obj); + + obj_old = entry->obj; + entry->obj = obj_new; + + NM_SET_OUT(out_entry, entry); + if (out_obj_old) + *out_obj_old = obj_old; + else + nm_dedup_multi_obj_unref(obj_old); + return TRUE; + } + + if (idx_type->klass->idx_obj_partitionable + && !idx_type->klass->idx_obj_partitionable(idx_type, obj)) { + /* this object cannot be partitioned by this idx_type. */ + nm_assert(!head_existing || head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING); + NM_SET_OUT(out_entry, NULL); + NM_SET_OUT(out_obj_old, NULL); + return FALSE; + } + + obj_new = nm_dedup_multi_index_obj_intern(self, obj); + + if (!head_existing) + head_entry = _entry_lookup_head(self, idx_type, obj_new); + else if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING) + head_entry = NULL; + else + head_entry = head_existing; + + if (!head_entry) { + head_entry = g_slice_new0(NMDedupMultiHeadEntry); + head_entry->is_head = TRUE; + head_entry->idx_type = idx_type; + c_list_init(&head_entry->lst_entries_head); + c_list_link_tail(&idx_type->lst_idx_head, &head_entry->lst_idx); + add_head_entry = TRUE; + } else + nm_assert(c_list_contains(&idx_type->lst_idx_head, &head_entry->lst_idx)); + + if (entry_order) { + nm_assert(!add_head_entry); + nm_assert(entry_order->head == head_entry); + nm_assert(c_list_contains(&head_entry->lst_entries_head, &entry_order->lst_entries)); + nm_assert(c_list_contains(&entry_order->lst_entries, &head_entry->lst_entries_head)); + } + + entry = g_slice_new0(NMDedupMultiEntry); + entry->obj = obj_new; + entry->head = head_entry; + + switch (mode) { + case NM_DEDUP_MULTI_IDX_MODE_PREPEND: + case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE: + if (entry_order) + c_list_link_before((CList *) &entry_order->lst_entries, &entry->lst_entries); + else + c_list_link_front(&head_entry->lst_entries_head, &entry->lst_entries); + break; + default: + if (entry_order) + c_list_link_after((CList *) &entry_order->lst_entries, &entry->lst_entries); + else + c_list_link_tail(&head_entry->lst_entries_head, &entry->lst_entries); + break; + }; + + idx_type->len++; + head_entry->len++; + + if (add_head_entry && !g_hash_table_add(self->idx_entries, head_entry)) + nm_assert_not_reached(); + + if (!g_hash_table_add(self->idx_entries, entry)) + nm_assert_not_reached(); + + NM_SET_OUT(out_entry, entry); + NM_SET_OUT(out_obj_old, NULL); + return TRUE; } gboolean -nm_dedup_multi_index_add (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj, - NMDedupMultiIdxMode mode, - const NMDedupMultiEntry **out_entry, - /* const NMDedupMultiObj ** */ gpointer out_obj_old) +nm_dedup_multi_index_add(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + NMDedupMultiIdxMode mode, + const NMDedupMultiEntry ** out_entry, + /* const NMDedupMultiObj ** */ gpointer out_obj_old) { - NMDedupMultiEntry *entry; - - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (idx_type, FALSE); - g_return_val_if_fail (obj, FALSE); - g_return_val_if_fail (NM_IN_SET (mode, - NM_DEDUP_MULTI_IDX_MODE_PREPEND, - NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, - NM_DEDUP_MULTI_IDX_MODE_APPEND, - NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE), - FALSE); - - entry = _entry_lookup_obj (self, idx_type, obj); - return _add (self, idx_type, obj, - entry, mode, - NULL, NULL, - out_entry, out_obj_old); + NMDedupMultiEntry *entry; + + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(idx_type, FALSE); + g_return_val_if_fail(obj, FALSE); + g_return_val_if_fail(NM_IN_SET(mode, + NM_DEDUP_MULTI_IDX_MODE_PREPEND, + NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE), + FALSE); + + entry = _entry_lookup_obj(self, idx_type, obj); + return _add(self, idx_type, obj, entry, mode, NULL, NULL, out_entry, out_obj_old); } /* nm_dedup_multi_index_add_full: @@ -427,216 +423,211 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self, * Return: %TRUE if anything changed, %FALSE if nothing changed. */ gboolean -nm_dedup_multi_index_add_full (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj, - NMDedupMultiIdxMode mode, - const NMDedupMultiEntry *entry_order, - const NMDedupMultiEntry *entry_existing, - const NMDedupMultiHeadEntry *head_existing, - const NMDedupMultiEntry **out_entry, - /* const NMDedupMultiObj ** */ gpointer out_obj_old) +nm_dedup_multi_index_add_full(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + NMDedupMultiIdxMode mode, + const NMDedupMultiEntry * entry_order, + const NMDedupMultiEntry * entry_existing, + const NMDedupMultiHeadEntry * head_existing, + const NMDedupMultiEntry ** out_entry, + /* const NMDedupMultiObj ** */ gpointer out_obj_old) { - NMDedupMultiEntry *entry; - - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (idx_type, FALSE); - g_return_val_if_fail (obj, FALSE); - g_return_val_if_fail (NM_IN_SET (mode, - NM_DEDUP_MULTI_IDX_MODE_PREPEND, - NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, - NM_DEDUP_MULTI_IDX_MODE_APPEND, - NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE), - FALSE); - - if (entry_existing == NULL) - entry = _entry_lookup_obj (self, idx_type, obj); - else if (entry_existing == NM_DEDUP_MULTI_ENTRY_MISSING) { - nm_assert (!_entry_lookup_obj (self, idx_type, obj)); - entry = NULL; - } else { - nm_assert (entry_existing == _entry_lookup_obj (self, idx_type, obj)); - entry = (NMDedupMultiEntry *) entry_existing; - } - return _add (self, idx_type, obj, - entry, - mode, entry_order, - (NMDedupMultiHeadEntry *) head_existing, - out_entry, out_obj_old); + NMDedupMultiEntry *entry; + + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(idx_type, FALSE); + g_return_val_if_fail(obj, FALSE); + g_return_val_if_fail(NM_IN_SET(mode, + NM_DEDUP_MULTI_IDX_MODE_PREPEND, + NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE), + FALSE); + + if (entry_existing == NULL) + entry = _entry_lookup_obj(self, idx_type, obj); + else if (entry_existing == NM_DEDUP_MULTI_ENTRY_MISSING) { + nm_assert(!_entry_lookup_obj(self, idx_type, obj)); + entry = NULL; + } else { + nm_assert(entry_existing == _entry_lookup_obj(self, idx_type, obj)); + entry = (NMDedupMultiEntry *) entry_existing; + } + return _add(self, + idx_type, + obj, + entry, + mode, + entry_order, + (NMDedupMultiHeadEntry *) head_existing, + out_entry, + out_obj_old); } /*****************************************************************************/ static void -_remove_entry (NMDedupMultiIndex *self, - NMDedupMultiEntry *entry, - gboolean *out_head_entry_removed) +_remove_entry(NMDedupMultiIndex *self, NMDedupMultiEntry *entry, gboolean *out_head_entry_removed) { - const NMDedupMultiObj *obj; - NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIdxType *idx_type; + const NMDedupMultiObj *obj; + NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIdxType * idx_type; - nm_assert (self); - nm_assert (entry); - nm_assert (entry->obj); - nm_assert (entry->head); - nm_assert (!c_list_is_empty (&entry->lst_entries)); - nm_assert (g_hash_table_lookup (self->idx_entries, entry) == entry); + nm_assert(self); + nm_assert(entry); + nm_assert(entry->obj); + nm_assert(entry->head); + nm_assert(!c_list_is_empty(&entry->lst_entries)); + nm_assert(g_hash_table_lookup(self->idx_entries, entry) == entry); - head_entry = (NMDedupMultiHeadEntry *) entry->head; - obj = entry->obj; + head_entry = (NMDedupMultiHeadEntry *) entry->head; + obj = entry->obj; - nm_assert (head_entry); - nm_assert (head_entry->len > 0); - nm_assert (g_hash_table_lookup (self->idx_entries, head_entry) == head_entry); + nm_assert(head_entry); + nm_assert(head_entry->len > 0); + nm_assert(g_hash_table_lookup(self->idx_entries, head_entry) == head_entry); - idx_type = (NMDedupMultiIdxType *) head_entry->idx_type; - ASSERT_idx_type (idx_type); + idx_type = (NMDedupMultiIdxType *) head_entry->idx_type; + ASSERT_idx_type(idx_type); - nm_assert (idx_type->len >= head_entry->len); - if (--head_entry->len > 0) { - nm_assert (idx_type->len > 1); - idx_type->len--; - head_entry = NULL; - } + nm_assert(idx_type->len >= head_entry->len); + if (--head_entry->len > 0) { + nm_assert(idx_type->len > 1); + idx_type->len--; + head_entry = NULL; + } - NM_SET_OUT (out_head_entry_removed, head_entry != NULL); + NM_SET_OUT(out_head_entry_removed, head_entry != NULL); - if (!g_hash_table_remove (self->idx_entries, entry)) - nm_assert_not_reached (); + if (!g_hash_table_remove(self->idx_entries, entry)) + nm_assert_not_reached(); - if ( head_entry - && !g_hash_table_remove (self->idx_entries, head_entry)) - nm_assert_not_reached (); + if (head_entry && !g_hash_table_remove(self->idx_entries, head_entry)) + nm_assert_not_reached(); - c_list_unlink_stale (&entry->lst_entries); - g_slice_free (NMDedupMultiEntry, entry); + c_list_unlink_stale(&entry->lst_entries); + g_slice_free(NMDedupMultiEntry, entry); - if (head_entry) { - nm_assert (c_list_is_empty (&head_entry->lst_entries_head)); - c_list_unlink_stale (&head_entry->lst_idx); - g_slice_free (NMDedupMultiHeadEntry, head_entry); - } + if (head_entry) { + nm_assert(c_list_is_empty(&head_entry->lst_entries_head)); + c_list_unlink_stale(&head_entry->lst_idx); + g_slice_free(NMDedupMultiHeadEntry, head_entry); + } - nm_dedup_multi_obj_unref (obj); + nm_dedup_multi_obj_unref(obj); } static guint -_remove_head (NMDedupMultiIndex *self, - NMDedupMultiHeadEntry *head_entry, - gboolean remove_all /* otherwise just dirty ones */, - gboolean mark_survivors_dirty) +_remove_head(NMDedupMultiIndex * self, + NMDedupMultiHeadEntry *head_entry, + gboolean remove_all /* otherwise just dirty ones */, + gboolean mark_survivors_dirty) { - guint n; - gboolean head_entry_removed; - CList *iter_entry, *iter_entry_safe; - - nm_assert (self); - nm_assert (head_entry); - nm_assert (head_entry->len > 0); - nm_assert (head_entry->len == c_list_length (&head_entry->lst_entries_head)); - nm_assert (g_hash_table_lookup (self->idx_entries, head_entry) == head_entry); - - n = 0; - c_list_for_each_safe (iter_entry, iter_entry_safe, &head_entry->lst_entries_head) { - NMDedupMultiEntry *entry; - - entry = c_list_entry (iter_entry, NMDedupMultiEntry, lst_entries); - if ( remove_all - || entry->dirty) { - _remove_entry (self, - entry, - &head_entry_removed); - n++; - if (head_entry_removed) - break; - } else if (mark_survivors_dirty) - nm_dedup_multi_entry_set_dirty (entry, TRUE); - } - - return n; + guint n; + gboolean head_entry_removed; + CList * iter_entry, *iter_entry_safe; + + nm_assert(self); + nm_assert(head_entry); + nm_assert(head_entry->len > 0); + nm_assert(head_entry->len == c_list_length(&head_entry->lst_entries_head)); + nm_assert(g_hash_table_lookup(self->idx_entries, head_entry) == head_entry); + + n = 0; + c_list_for_each_safe (iter_entry, iter_entry_safe, &head_entry->lst_entries_head) { + NMDedupMultiEntry *entry; + + entry = c_list_entry(iter_entry, NMDedupMultiEntry, lst_entries); + if (remove_all || entry->dirty) { + _remove_entry(self, entry, &head_entry_removed); + n++; + if (head_entry_removed) + break; + } else if (mark_survivors_dirty) + nm_dedup_multi_entry_set_dirty(entry, TRUE); + } + + return n; } static guint -_remove_idx_entry (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - gboolean remove_all /* otherwise just dirty ones */, - gboolean mark_survivors_dirty) +_remove_idx_entry(NMDedupMultiIndex * self, + NMDedupMultiIdxType *idx_type, + gboolean remove_all /* otherwise just dirty ones */, + gboolean mark_survivors_dirty) { - guint n; - CList *iter_idx, *iter_idx_safe; - - nm_assert (self); - ASSERT_idx_type (idx_type); - - n = 0; - c_list_for_each_safe (iter_idx, iter_idx_safe, &idx_type->lst_idx_head) { - n += _remove_head (self, - c_list_entry (iter_idx, NMDedupMultiHeadEntry, lst_idx), - remove_all, mark_survivors_dirty); - } - return n; + guint n; + CList *iter_idx, *iter_idx_safe; + + nm_assert(self); + ASSERT_idx_type(idx_type); + + n = 0; + c_list_for_each_safe (iter_idx, iter_idx_safe, &idx_type->lst_idx_head) { + n += _remove_head(self, + c_list_entry(iter_idx, NMDedupMultiHeadEntry, lst_idx), + remove_all, + mark_survivors_dirty); + } + return n; } guint -nm_dedup_multi_index_remove_entry (NMDedupMultiIndex *self, - gconstpointer entry) +nm_dedup_multi_index_remove_entry(NMDedupMultiIndex *self, gconstpointer entry) { - g_return_val_if_fail (self, 0); + g_return_val_if_fail(self, 0); - nm_assert (entry); + nm_assert(entry); - if (!((NMDedupMultiEntry *) entry)->is_head) { - _remove_entry (self, (NMDedupMultiEntry *) entry, NULL); - return 1; - } - return _remove_head (self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE); + if (!((NMDedupMultiEntry *) entry)->is_head) { + _remove_entry(self, (NMDedupMultiEntry *) entry, NULL); + return 1; + } + return _remove_head(self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE); } guint -nm_dedup_multi_index_remove_obj (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj, - /*const NMDedupMultiObj ** */ gconstpointer *out_obj) +nm_dedup_multi_index_remove_obj(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + /*const NMDedupMultiObj ** */ gconstpointer *out_obj) { - const NMDedupMultiEntry *entry; + const NMDedupMultiEntry *entry; - entry = nm_dedup_multi_index_lookup_obj (self, idx_type, obj); - if (!entry) { - NM_SET_OUT (out_obj, NULL); - return 0; - } + entry = nm_dedup_multi_index_lookup_obj(self, idx_type, obj); + if (!entry) { + NM_SET_OUT(out_obj, NULL); + return 0; + } - /* since we are about to remove the object, we obviously pass - * a reference to @out_obj, the caller MUST unref the object, - * if he chooses to provide @out_obj. */ - NM_SET_OUT (out_obj, nm_dedup_multi_obj_ref (entry->obj)); + /* since we are about to remove the object, we obviously pass + * a reference to @out_obj, the caller MUST unref the object, + * if he chooses to provide @out_obj. */ + NM_SET_OUT(out_obj, nm_dedup_multi_obj_ref(entry->obj)); - _remove_entry (self, (NMDedupMultiEntry *) entry, NULL); - return 1; + _remove_entry(self, (NMDedupMultiEntry *) entry, NULL); + return 1; } guint -nm_dedup_multi_index_remove_head (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_remove_head(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj) { - const NMDedupMultiHeadEntry *entry; + const NMDedupMultiHeadEntry *entry; - entry = nm_dedup_multi_index_lookup_head (self, idx_type, obj); - return entry - ? _remove_head (self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE) - : 0; + entry = nm_dedup_multi_index_lookup_head(self, idx_type, obj); + return entry ? _remove_head(self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE) : 0; } guint -nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type) +nm_dedup_multi_index_remove_idx(NMDedupMultiIndex *self, NMDedupMultiIdxType *idx_type) { - g_return_val_if_fail (self, 0); - g_return_val_if_fail (idx_type, 0); + g_return_val_if_fail(self, 0); + g_return_val_if_fail(idx_type, 0); - return _remove_idx_entry (self, idx_type, TRUE, FALSE); + return _remove_idx_entry(self, idx_type, TRUE, FALSE); } /*****************************************************************************/ @@ -652,16 +643,16 @@ nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self, * Returns: the cache entry or %NULL if the entry wasn't found. */ const NMDedupMultiEntry * -nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_lookup_obj(const NMDedupMultiIndex * self, + const NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj) { - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (idx_type, FALSE); - g_return_val_if_fail (obj, FALSE); + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(idx_type, FALSE); + g_return_val_if_fail(obj, FALSE); - nm_assert (idx_type && idx_type->klass); - return _entry_lookup_obj (self, idx_type, obj); + nm_assert(idx_type && idx_type->klass); + return _entry_lookup_obj(self, idx_type, obj); } /** @@ -678,61 +669,60 @@ nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self, * Returns: the cache entry or %NULL if the entry wasn't found. */ const NMDedupMultiHeadEntry * -nm_dedup_multi_index_lookup_head (const NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_lookup_head(const NMDedupMultiIndex * self, + const NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj) { - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (idx_type, FALSE); + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(idx_type, FALSE); - return _entry_lookup_head (self, idx_type, obj); + return _entry_lookup_head(self, idx_type, obj); } /*****************************************************************************/ void -nm_dedup_multi_index_dirty_set_head (NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_dirty_set_head(NMDedupMultiIndex * self, + const NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj) { - NMDedupMultiHeadEntry *head_entry; - CList *iter_entry; + NMDedupMultiHeadEntry *head_entry; + CList * iter_entry; - g_return_if_fail (self); - g_return_if_fail (idx_type); + g_return_if_fail(self); + g_return_if_fail(idx_type); - head_entry = _entry_lookup_head (self, idx_type, obj); - if (!head_entry) - return; + head_entry = _entry_lookup_head(self, idx_type, obj); + if (!head_entry) + return; - c_list_for_each (iter_entry, &head_entry->lst_entries_head) { - NMDedupMultiEntry *entry; + c_list_for_each (iter_entry, &head_entry->lst_entries_head) { + NMDedupMultiEntry *entry; - entry = c_list_entry (iter_entry, NMDedupMultiEntry, lst_entries); - nm_dedup_multi_entry_set_dirty (entry, TRUE); - } + entry = c_list_entry(iter_entry, NMDedupMultiEntry, lst_entries); + nm_dedup_multi_entry_set_dirty(entry, TRUE); + } } void -nm_dedup_multi_index_dirty_set_idx (NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type) +nm_dedup_multi_index_dirty_set_idx(NMDedupMultiIndex *self, const NMDedupMultiIdxType *idx_type) { - CList *iter_idx, *iter_entry; + CList *iter_idx, *iter_entry; - g_return_if_fail (self); - g_return_if_fail (idx_type); + g_return_if_fail(self); + g_return_if_fail(idx_type); - c_list_for_each (iter_idx, &idx_type->lst_idx_head) { - NMDedupMultiHeadEntry *head_entry; + c_list_for_each (iter_idx, &idx_type->lst_idx_head) { + NMDedupMultiHeadEntry *head_entry; - head_entry = c_list_entry (iter_idx, NMDedupMultiHeadEntry, lst_idx); - c_list_for_each (iter_entry, &head_entry->lst_entries_head) { - NMDedupMultiEntry *entry; + head_entry = c_list_entry(iter_idx, NMDedupMultiHeadEntry, lst_idx); + c_list_for_each (iter_entry, &head_entry->lst_entries_head) { + NMDedupMultiEntry *entry; - entry = c_list_entry (iter_entry, NMDedupMultiEntry, lst_entries); - nm_dedup_multi_entry_set_dirty (entry, TRUE); - } - } + entry = c_list_entry(iter_entry, NMDedupMultiEntry, lst_entries); + nm_dedup_multi_entry_set_dirty(entry, TRUE); + } + } } /** @@ -750,219 +740,212 @@ nm_dedup_multi_index_dirty_set_idx (NMDedupMultiIndex *self, * Returns: number of deleted entries. */ guint -nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - gboolean mark_survivors_dirty) +nm_dedup_multi_index_dirty_remove_idx(NMDedupMultiIndex * self, + NMDedupMultiIdxType *idx_type, + gboolean mark_survivors_dirty) { - g_return_val_if_fail (self, 0); - g_return_val_if_fail (idx_type, 0); + g_return_val_if_fail(self, 0); + g_return_val_if_fail(idx_type, 0); - return _remove_idx_entry (self, idx_type, FALSE, mark_survivors_dirty); + return _remove_idx_entry(self, idx_type, FALSE, mark_survivors_dirty); } /*****************************************************************************/ static guint -_dict_idx_objs_hash (const NMDedupMultiObj *obj) +_dict_idx_objs_hash(const NMDedupMultiObj *obj) { - NMHashState h; + NMHashState h; - nm_hash_init (&h, 1748638583u); - obj->klass->obj_full_hash_update (obj, &h); - return nm_hash_complete (&h); + nm_hash_init(&h, 1748638583u); + obj->klass->obj_full_hash_update(obj, &h); + return nm_hash_complete(&h); } static gboolean -_dict_idx_objs_equal (const NMDedupMultiObj *obj_a, - const NMDedupMultiObj *obj_b) +_dict_idx_objs_equal(const NMDedupMultiObj *obj_a, const NMDedupMultiObj *obj_b) { - return obj_a == obj_b - || ( obj_a->klass == obj_b->klass - && obj_a->klass->obj_full_equal (obj_a, obj_b)); + return obj_a == obj_b + || (obj_a->klass == obj_b->klass && obj_a->klass->obj_full_equal(obj_a, obj_b)); } void -nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self, - /* const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_obj_release(NMDedupMultiIndex * self, + /* const NMDedupMultiObj * */ gconstpointer obj) { - nm_assert (self); - nm_assert (obj); - nm_assert (g_hash_table_lookup (self->idx_objs, obj) == obj); - nm_assert (((const NMDedupMultiObj *) obj)->_multi_idx == self); - - ((NMDedupMultiObj *) obj)->_multi_idx = NULL; - if (!g_hash_table_remove (self->idx_objs, obj)) - nm_assert_not_reached (); + nm_assert(self); + nm_assert(obj); + nm_assert(g_hash_table_lookup(self->idx_objs, obj) == obj); + nm_assert(((const NMDedupMultiObj *) obj)->_multi_idx == self); + + ((NMDedupMultiObj *) obj)->_multi_idx = NULL; + if (!g_hash_table_remove(self->idx_objs, obj)) + nm_assert_not_reached(); } gconstpointer -nm_dedup_multi_index_obj_find (NMDedupMultiIndex *self, - /* const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_obj_find(NMDedupMultiIndex * self, + /* const NMDedupMultiObj * */ gconstpointer obj) { - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (obj, NULL); + g_return_val_if_fail(self, NULL); + g_return_val_if_fail(obj, NULL); - return g_hash_table_lookup (self->idx_objs, obj); + return g_hash_table_lookup(self->idx_objs, obj); } gconstpointer -nm_dedup_multi_index_obj_intern (NMDedupMultiIndex *self, - /* const NMDedupMultiObj * */ gconstpointer obj) +nm_dedup_multi_index_obj_intern(NMDedupMultiIndex * self, + /* const NMDedupMultiObj * */ gconstpointer obj) { - const NMDedupMultiObj *obj_new = obj; - const NMDedupMultiObj *obj_old; + const NMDedupMultiObj *obj_new = obj; + const NMDedupMultiObj *obj_old; - nm_assert (self); - nm_assert (obj_new); + nm_assert(self); + nm_assert(obj_new); - if (obj_new->_multi_idx == self) { - nm_assert (g_hash_table_lookup (self->idx_objs, obj_new) == obj_new); - nm_dedup_multi_obj_ref (obj_new); - return obj_new; - } + if (obj_new->_multi_idx == self) { + nm_assert(g_hash_table_lookup(self->idx_objs, obj_new) == obj_new); + nm_dedup_multi_obj_ref(obj_new); + return obj_new; + } - obj_old = g_hash_table_lookup (self->idx_objs, obj_new); - nm_assert (obj_old != obj_new); + obj_old = g_hash_table_lookup(self->idx_objs, obj_new); + nm_assert(obj_old != obj_new); - if (obj_old) { - nm_assert (obj_old->_multi_idx == self); - nm_dedup_multi_obj_ref (obj_old); - return obj_old; - } + if (obj_old) { + nm_assert(obj_old->_multi_idx == self); + nm_dedup_multi_obj_ref(obj_old); + return obj_old; + } - if (nm_dedup_multi_obj_needs_clone (obj_new)) - obj_new = nm_dedup_multi_obj_clone (obj_new); - else - obj_new = nm_dedup_multi_obj_ref (obj_new); + if (nm_dedup_multi_obj_needs_clone(obj_new)) + obj_new = nm_dedup_multi_obj_clone(obj_new); + else + obj_new = nm_dedup_multi_obj_ref(obj_new); - nm_assert (obj_new); - nm_assert (!obj_new->_multi_idx); + nm_assert(obj_new); + nm_assert(!obj_new->_multi_idx); - if (!g_hash_table_add (self->idx_objs, (gpointer) obj_new)) - nm_assert_not_reached (); + if (!g_hash_table_add(self->idx_objs, (gpointer) obj_new)) + nm_assert_not_reached(); - ((NMDedupMultiObj *) obj_new)->_multi_idx = self; - return obj_new; + ((NMDedupMultiObj *) obj_new)->_multi_idx = self; + return obj_new; } void -nm_dedup_multi_obj_unref (const NMDedupMultiObj *obj) +nm_dedup_multi_obj_unref(const NMDedupMultiObj *obj) { - if (obj) { - nm_assert (obj->_ref_count > 0); - nm_assert (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); + if (obj) { + nm_assert(obj->_ref_count > 0); + nm_assert(obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); again: - if (--(((NMDedupMultiObj *) obj)->_ref_count) <= 0) { - if (obj->_multi_idx) { - /* restore the ref-count to 1 and release the object first - * from the index. Then, retry again to unref. */ - ((NMDedupMultiObj *) obj)->_ref_count++; - nm_dedup_multi_index_obj_release (obj->_multi_idx, obj); - nm_assert (obj->_ref_count == 1); - nm_assert (!obj->_multi_idx); - goto again; - } - - obj->klass->obj_destroy ((NMDedupMultiObj *) obj); - } - } + if (--(((NMDedupMultiObj *) obj)->_ref_count) <= 0) { + if (obj->_multi_idx) { + /* restore the ref-count to 1 and release the object first + * from the index. Then, retry again to unref. */ + ((NMDedupMultiObj *) obj)->_ref_count++; + nm_dedup_multi_index_obj_release(obj->_multi_idx, obj); + nm_assert(obj->_ref_count == 1); + nm_assert(!obj->_multi_idx); + goto again; + } + + obj->klass->obj_destroy((NMDedupMultiObj *) obj); + } + } } gboolean -nm_dedup_multi_obj_needs_clone (const NMDedupMultiObj *obj) +nm_dedup_multi_obj_needs_clone(const NMDedupMultiObj *obj) { - nm_assert (obj); + nm_assert(obj); - if ( obj->_multi_idx - || obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT) - return TRUE; + if (obj->_multi_idx || obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT) + return TRUE; - if ( obj->klass->obj_needs_clone - && obj->klass->obj_needs_clone (obj)) - return TRUE; + if (obj->klass->obj_needs_clone && obj->klass->obj_needs_clone(obj)) + return TRUE; - return FALSE; + return FALSE; } const NMDedupMultiObj * -nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj) +nm_dedup_multi_obj_clone(const NMDedupMultiObj *obj) { - const NMDedupMultiObj *o; + const NMDedupMultiObj *o; - nm_assert (obj); + nm_assert(obj); - o = obj->klass->obj_clone (obj); - nm_assert (o); - nm_assert (o->_ref_count == 1); - return o; + o = obj->klass->obj_clone(obj); + nm_assert(o); + nm_assert(o->_ref_count == 1); + return o; } gconstpointer * -nm_dedup_multi_objs_to_array_head (const NMDedupMultiHeadEntry *head_entry, - NMDedupMultiFcnSelectPredicate predicate, - gpointer user_data, - guint *out_len) +nm_dedup_multi_objs_to_array_head(const NMDedupMultiHeadEntry * head_entry, + NMDedupMultiFcnSelectPredicate predicate, + gpointer user_data, + guint * out_len) { - gconstpointer *result; - CList *iter; - guint i; - - if (!head_entry) { - NM_SET_OUT (out_len, 0); - return NULL; - } - - result = g_new (gconstpointer, head_entry->len + 1); - i = 0; - c_list_for_each (iter, &head_entry->lst_entries_head) { - const NMDedupMultiObj *obj = c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj; - - if ( !predicate - || predicate (obj, user_data)) { - nm_assert (i < head_entry->len); - result[i++] = obj; - } - } - - if (i == 0) { - g_free (result); - NM_SET_OUT (out_len, 0); - return NULL; - } - - nm_assert (i <= head_entry->len); - NM_SET_OUT (out_len, i); - result[i++] = NULL; - return result; + gconstpointer *result; + CList * iter; + guint i; + + if (!head_entry) { + NM_SET_OUT(out_len, 0); + return NULL; + } + + result = g_new(gconstpointer, head_entry->len + 1); + i = 0; + c_list_for_each (iter, &head_entry->lst_entries_head) { + const NMDedupMultiObj *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + + if (!predicate || predicate(obj, user_data)) { + nm_assert(i < head_entry->len); + result[i++] = obj; + } + } + + if (i == 0) { + g_free(result); + NM_SET_OUT(out_len, 0); + return NULL; + } + + nm_assert(i <= head_entry->len); + NM_SET_OUT(out_len, i); + result[i++] = NULL; + return result; } GPtrArray * -nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry, - NMDedupMultiFcnSelectPredicate predicate, - gpointer user_data) +nm_dedup_multi_objs_to_ptr_array_head(const NMDedupMultiHeadEntry * head_entry, + NMDedupMultiFcnSelectPredicate predicate, + gpointer user_data) { - GPtrArray *result; - CList *iter; - - if (!head_entry) - return NULL; - - result = g_ptr_array_new_full (head_entry->len, - (GDestroyNotify) nm_dedup_multi_obj_unref); - c_list_for_each (iter, &head_entry->lst_entries_head) { - const NMDedupMultiObj *obj = c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj; - - if ( !predicate - || predicate (obj, user_data)) - g_ptr_array_add (result, (gpointer) nm_dedup_multi_obj_ref (obj)); - } - - if (result->len == 0) { - g_ptr_array_unref (result); - return NULL; - } - return result; + GPtrArray *result; + CList * iter; + + if (!head_entry) + return NULL; + + result = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); + c_list_for_each (iter, &head_entry->lst_entries_head) { + const NMDedupMultiObj *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + + if (!predicate || predicate(obj, user_data)) + g_ptr_array_add(result, (gpointer) nm_dedup_multi_obj_ref(obj)); + } + + if (result->len == 0) { + g_ptr_array_unref(result); + return NULL; + } + return result; } /** @@ -981,96 +964,102 @@ nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry, * right place and nothing was done. */ gboolean -nm_dedup_multi_entry_reorder (const NMDedupMultiEntry *entry, - const NMDedupMultiEntry *entry_order, - gboolean order_after) +nm_dedup_multi_entry_reorder(const NMDedupMultiEntry *entry, + const NMDedupMultiEntry *entry_order, + gboolean order_after) { - nm_assert (entry); - - if (!entry_order) { - const NMDedupMultiHeadEntry *head_entry = entry->head; - - if (order_after) { - if (nm_c_list_move_tail ((CList *) &head_entry->lst_entries_head, (CList *) &entry->lst_entries)) - return TRUE; - } else { - if (nm_c_list_move_front ((CList *) &head_entry->lst_entries_head, (CList *) &entry->lst_entries)) - return TRUE; - } - } else { - if (order_after) { - if (nm_c_list_move_after ((CList *) &entry_order->lst_entries, (CList *) &entry->lst_entries)) - return TRUE; - } else { - if (nm_c_list_move_before ((CList *) &entry_order->lst_entries, (CList *) &entry->lst_entries)) - return TRUE; - } - } - - return FALSE; + nm_assert(entry); + + if (!entry_order) { + const NMDedupMultiHeadEntry *head_entry = entry->head; + + if (order_after) { + if (nm_c_list_move_tail((CList *) &head_entry->lst_entries_head, + (CList *) &entry->lst_entries)) + return TRUE; + } else { + if (nm_c_list_move_front((CList *) &head_entry->lst_entries_head, + (CList *) &entry->lst_entries)) + return TRUE; + } + } else { + if (order_after) { + if (nm_c_list_move_after((CList *) &entry_order->lst_entries, + (CList *) &entry->lst_entries)) + return TRUE; + } else { + if (nm_c_list_move_before((CList *) &entry_order->lst_entries, + (CList *) &entry->lst_entries)) + return TRUE; + } + } + + return FALSE; } /*****************************************************************************/ NMDedupMultiIndex * -nm_dedup_multi_index_new (void) +nm_dedup_multi_index_new(void) { - NMDedupMultiIndex *self; - - self = g_slice_new0 (NMDedupMultiIndex); - self->ref_count = 1; - self->idx_entries = g_hash_table_new ((GHashFunc) _dict_idx_entries_hash, (GEqualFunc) _dict_idx_entries_equal); - self->idx_objs = g_hash_table_new ((GHashFunc) _dict_idx_objs_hash, (GEqualFunc) _dict_idx_objs_equal); - return self; + NMDedupMultiIndex *self; + + self = g_slice_new0(NMDedupMultiIndex); + self->ref_count = 1; + self->idx_entries = + g_hash_table_new((GHashFunc) _dict_idx_entries_hash, (GEqualFunc) _dict_idx_entries_equal); + self->idx_objs = + g_hash_table_new((GHashFunc) _dict_idx_objs_hash, (GEqualFunc) _dict_idx_objs_equal); + return self; } NMDedupMultiIndex * -nm_dedup_multi_index_ref (NMDedupMultiIndex *self) +nm_dedup_multi_index_ref(NMDedupMultiIndex *self) { - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (self->ref_count > 0, NULL); + g_return_val_if_fail(self, NULL); + g_return_val_if_fail(self->ref_count > 0, NULL); - self->ref_count++; - return self; + self->ref_count++; + return self; } NMDedupMultiIndex * -nm_dedup_multi_index_unref (NMDedupMultiIndex *self) +nm_dedup_multi_index_unref(NMDedupMultiIndex *self) { - GHashTableIter iter; - const NMDedupMultiIdxType *idx_type; - NMDedupMultiEntry *entry; - const NMDedupMultiObj *obj; + GHashTableIter iter; + const NMDedupMultiIdxType *idx_type; + NMDedupMultiEntry * entry; + const NMDedupMultiObj * obj; - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (self->ref_count > 0, NULL); + g_return_val_if_fail(self, NULL); + g_return_val_if_fail(self->ref_count > 0, NULL); - if (--self->ref_count > 0) - return NULL; + if (--self->ref_count > 0) + return NULL; more: - g_hash_table_iter_init (&iter, self->idx_entries); - while (g_hash_table_iter_next (&iter, (gpointer *) &entry, NULL)) { - if (entry->is_head) - idx_type = ((NMDedupMultiHeadEntry *) entry)->idx_type; - else - idx_type = entry->head->idx_type; - _remove_idx_entry (self, (NMDedupMultiIdxType *) idx_type, TRUE, FALSE); - goto more; - } - - nm_assert (g_hash_table_size (self->idx_entries) == 0); - - g_hash_table_iter_init (&iter, self->idx_objs); - while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) { - nm_assert (obj->_multi_idx == self); - ((NMDedupMultiObj * )obj)->_multi_idx = NULL; - } - g_hash_table_remove_all (self->idx_objs); - - g_hash_table_unref (self->idx_entries); - g_hash_table_unref (self->idx_objs); - - g_slice_free (NMDedupMultiIndex, self); - return NULL; + g_hash_table_iter_init(&iter, self->idx_entries); + while (g_hash_table_iter_next(&iter, (gpointer *) &entry, NULL)) { + if (entry->is_head) + idx_type = ((NMDedupMultiHeadEntry *) entry)->idx_type; + else + idx_type = entry->head->idx_type; + _remove_idx_entry(self, (NMDedupMultiIdxType *) idx_type, TRUE, FALSE); + goto more; + } + + nm_assert(g_hash_table_size(self->idx_entries) == 0); + + g_hash_table_iter_init(&iter, self->idx_objs); + while (g_hash_table_iter_next(&iter, (gpointer *) &obj, NULL)) { + nm_assert(obj->_multi_idx == self); + ((NMDedupMultiObj *) obj)->_multi_idx = NULL; + } + g_hash_table_remove_all(self->idx_objs); + + g_hash_table_unref(self->idx_entries); + g_hash_table_unref(self->idx_objs); + + g_slice_free(NMDedupMultiIndex, self); + return NULL; } diff --git a/shared/nm-glib-aux/nm-dedup-multi.h b/shared/nm-glib-aux/nm-dedup-multi.h index 6867ae79..6941dc63 100644 --- a/shared/nm-glib-aux/nm-dedup-multi.h +++ b/shared/nm-glib-aux/nm-dedup-multi.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -13,86 +13,85 @@ struct _NMHashState; -typedef struct _NMDedupMultiObj NMDedupMultiObj; -typedef struct _NMDedupMultiObjClass NMDedupMultiObjClass; -typedef struct _NMDedupMultiIdxType NMDedupMultiIdxType; -typedef struct _NMDedupMultiIdxTypeClass NMDedupMultiIdxTypeClass; -typedef struct _NMDedupMultiEntry NMDedupMultiEntry; -typedef struct _NMDedupMultiHeadEntry NMDedupMultiHeadEntry; -typedef struct _NMDedupMultiIndex NMDedupMultiIndex; +typedef struct _NMDedupMultiObj NMDedupMultiObj; +typedef struct _NMDedupMultiObjClass NMDedupMultiObjClass; +typedef struct _NMDedupMultiIdxType NMDedupMultiIdxType; +typedef struct _NMDedupMultiIdxTypeClass NMDedupMultiIdxTypeClass; +typedef struct _NMDedupMultiEntry NMDedupMultiEntry; +typedef struct _NMDedupMultiHeadEntry NMDedupMultiHeadEntry; +typedef struct _NMDedupMultiIndex NMDedupMultiIndex; typedef enum _NMDedupMultiIdxMode { - NM_DEDUP_MULTI_IDX_MODE_PREPEND, + NM_DEDUP_MULTI_IDX_MODE_PREPEND, - NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, + NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, - /* append new objects to the end of the list. - * If the object is already in the cache, don't move it. */ - NM_DEDUP_MULTI_IDX_MODE_APPEND, + /* append new objects to the end of the list. + * If the object is already in the cache, don't move it. */ + NM_DEDUP_MULTI_IDX_MODE_APPEND, - /* like NM_DEDUP_MULTI_IDX_MODE_APPEND, but if the object - * is already in the cache, move it to the end. */ - NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, + /* like NM_DEDUP_MULTI_IDX_MODE_APPEND, but if the object + * is already in the cache, move it to the end. */ + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, } NMDedupMultiIdxMode; /*****************************************************************************/ struct _NMDedupMultiObj { - union { - NMObjBaseInst parent; - const NMDedupMultiObjClass *klass; - }; - NMDedupMultiIndex *_multi_idx; - guint _ref_count; + union { + NMObjBaseInst parent; + const NMDedupMultiObjClass *klass; + }; + NMDedupMultiIndex *_multi_idx; + guint _ref_count; }; struct _NMDedupMultiObjClass { - NMObjBaseClass parent; + NMObjBaseClass parent; - const NMDedupMultiObj *(*obj_clone) (const NMDedupMultiObj *obj); + const NMDedupMultiObj *(*obj_clone)(const NMDedupMultiObj *obj); - gboolean (*obj_needs_clone) (const NMDedupMultiObj *obj); + gboolean (*obj_needs_clone)(const NMDedupMultiObj *obj); - void (*obj_destroy) (NMDedupMultiObj *obj); + void (*obj_destroy)(NMDedupMultiObj *obj); - /* the NMDedupMultiObj can be deduplicated. For that the obj_full_hash_update() - * and obj_full_equal() compare *all* fields of the object, even minor ones. */ - void (*obj_full_hash_update) (const NMDedupMultiObj *obj, - struct _NMHashState *h); - gboolean (*obj_full_equal) (const NMDedupMultiObj *obj_a, - const NMDedupMultiObj *obj_b); + /* the NMDedupMultiObj can be deduplicated. For that the obj_full_hash_update() + * and obj_full_equal() compare *all* fields of the object, even minor ones. */ + void (*obj_full_hash_update)(const NMDedupMultiObj *obj, struct _NMHashState *h); + gboolean (*obj_full_equal)(const NMDedupMultiObj *obj_a, const NMDedupMultiObj *obj_b); }; /*****************************************************************************/ static inline const NMDedupMultiObj * -nm_dedup_multi_obj_ref (const NMDedupMultiObj *obj) +nm_dedup_multi_obj_ref(const NMDedupMultiObj *obj) { - /* ref and unref accept const pointers. Objects is supposed to be shared - * and kept immutable. Disallowing to take/return a reference to a const - * NMPObject is cumbersome, because callers are precisely expected to - * keep a ref on the otherwise immutable object. */ + /* ref and unref accept const pointers. Objects is supposed to be shared + * and kept immutable. Disallowing to take/return a reference to a const + * NMPObject is cumbersome, because callers are precisely expected to + * keep a ref on the otherwise immutable object. */ - nm_assert (obj); - nm_assert (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); - nm_assert (obj->_ref_count > 0); + nm_assert(obj); + nm_assert(obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); + nm_assert(obj->_ref_count > 0); - ((NMDedupMultiObj *) obj)->_ref_count++; - return obj; + ((NMDedupMultiObj *) obj)->_ref_count++; + return obj; } -void nm_dedup_multi_obj_unref (const NMDedupMultiObj *obj); -const NMDedupMultiObj *nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj); -gboolean nm_dedup_multi_obj_needs_clone (const NMDedupMultiObj *obj); +void nm_dedup_multi_obj_unref(const NMDedupMultiObj *obj); +const NMDedupMultiObj *nm_dedup_multi_obj_clone(const NMDedupMultiObj *obj); +gboolean nm_dedup_multi_obj_needs_clone(const NMDedupMultiObj *obj); -gconstpointer nm_dedup_multi_index_obj_intern (NMDedupMultiIndex *self, - /* const NMDedupMultiObj * */ gconstpointer obj); +gconstpointer nm_dedup_multi_index_obj_intern(NMDedupMultiIndex * self, + /* const NMDedupMultiObj * */ gconstpointer obj); -void nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self, - /* const NMDedupMultiObj * */ gconstpointer obj); +void nm_dedup_multi_index_obj_release(NMDedupMultiIndex * self, + /* const NMDedupMultiObj * */ gconstpointer obj); -/* const NMDedupMultiObj * */ gconstpointer nm_dedup_multi_index_obj_find (NMDedupMultiIndex *self, - /* const NMDedupMultiObj * */ gconstpointer obj); +/* const NMDedupMultiObj * */ gconstpointer +nm_dedup_multi_index_obj_find(NMDedupMultiIndex * self, + /* const NMDedupMultiObj * */ gconstpointer obj); /*****************************************************************************/ @@ -123,298 +122,285 @@ void nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self, * In the platform example, the NMDedupMultiHeadEntry partition the indexed objects * by their ifindex. */ struct _NMDedupMultiIdxType { - union { - NMObjBaseInst parent; - const NMDedupMultiIdxTypeClass *klass; - }; + union { + NMObjBaseInst parent; + const NMDedupMultiIdxTypeClass *klass; + }; - CList lst_idx_head; + CList lst_idx_head; - guint len; + guint len; }; -void nm_dedup_multi_idx_type_init (NMDedupMultiIdxType *idx_type, - const NMDedupMultiIdxTypeClass *klass); +void nm_dedup_multi_idx_type_init(NMDedupMultiIdxType * idx_type, + const NMDedupMultiIdxTypeClass *klass); struct _NMDedupMultiIdxTypeClass { - NMObjBaseClass parent; - - void (*idx_obj_id_hash_update) (const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj, - struct _NMHashState *h); - gboolean (*idx_obj_id_equal) (const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj_a, - const NMDedupMultiObj *obj_b); - - /* an NMDedupMultiIdxTypeClass which implements partitioning of the - * tracked objects, must implement the idx_obj_partition*() functions. - * - * idx_obj_partitionable() may return NULL if the object cannot be tracked. - * For example, a index for routes by ifindex, may not want to track any - * routes that don't have a valid ifindex. If the idx-type says that the - * object is not partitionable, it is never added to the NMDedupMultiIndex. */ - gboolean (*idx_obj_partitionable) (const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj); - void (*idx_obj_partition_hash_update) (const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj, - struct _NMHashState *h); - gboolean (*idx_obj_partition_equal) (const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj *obj_a, - const NMDedupMultiObj *obj_b); + NMObjBaseClass parent; + + void (*idx_obj_id_hash_update)(const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj, + struct _NMHashState * h); + gboolean (*idx_obj_id_equal)(const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj_a, + const NMDedupMultiObj * obj_b); + + /* an NMDedupMultiIdxTypeClass which implements partitioning of the + * tracked objects, must implement the idx_obj_partition*() functions. + * + * idx_obj_partitionable() may return NULL if the object cannot be tracked. + * For example, a index for routes by ifindex, may not want to track any + * routes that don't have a valid ifindex. If the idx-type says that the + * object is not partitionable, it is never added to the NMDedupMultiIndex. */ + gboolean (*idx_obj_partitionable)(const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj); + void (*idx_obj_partition_hash_update)(const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj, + struct _NMHashState * h); + gboolean (*idx_obj_partition_equal)(const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj * obj_a, + const NMDedupMultiObj * obj_b); }; static inline gboolean -nm_dedup_multi_idx_type_id_equal (const NMDedupMultiIdxType *idx_type, - /* const NMDedupMultiObj * */ gconstpointer obj_a, - /* const NMDedupMultiObj * */ gconstpointer obj_b) +nm_dedup_multi_idx_type_id_equal(const NMDedupMultiIdxType * idx_type, + /* const NMDedupMultiObj * */ gconstpointer obj_a, + /* const NMDedupMultiObj * */ gconstpointer obj_b) { - nm_assert (idx_type); - return obj_a == obj_b - || idx_type->klass->idx_obj_id_equal (idx_type, - obj_a, - obj_b); + nm_assert(idx_type); + return obj_a == obj_b || idx_type->klass->idx_obj_id_equal(idx_type, obj_a, obj_b); } static inline gboolean -nm_dedup_multi_idx_type_partition_equal (const NMDedupMultiIdxType *idx_type, - /* const NMDedupMultiObj * */ gconstpointer obj_a, - /* const NMDedupMultiObj * */ gconstpointer obj_b) +nm_dedup_multi_idx_type_partition_equal(const NMDedupMultiIdxType * idx_type, + /* const NMDedupMultiObj * */ gconstpointer obj_a, + /* const NMDedupMultiObj * */ gconstpointer obj_b) { - nm_assert (idx_type); - if (idx_type->klass->idx_obj_partition_equal) { - nm_assert (obj_a); - nm_assert (obj_b); - return obj_a == obj_b - || idx_type->klass->idx_obj_partition_equal (idx_type, - obj_a, - obj_b); - } - return TRUE; + nm_assert(idx_type); + if (idx_type->klass->idx_obj_partition_equal) { + nm_assert(obj_a); + nm_assert(obj_b); + return obj_a == obj_b || idx_type->klass->idx_obj_partition_equal(idx_type, obj_a, obj_b); + } + return TRUE; } /*****************************************************************************/ struct _NMDedupMultiEntry { + /* this is the list of all entries that share the same head entry. + * All entries compare equal according to idx_obj_partition_equal(). */ + CList lst_entries; - /* this is the list of all entries that share the same head entry. - * All entries compare equal according to idx_obj_partition_equal(). */ - CList lst_entries; + /* const NMDedupMultiObj * */ gconstpointer obj; - /* const NMDedupMultiObj * */ gconstpointer obj; + bool is_head; + bool dirty; - bool is_head; - bool dirty; - - const NMDedupMultiHeadEntry *head; + const NMDedupMultiHeadEntry *head; }; struct _NMDedupMultiHeadEntry { + /* this is the list of all entries that share the same head entry. + * All entries compare equal according to idx_obj_partition_equal(). */ + CList lst_entries_head; - /* this is the list of all entries that share the same head entry. - * All entries compare equal according to idx_obj_partition_equal(). */ - CList lst_entries_head; - - const NMDedupMultiIdxType *idx_type; + const NMDedupMultiIdxType *idx_type; - bool is_head; + bool is_head; - guint len; + guint len; - CList lst_idx; + CList lst_idx; }; /*****************************************************************************/ static inline gconstpointer -nm_dedup_multi_entry_get_obj (const NMDedupMultiEntry *entry) +nm_dedup_multi_entry_get_obj(const NMDedupMultiEntry *entry) { - /* convenience method that allows to skip the %NULL check on - * @entry. Think of the NULL-conditional operator ?. of C# */ - return entry ? entry->obj : NULL; + /* convenience method that allows to skip the %NULL check on + * @entry. Think of the NULL-conditional operator ?. of C# */ + return entry ? entry->obj : NULL; } /*****************************************************************************/ static inline void -nm_dedup_multi_entry_set_dirty (const NMDedupMultiEntry *entry, - gboolean dirty) +nm_dedup_multi_entry_set_dirty(const NMDedupMultiEntry *entry, gboolean dirty) { - /* NMDedupMultiEntry is always exposed as a const object, because it is not - * supposed to be modified outside NMDedupMultiIndex API. Except the "dirty" - * flag. In C++ speak, it is a mutable field. - * - * Add this inline function, to cast-away constness and set the dirty flag. */ - nm_assert (entry); - ((NMDedupMultiEntry *) entry)->dirty = dirty; + /* NMDedupMultiEntry is always exposed as a const object, because it is not + * supposed to be modified outside NMDedupMultiIndex API. Except the "dirty" + * flag. In C++ speak, it is a mutable field. + * + * Add this inline function, to cast-away constness and set the dirty flag. */ + nm_assert(entry); + ((NMDedupMultiEntry *) entry)->dirty = dirty; } /*****************************************************************************/ -NMDedupMultiIndex *nm_dedup_multi_index_new (void); -NMDedupMultiIndex *nm_dedup_multi_index_ref (NMDedupMultiIndex *self); -NMDedupMultiIndex *nm_dedup_multi_index_unref (NMDedupMultiIndex *self); +NMDedupMultiIndex *nm_dedup_multi_index_new(void); +NMDedupMultiIndex *nm_dedup_multi_index_ref(NMDedupMultiIndex *self); +NMDedupMultiIndex *nm_dedup_multi_index_unref(NMDedupMultiIndex *self); static inline void -_nm_auto_unref_dedup_multi_index (NMDedupMultiIndex **v) +_nm_auto_unref_dedup_multi_index(NMDedupMultiIndex **v) { - if (*v) - nm_dedup_multi_index_unref (*v); + if (*v) + nm_dedup_multi_index_unref(*v); } #define nm_auto_unref_dedup_multi_index nm_auto(_nm_auto_unref_dedup_multi_index) -#define NM_DEDUP_MULTI_ENTRY_MISSING ((const NMDedupMultiEntry *) GUINT_TO_POINTER (1)) -#define NM_DEDUP_MULTI_HEAD_ENTRY_MISSING ((const NMDedupMultiHeadEntry *) GUINT_TO_POINTER (1)) - -gboolean nm_dedup_multi_index_add_full (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj, - NMDedupMultiIdxMode mode, - const NMDedupMultiEntry *entry_order, - const NMDedupMultiEntry *entry_existing, - const NMDedupMultiHeadEntry *head_existing, - const NMDedupMultiEntry **out_entry, - /* const NMDedupMultiObj ** */ gpointer out_obj_old); - -gboolean nm_dedup_multi_index_add (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj, - NMDedupMultiIdxMode mode, - const NMDedupMultiEntry **out_entry, - /* const NMDedupMultiObj ** */ gpointer out_obj_old); - -const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj); - -const NMDedupMultiHeadEntry *nm_dedup_multi_index_lookup_head (const NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj); - -guint nm_dedup_multi_index_remove_entry (NMDedupMultiIndex *self, - gconstpointer entry); - -guint nm_dedup_multi_index_remove_obj (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj, - /*const NMDedupMultiObj ** */ gconstpointer *out_obj); - -guint nm_dedup_multi_index_remove_head (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj); +#define NM_DEDUP_MULTI_ENTRY_MISSING ((const NMDedupMultiEntry *) GUINT_TO_POINTER(1)) +#define NM_DEDUP_MULTI_HEAD_ENTRY_MISSING ((const NMDedupMultiHeadEntry *) GUINT_TO_POINTER(1)) -guint nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type); - -void nm_dedup_multi_index_dirty_set_head (NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type, - /*const NMDedupMultiObj * */ gconstpointer obj); - -void nm_dedup_multi_index_dirty_set_idx (NMDedupMultiIndex *self, - const NMDedupMultiIdxType *idx_type); - -guint nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self, - NMDedupMultiIdxType *idx_type, - gboolean mark_survivors_dirty); +gboolean nm_dedup_multi_index_add_full(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + NMDedupMultiIdxMode mode, + const NMDedupMultiEntry * entry_order, + const NMDedupMultiEntry * entry_existing, + const NMDedupMultiHeadEntry * head_existing, + const NMDedupMultiEntry ** out_entry, + /* const NMDedupMultiObj ** */ gpointer out_obj_old); + +gboolean nm_dedup_multi_index_add(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + NMDedupMultiIdxMode mode, + const NMDedupMultiEntry ** out_entry, + /* const NMDedupMultiObj ** */ gpointer out_obj_old); + +const NMDedupMultiEntry * +nm_dedup_multi_index_lookup_obj(const NMDedupMultiIndex * self, + const NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj); + +const NMDedupMultiHeadEntry * +nm_dedup_multi_index_lookup_head(const NMDedupMultiIndex * self, + const NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj); + +guint nm_dedup_multi_index_remove_entry(NMDedupMultiIndex *self, gconstpointer entry); + +guint nm_dedup_multi_index_remove_obj(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + /*const NMDedupMultiObj ** */ gconstpointer *out_obj); + +guint nm_dedup_multi_index_remove_head(NMDedupMultiIndex * self, + NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj); + +guint nm_dedup_multi_index_remove_idx(NMDedupMultiIndex *self, NMDedupMultiIdxType *idx_type); + +void nm_dedup_multi_index_dirty_set_head(NMDedupMultiIndex * self, + const NMDedupMultiIdxType * idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj); + +void nm_dedup_multi_index_dirty_set_idx(NMDedupMultiIndex * self, + const NMDedupMultiIdxType *idx_type); + +guint nm_dedup_multi_index_dirty_remove_idx(NMDedupMultiIndex * self, + NMDedupMultiIdxType *idx_type, + gboolean mark_survivors_dirty); /*****************************************************************************/ typedef struct _NMDedupMultiIter { - const CList *_head; - const CList *_next; - const NMDedupMultiEntry *current; + const CList * _head; + const CList * _next; + const NMDedupMultiEntry *current; } NMDedupMultiIter; static inline void -nm_dedup_multi_iter_init (NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *head) +nm_dedup_multi_iter_init(NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *head) { - g_return_if_fail (iter); - - if (head && !c_list_is_empty (&head->lst_entries_head)) { - iter->_head = &head->lst_entries_head; - iter->_next = head->lst_entries_head.next; - } else { - iter->_head = NULL; - iter->_next = NULL; - } - iter->current = NULL; + g_return_if_fail(iter); + + if (head && !c_list_is_empty(&head->lst_entries_head)) { + iter->_head = &head->lst_entries_head; + iter->_next = head->lst_entries_head.next; + } else { + iter->_head = NULL; + iter->_next = NULL; + } + iter->current = NULL; } static inline gboolean -nm_dedup_multi_iter_next (NMDedupMultiIter *iter) +nm_dedup_multi_iter_next(NMDedupMultiIter *iter) { - g_return_val_if_fail (iter, FALSE); - - if (!iter->_next) - return FALSE; - - /* we always look ahead for the next. This way, the user - * may delete the current entry (but no other entries). */ - iter->current = c_list_entry (iter->_next, NMDedupMultiEntry, lst_entries); - if (iter->_next->next == iter->_head) - iter->_next = NULL; - else - iter->_next = iter->_next->next; - return TRUE; + g_return_val_if_fail(iter, FALSE); + + if (!iter->_next) + return FALSE; + + /* we always look ahead for the next. This way, the user + * may delete the current entry (but no other entries). */ + iter->current = c_list_entry(iter->_next, NMDedupMultiEntry, lst_entries); + if (iter->_next->next == iter->_head) + iter->_next = NULL; + else + iter->_next = iter->_next->next; + return TRUE; } #define nm_dedup_multi_iter_for_each(iter, head_entry) \ - for (nm_dedup_multi_iter_init ((iter), (head_entry)); \ - nm_dedup_multi_iter_next ((iter)); \ - ) + for (nm_dedup_multi_iter_init((iter), (head_entry)); nm_dedup_multi_iter_next((iter));) /*****************************************************************************/ -typedef gboolean (*NMDedupMultiFcnSelectPredicate) (/* const NMDedupMultiObj * */ gconstpointer obj, - gpointer user_data); +typedef gboolean (*NMDedupMultiFcnSelectPredicate)(/* const NMDedupMultiObj * */ gconstpointer obj, + gpointer user_data); -gconstpointer *nm_dedup_multi_objs_to_array_head (const NMDedupMultiHeadEntry *head_entry, - NMDedupMultiFcnSelectPredicate predicate, - gpointer user_data, - guint *out_len); -GPtrArray *nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry, - NMDedupMultiFcnSelectPredicate predicate, - gpointer user_data); +gconstpointer *nm_dedup_multi_objs_to_array_head(const NMDedupMultiHeadEntry * head_entry, + NMDedupMultiFcnSelectPredicate predicate, + gpointer user_data, + guint * out_len); +GPtrArray * nm_dedup_multi_objs_to_ptr_array_head(const NMDedupMultiHeadEntry * head_entry, + NMDedupMultiFcnSelectPredicate predicate, + gpointer user_data); static inline const NMDedupMultiEntry * -nm_dedup_multi_head_entry_get_idx (const NMDedupMultiHeadEntry *head_entry, - int idx) +nm_dedup_multi_head_entry_get_idx(const NMDedupMultiHeadEntry *head_entry, int idx) { - CList *iter; - - if (head_entry) { - if (idx >= 0) { - c_list_for_each (iter, &head_entry->lst_entries_head) { - if (idx-- == 0) - return c_list_entry (iter, NMDedupMultiEntry, lst_entries); - } - } else { - for (iter = head_entry->lst_entries_head.prev; - iter != &head_entry->lst_entries_head; - iter = iter->prev) { - if (++idx == 0) - return c_list_entry (iter, NMDedupMultiEntry, lst_entries); - } - } - } - return NULL; + CList *iter; + + if (head_entry) { + if (idx >= 0) { + c_list_for_each (iter, &head_entry->lst_entries_head) { + if (idx-- == 0) + return c_list_entry(iter, NMDedupMultiEntry, lst_entries); + } + } else { + for (iter = head_entry->lst_entries_head.prev; iter != &head_entry->lst_entries_head; + iter = iter->prev) { + if (++idx == 0) + return c_list_entry(iter, NMDedupMultiEntry, lst_entries); + } + } + } + return NULL; } static inline void -nm_dedup_multi_head_entry_sort (const NMDedupMultiHeadEntry *head_entry, - CListSortCmp cmp, - gconstpointer user_data) +nm_dedup_multi_head_entry_sort(const NMDedupMultiHeadEntry *head_entry, + CListSortCmp cmp, + gconstpointer user_data) { - if (head_entry) { - /* the head entry can be sorted directly without messing up the - * index to which it belongs. Of course, this does mess up any - * NMDedupMultiIter instances. */ - c_list_sort ((CList *) &head_entry->lst_entries_head, cmp, user_data); - } + if (head_entry) { + /* the head entry can be sorted directly without messing up the + * index to which it belongs. Of course, this does mess up any + * NMDedupMultiIter instances. */ + c_list_sort((CList *) &head_entry->lst_entries_head, cmp, user_data); + } } -gboolean nm_dedup_multi_entry_reorder (const NMDedupMultiEntry *entry, - const NMDedupMultiEntry *entry_order, - gboolean order_after); +gboolean nm_dedup_multi_entry_reorder(const NMDedupMultiEntry *entry, + const NMDedupMultiEntry *entry_order, + gboolean order_after); /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-enum-utils.c b/shared/nm-glib-aux/nm-enum-utils.c index 854eda6e..5292755d 100644 --- a/shared/nm-glib-aux/nm-enum-utils.c +++ b/shared/nm-glib-aux/nm-enum-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -10,349 +10,341 @@ /*****************************************************************************/ -#define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET ((ch), ' ', '\t', ',', '\n', '\r')) +#define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET((ch), ' ', '\t', ',', '\n', '\r')) static void -_ASSERT_enum_values_info (GType type, - const NMUtilsEnumValueInfo *value_infos) +_ASSERT_enum_values_info(GType type, const NMUtilsEnumValueInfo *value_infos) { #if NM_MORE_ASSERTS > 5 - nm_auto_unref_gtypeclass GTypeClass *klass = NULL; - gs_unref_hashtable GHashTable *ht = NULL; - - klass = g_type_class_ref (type); - - g_assert (G_IS_ENUM_CLASS (klass) || G_IS_FLAGS_CLASS (klass)); - - if (!value_infos) - return; - - ht = g_hash_table_new (g_str_hash, g_str_equal); - - for (; value_infos->nick; value_infos++) { - - g_assert (value_infos->nick[0]); - - /* duplicate nicks make no sense!! */ - g_assert (!g_hash_table_contains (ht, value_infos->nick)); - g_hash_table_add (ht, (gpointer) value_infos->nick); - - if (G_IS_ENUM_CLASS (klass)) { - GEnumValue *enum_value; - - enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (klass), value_infos->nick); - if (enum_value) { - /* we do allow specifying the same name via @value_infos and @type. - * That might make sense, if @type comes from a library where older versions - * of the library don't yet support the value. In this case, the caller can - * provide the nick via @value_infos, to support the older library version. - * And then, when actually running against a newer library version where - * @type knows the nick, we have this situation. - * - * Another reason for specifying a nick both in @value_infos and @type, - * is to specify an alias which is not used with highest preference. For - * example, if you add an alias "disabled" for "none" (both numerically - * equal), then the first alias in @value_infos will be preferred over - * the name from @type. So, to still use "none" as preferred name, you may - * explicitly specify the "none" alias in @value_infos before "disabled". - * - * However, what never is allowed, is to use a name (nick) to re-number - * the value. That is, if both @value_infos and @type contain a particular - * nick, their numeric values must agree as well. - * Allowing this, would be very confusing, because the name would have a different - * value from the regular GLib GEnum API. - */ - g_assert (enum_value->value == value_infos->value); - } - } else { - GFlagsValue *flags_value; - - flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (klass), value_infos->nick); - if (flags_value) { - /* see ENUM case above. */ - g_assert (flags_value->value == (guint) value_infos->value); - } - } - } + nm_auto_unref_gtypeclass GTypeClass *klass = NULL; + gs_unref_hashtable GHashTable *ht = NULL; + + klass = g_type_class_ref(type); + + g_assert(G_IS_ENUM_CLASS(klass) || G_IS_FLAGS_CLASS(klass)); + + if (!value_infos) + return; + + ht = g_hash_table_new(g_str_hash, g_str_equal); + + for (; value_infos->nick; value_infos++) { + g_assert(value_infos->nick[0]); + + /* duplicate nicks make no sense!! */ + g_assert(!g_hash_table_contains(ht, value_infos->nick)); + g_hash_table_add(ht, (gpointer) value_infos->nick); + + if (G_IS_ENUM_CLASS(klass)) { + GEnumValue *enum_value; + + enum_value = g_enum_get_value_by_nick(G_ENUM_CLASS(klass), value_infos->nick); + if (enum_value) { + /* we do allow specifying the same name via @value_infos and @type. + * That might make sense, if @type comes from a library where older versions + * of the library don't yet support the value. In this case, the caller can + * provide the nick via @value_infos, to support the older library version. + * And then, when actually running against a newer library version where + * @type knows the nick, we have this situation. + * + * Another reason for specifying a nick both in @value_infos and @type, + * is to specify an alias which is not used with highest preference. For + * example, if you add an alias "disabled" for "none" (both numerically + * equal), then the first alias in @value_infos will be preferred over + * the name from @type. So, to still use "none" as preferred name, you may + * explicitly specify the "none" alias in @value_infos before "disabled". + * + * However, what never is allowed, is to use a name (nick) to re-number + * the value. That is, if both @value_infos and @type contain a particular + * nick, their numeric values must agree as well. + * Allowing this, would be very confusing, because the name would have a different + * value from the regular GLib GEnum API. + */ + g_assert(enum_value->value == value_infos->value); + } + } else { + GFlagsValue *flags_value; + + flags_value = g_flags_get_value_by_nick(G_FLAGS_CLASS(klass), value_infos->nick); + if (flags_value) { + /* see ENUM case above. */ + g_assert(flags_value->value == (guint) value_infos->value); + } + } + } #endif } static gboolean -_is_hex_string (const char *str) +_is_hex_string(const char *str) { - return str[0] == '0' - && str[1] == 'x' - && str[2] - && NM_STRCHAR_ALL (&str[2], ch, g_ascii_isxdigit (ch)); + return str[0] == '0' && str[1] == 'x' && str[2] + && NM_STRCHAR_ALL(&str[2], ch, g_ascii_isxdigit(ch)); } static gboolean -_is_dec_string (const char *str) +_is_dec_string(const char *str) { - return str[0] - && NM_STRCHAR_ALL (&str[0], ch, g_ascii_isdigit (ch)); + return str[0] && NM_STRCHAR_ALL(&str[0], ch, g_ascii_isdigit(ch)); } static gboolean -_enum_is_valid_enum_nick (const char *str) +_enum_is_valid_enum_nick(const char *str) { - return str[0] - && !NM_STRCHAR_ANY (str, ch, g_ascii_isspace (ch)) - && !_is_dec_string (str) - && !_is_hex_string (str); + return str[0] && !NM_STRCHAR_ANY(str, ch, g_ascii_isspace(ch)) && !_is_dec_string(str) + && !_is_hex_string(str); } static gboolean -_enum_is_valid_flags_nick (const char *str) +_enum_is_valid_flags_nick(const char *str) { - return str[0] - && !NM_STRCHAR_ANY (str, ch, IS_FLAGS_SEPARATOR (ch)) - && !_is_dec_string (str) - && !_is_hex_string (str); + return str[0] && !NM_STRCHAR_ANY(str, ch, IS_FLAGS_SEPARATOR(ch)) && !_is_dec_string(str) + && !_is_hex_string(str); } char * -_nm_utils_enum_to_str_full (GType type, - int value, - const char *flags_separator, - const NMUtilsEnumValueInfo *value_infos) +_nm_utils_enum_to_str_full(GType type, + int value, + const char * flags_separator, + const NMUtilsEnumValueInfo *value_infos) { - nm_auto_unref_gtypeclass GTypeClass *klass = NULL; - - _ASSERT_enum_values_info (type, value_infos); - - if ( flags_separator - && ( !flags_separator[0] - || NM_STRCHAR_ANY (flags_separator, ch, !IS_FLAGS_SEPARATOR (ch)))) - g_return_val_if_reached (NULL); - - klass = g_type_class_ref (type); - - if (G_IS_ENUM_CLASS (klass)) { - GEnumValue *enum_value; - - for ( ; value_infos && value_infos->nick; value_infos++) { - if (value_infos->value == value) - return g_strdup (value_infos->nick); - } - - enum_value = g_enum_get_value (G_ENUM_CLASS (klass), value); - if ( !enum_value - || !_enum_is_valid_enum_nick (enum_value->value_nick)) - return g_strdup_printf ("%d", value); - else - return g_strdup (enum_value->value_nick); - } else if (G_IS_FLAGS_CLASS (klass)) { - unsigned uvalue = (unsigned) value; - GFlagsValue *flags_value; - NMStrBuf strbuf; - - flags_separator = flags_separator ?: " "; - - nm_str_buf_init (&strbuf, 16, FALSE); - - for ( ; value_infos && value_infos->nick; value_infos++) { - - nm_assert (_enum_is_valid_flags_nick (value_infos->nick)); - - if (uvalue == 0) { - if (value_infos->value != 0) - continue; - } else { - if (!NM_FLAGS_ALL (uvalue, (unsigned) value_infos->value)) - continue; - } - - if (strbuf.len) - nm_str_buf_append (&strbuf, flags_separator); - nm_str_buf_append (&strbuf, value_infos->nick); - uvalue &= ~((unsigned) value_infos->value); - if (uvalue == 0) { - /* we printed all flags. Done. */ - goto flags_done; - } - } - - do { - flags_value = g_flags_get_first_value (G_FLAGS_CLASS (klass), uvalue); - if (strbuf.len) - nm_str_buf_append (&strbuf, flags_separator); - if ( !flags_value - || !_enum_is_valid_flags_nick (flags_value->value_nick)) { - if (uvalue) - nm_str_buf_append_printf (&strbuf, "0x%x", uvalue); - break; - } - nm_str_buf_append (&strbuf, flags_value->value_nick); - uvalue &= ~flags_value->value; - } while (uvalue); + nm_auto_unref_gtypeclass GTypeClass *klass = NULL; + + _ASSERT_enum_values_info(type, value_infos); + + if (flags_separator + && (!flags_separator[0] || NM_STRCHAR_ANY(flags_separator, ch, !IS_FLAGS_SEPARATOR(ch)))) + g_return_val_if_reached(NULL); + + klass = g_type_class_ref(type); + + if (G_IS_ENUM_CLASS(klass)) { + GEnumValue *enum_value; + + for (; value_infos && value_infos->nick; value_infos++) { + if (value_infos->value == value) + return g_strdup(value_infos->nick); + } + + enum_value = g_enum_get_value(G_ENUM_CLASS(klass), value); + if (!enum_value || !_enum_is_valid_enum_nick(enum_value->value_nick)) + return g_strdup_printf("%d", value); + else + return g_strdup(enum_value->value_nick); + } else if (G_IS_FLAGS_CLASS(klass)) { + unsigned uvalue = (unsigned) value; + GFlagsValue *flags_value; + NMStrBuf strbuf; + + flags_separator = flags_separator ?: " "; + + nm_str_buf_init(&strbuf, 16, FALSE); + + for (; value_infos && value_infos->nick; value_infos++) { + nm_assert(_enum_is_valid_flags_nick(value_infos->nick)); + + if (uvalue == 0) { + if (value_infos->value != 0) + continue; + } else { + if (!NM_FLAGS_ALL(uvalue, (unsigned) value_infos->value)) + continue; + } + + if (strbuf.len) + nm_str_buf_append(&strbuf, flags_separator); + nm_str_buf_append(&strbuf, value_infos->nick); + uvalue &= ~((unsigned) value_infos->value); + if (uvalue == 0) { + /* we printed all flags. Done. */ + goto flags_done; + } + } + + do { + flags_value = g_flags_get_first_value(G_FLAGS_CLASS(klass), uvalue); + if (strbuf.len) + nm_str_buf_append(&strbuf, flags_separator); + if (!flags_value || !_enum_is_valid_flags_nick(flags_value->value_nick)) { + if (uvalue) + nm_str_buf_append_printf(&strbuf, "0x%x", uvalue); + break; + } + nm_str_buf_append(&strbuf, flags_value->value_nick); + uvalue &= ~flags_value->value; + } while (uvalue); flags_done: - return nm_str_buf_finalize (&strbuf, NULL); - } + return nm_str_buf_finalize(&strbuf, NULL); + } - g_return_val_if_reached (NULL); + g_return_val_if_reached(NULL); } static const NMUtilsEnumValueInfo * -_find_value_info (const NMUtilsEnumValueInfo *value_infos, const char *needle) +_find_value_info(const NMUtilsEnumValueInfo *value_infos, const char *needle) { - if (value_infos) { - for (; value_infos->nick; value_infos++) { - if (nm_streq (needle, value_infos->nick)) - return value_infos; - } - } - return NULL; + if (value_infos) { + for (; value_infos->nick; value_infos++) { + if (nm_streq(needle, value_infos->nick)) + return value_infos; + } + } + return NULL; } gboolean -_nm_utils_enum_from_str_full (GType type, - const char *str, - int *out_value, - char **err_token, - const NMUtilsEnumValueInfo *value_infos) +_nm_utils_enum_from_str_full(GType type, + const char * str, + int * out_value, + char ** err_token, + const NMUtilsEnumValueInfo *value_infos) { - nm_auto_unref_gtypeclass GTypeClass *klass = NULL; - gboolean ret = FALSE; - int value = 0; - gs_free char *str_clone = NULL; - char *s; - gint64 v64; - const NMUtilsEnumValueInfo *nick; - - g_return_val_if_fail (str, FALSE); - - _ASSERT_enum_values_info (type, value_infos); - - str_clone = strdup (str); - s = nm_str_skip_leading_spaces (str_clone); - g_strchomp (s); - - klass = g_type_class_ref (type); - - if (G_IS_ENUM_CLASS (klass)) { - GEnumValue *enum_value; - - if (s[0]) { - if (_is_hex_string (s)) { - v64 = _nm_utils_ascii_str_to_int64 (s, 16, 0, G_MAXUINT, -1); - if (v64 != -1) { - value = (int) v64; - ret = TRUE; - } - } else if (_is_dec_string (s)) { - v64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT, -1); - if (v64 != -1) { - value = (int) v64; - ret = TRUE; - } - } else if ((nick = _find_value_info (value_infos, s))) { - value = nick->value; - ret = TRUE; - } else if ((enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (klass), s))) { - value = enum_value->value; - ret = TRUE; - } - } - } else if (G_IS_FLAGS_CLASS (klass)) { - GFlagsValue *flags_value; - unsigned uvalue = 0; - - ret = TRUE; - while (s[0]) { - char *s_end; - - for (s_end = s; s_end[0]; s_end++) { - if (IS_FLAGS_SEPARATOR (s_end[0])) { - s_end[0] = '\0'; - s_end++; - break; - } - } - - if (s[0]) { - if (_is_hex_string (s)) { - v64 = _nm_utils_ascii_str_to_int64 (&s[2], 16, 0, G_MAXUINT, -1); - if (v64 == -1) { - ret = FALSE; - break; - } - uvalue |= (unsigned) v64; - } else if (_is_dec_string (s)) { - v64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXUINT, -1); - if (v64 == -1) { - ret = FALSE; - break; - } - uvalue |= (unsigned) v64; - } else if ((nick = _find_value_info (value_infos, s))) - uvalue |= (unsigned) nick->value; - else if ((flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (klass), s))) - uvalue |= flags_value->value; - else { - ret = FALSE; - break; - } - } - - s = s_end; - } - - value = (int) uvalue; - } else - g_return_val_if_reached (FALSE); - - NM_SET_OUT (err_token, !ret && s[0] ? g_strdup (s) : NULL); - NM_SET_OUT (out_value, ret ? value : 0); - return ret; + nm_auto_unref_gtypeclass GTypeClass *klass = NULL; + gboolean ret = FALSE; + int value = 0; + gs_free char * str_clone = NULL; + char * s; + gint64 v64; + const NMUtilsEnumValueInfo * nick; + + g_return_val_if_fail(str, FALSE); + + _ASSERT_enum_values_info(type, value_infos); + + str_clone = strdup(str); + s = nm_str_skip_leading_spaces(str_clone); + g_strchomp(s); + + klass = g_type_class_ref(type); + + if (G_IS_ENUM_CLASS(klass)) { + GEnumValue *enum_value; + + if (s[0]) { + if (_is_hex_string(s)) { + v64 = _nm_utils_ascii_str_to_int64(s, 16, 0, G_MAXUINT, -1); + if (v64 != -1) { + value = (int) v64; + ret = TRUE; + } + } else if (_is_dec_string(s)) { + v64 = _nm_utils_ascii_str_to_int64(s, 10, 0, G_MAXUINT, -1); + if (v64 != -1) { + value = (int) v64; + ret = TRUE; + } + } else if ((nick = _find_value_info(value_infos, s))) { + value = nick->value; + ret = TRUE; + } else if ((enum_value = g_enum_get_value_by_nick(G_ENUM_CLASS(klass), s))) { + value = enum_value->value; + ret = TRUE; + } + } + } else if (G_IS_FLAGS_CLASS(klass)) { + GFlagsValue *flags_value; + unsigned uvalue = 0; + + ret = TRUE; + while (s[0]) { + char *s_end; + + for (s_end = s; s_end[0]; s_end++) { + if (IS_FLAGS_SEPARATOR(s_end[0])) { + s_end[0] = '\0'; + s_end++; + break; + } + } + + if (s[0]) { + if (_is_hex_string(s)) { + v64 = _nm_utils_ascii_str_to_int64(&s[2], 16, 0, G_MAXUINT, -1); + if (v64 == -1) { + ret = FALSE; + break; + } + uvalue |= (unsigned) v64; + } else if (_is_dec_string(s)) { + v64 = _nm_utils_ascii_str_to_int64(s, 10, 0, G_MAXUINT, -1); + if (v64 == -1) { + ret = FALSE; + break; + } + uvalue |= (unsigned) v64; + } else if ((nick = _find_value_info(value_infos, s))) + uvalue |= (unsigned) nick->value; + else if ((flags_value = g_flags_get_value_by_nick(G_FLAGS_CLASS(klass), s))) + uvalue |= flags_value->value; + else { + ret = FALSE; + break; + } + } + + s = s_end; + } + + value = (int) uvalue; + } else + g_return_val_if_reached(FALSE); + + NM_SET_OUT(err_token, !ret && s[0] ? g_strdup(s) : NULL); + NM_SET_OUT(out_value, ret ? value : 0); + return ret; } const char ** -_nm_utils_enum_get_values (GType type, int from, int to) +_nm_utils_enum_get_values(GType type, int from, int to) { - GTypeClass *klass; - GPtrArray *array; - int i; - char sbuf[64]; - - klass = g_type_class_ref (type); - array = g_ptr_array_new (); - - if (G_IS_ENUM_CLASS (klass)) { - GEnumClass *enum_class = G_ENUM_CLASS (klass); - GEnumValue *enum_value; - - for (i = 0; i < enum_class->n_values; i++) { - enum_value = &enum_class->values[i]; - if (enum_value->value >= from && enum_value->value <= to) { - if (_enum_is_valid_enum_nick (enum_value->value_nick)) - g_ptr_array_add (array, (gpointer) enum_value->value_nick); - else - g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "%d", enum_value->value))); - } - } - } else if (G_IS_FLAGS_CLASS (klass)) { - GFlagsClass *flags_class = G_FLAGS_CLASS (klass); - GFlagsValue *flags_value; - - for (i = 0; i < flags_class->n_values; i++) { - flags_value = &flags_class->values[i]; - if (flags_value->value >= (guint) from && flags_value->value <= (guint) to) { - if (_enum_is_valid_flags_nick (flags_value->value_nick)) - g_ptr_array_add (array, (gpointer) flags_value->value_nick); - else - g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "0x%x", (unsigned) flags_value->value))); - } - } - } else { - g_type_class_unref (klass); - g_ptr_array_free (array, TRUE); - g_return_val_if_reached (NULL); - } - - g_type_class_unref (klass); - g_ptr_array_add (array, NULL); - - return (const char **) g_ptr_array_free (array, FALSE); + GTypeClass *klass; + GPtrArray * array; + int i; + char sbuf[64]; + + klass = g_type_class_ref(type); + array = g_ptr_array_new(); + + if (G_IS_ENUM_CLASS(klass)) { + GEnumClass *enum_class = G_ENUM_CLASS(klass); + GEnumValue *enum_value; + + for (i = 0; i < enum_class->n_values; i++) { + enum_value = &enum_class->values[i]; + if (enum_value->value >= from && enum_value->value <= to) { + if (_enum_is_valid_enum_nick(enum_value->value_nick)) + g_ptr_array_add(array, (gpointer) enum_value->value_nick); + else + g_ptr_array_add( + array, + (gpointer) g_intern_string(nm_sprintf_buf(sbuf, "%d", enum_value->value))); + } + } + } else if (G_IS_FLAGS_CLASS(klass)) { + GFlagsClass *flags_class = G_FLAGS_CLASS(klass); + GFlagsValue *flags_value; + + for (i = 0; i < flags_class->n_values; i++) { + flags_value = &flags_class->values[i]; + if (flags_value->value >= (guint) from && flags_value->value <= (guint) to) { + if (_enum_is_valid_flags_nick(flags_value->value_nick)) + g_ptr_array_add(array, (gpointer) flags_value->value_nick); + else + g_ptr_array_add( + array, + (gpointer) g_intern_string( + nm_sprintf_buf(sbuf, "0x%x", (unsigned) flags_value->value))); + } + } + } else { + g_type_class_unref(klass); + g_ptr_array_free(array, TRUE); + g_return_val_if_reached(NULL); + } + + g_type_class_unref(klass); + g_ptr_array_add(array, NULL); + + return (const char **) g_ptr_array_free(array, FALSE); } diff --git a/shared/nm-glib-aux/nm-enum-utils.h b/shared/nm-glib-aux/nm-enum-utils.h index d863dabd..38acf8fd 100644 --- a/shared/nm-glib-aux/nm-enum-utils.h +++ b/shared/nm-glib-aux/nm-enum-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -9,23 +9,23 @@ /*****************************************************************************/ typedef struct _NMUtilsEnumValueInfo { - /* currently, this is only used for _nm_utils_enum_from_str_full() to - * declare additional aliases for values. */ - const char *nick; - int value; + /* currently, this is only used for _nm_utils_enum_from_str_full() to + * declare additional aliases for values. */ + const char *nick; + int value; } NMUtilsEnumValueInfo; -char *_nm_utils_enum_to_str_full (GType type, - int value, - const char *sep, - const NMUtilsEnumValueInfo *value_infos); -gboolean _nm_utils_enum_from_str_full (GType type, - const char *str, - int *out_value, - char **err_token, - const NMUtilsEnumValueInfo *value_infos); +char * _nm_utils_enum_to_str_full(GType type, + int value, + const char * sep, + const NMUtilsEnumValueInfo *value_infos); +gboolean _nm_utils_enum_from_str_full(GType type, + const char * str, + int * out_value, + char ** err_token, + const NMUtilsEnumValueInfo *value_infos); -const char **_nm_utils_enum_get_values (GType type, int from, int to); +const char **_nm_utils_enum_get_values(GType type, int from, int to); /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-errno.c b/shared/nm-glib-aux/nm-errno.c index e709f9e6..f7a7685d 100644 --- a/shared/nm-glib-aux/nm-errno.c +++ b/shared/nm-glib-aux/nm-errno.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -11,43 +11,42 @@ /*****************************************************************************/ -static -NM_UTILS_LOOKUP_STR_DEFINE (_geterror, +static NM_UTILS_LOOKUP_STR_DEFINE( + _geterror, #if 0 - enum _NMErrno, + enum _NMErrno, #else - int, + int, #endif - NM_UTILS_LOOKUP_DEFAULT (NULL), - - NM_UTILS_LOOKUP_STR_ITEM (NME_ERRNO_SUCCESS, "NME_ERRNO_SUCCESS"), - NM_UTILS_LOOKUP_STR_ITEM (NME_ERRNO_OUT_OF_RANGE, "NME_ERRNO_OUT_OF_RANGE"), - - NM_UTILS_LOOKUP_STR_ITEM (NME_UNSPEC, "NME_UNSPEC"), - NM_UTILS_LOOKUP_STR_ITEM (NME_BUG, "NME_BUG"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NATIVE_ERRNO, "NME_NATIVE_ERRNO"), - - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_ATTRSIZE, "NME_NL_ATTRSIZE"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_BAD_SOCK, "NME_NL_BAD_SOCK"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_DUMP_INTR, "NME_NL_DUMP_INTR"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_MSG_OVERFLOW, "NME_NL_MSG_OVERFLOW"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_MSG_TOOSHORT, "NME_NL_MSG_TOOSHORT"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_MSG_TRUNC, "NME_NL_MSG_TRUNC"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_SEQ_MISMATCH, "NME_NL_SEQ_MISMATCH"), - NM_UTILS_LOOKUP_STR_ITEM (NME_NL_NOADDR, "NME_NL_NOADDR"), - - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NOT_FOUND, "not-found"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_EXISTS, "exists"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_WRONG_TYPE, "wrong-type"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NOT_SLAVE, "not-slave"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NO_FIRMWARE, "no-firmware"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_OPNOTSUPP, "not-supported"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_NETLINK, "netlink"), - NM_UTILS_LOOKUP_STR_ITEM (NME_PL_CANT_SET_MTU, "cant-set-mtu"), - - NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_ERRNO_MININT), - NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_ERRNO_RESERVED_LAST_PLUS_1), -); + NM_UTILS_LOOKUP_DEFAULT(NULL), + + NM_UTILS_LOOKUP_STR_ITEM(NME_ERRNO_SUCCESS, "NME_ERRNO_SUCCESS"), + NM_UTILS_LOOKUP_STR_ITEM(NME_ERRNO_OUT_OF_RANGE, "NME_ERRNO_OUT_OF_RANGE"), + + NM_UTILS_LOOKUP_STR_ITEM(NME_UNSPEC, "NME_UNSPEC"), + NM_UTILS_LOOKUP_STR_ITEM(NME_BUG, "NME_BUG"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NATIVE_ERRNO, "NME_NATIVE_ERRNO"), + + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_ATTRSIZE, "NME_NL_ATTRSIZE"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_BAD_SOCK, "NME_NL_BAD_SOCK"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_DUMP_INTR, "NME_NL_DUMP_INTR"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_OVERFLOW, "NME_NL_MSG_OVERFLOW"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TOOSHORT, "NME_NL_MSG_TOOSHORT"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TRUNC, "NME_NL_MSG_TRUNC"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_SEQ_MISMATCH, "NME_NL_SEQ_MISMATCH"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_NOADDR, "NME_NL_NOADDR"), + + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NOT_FOUND, "not-found"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_EXISTS, "exists"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_WRONG_TYPE, "wrong-type"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NOT_SLAVE, "not-slave"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NO_FIRMWARE, "no-firmware"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_OPNOTSUPP, "not-supported"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NETLINK, "netlink"), + NM_UTILS_LOOKUP_STR_ITEM(NME_PL_CANT_SET_MTU, "cant-set-mtu"), + + NM_UTILS_LOOKUP_ITEM_IGNORE(_NM_ERRNO_MININT), + NM_UTILS_LOOKUP_ITEM_IGNORE(_NM_ERRNO_RESERVED_LAST_PLUS_1), ); /** * nm_strerror(): @@ -58,24 +57,24 @@ 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. */ const char * -nm_strerror (int nmerr) +nm_strerror(int nmerr) { - const char *s; + const char *s; - nmerr = nm_errno (nmerr); + nmerr = nm_errno(nmerr); - if (nmerr >= _NM_ERRNO_RESERVED_FIRST) { - s = _geterror (nmerr); - if (s) - return s; - } - return nm_strerror_native (nmerr); + if (nmerr >= _NM_ERRNO_RESERVED_FIRST) { + s = _geterror(nmerr); + if (s) + return s; + } + return nm_strerror_native(nmerr); } /*****************************************************************************/ @@ -97,45 +96,44 @@ 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) +nm_strerror_native_r(int errsv, char *buf, gsize buf_size) { - char *buf2; - - nm_assert (buf); - nm_assert (buf_size > 0); - -#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE - /* XSI-compliant */ - { - int errno_saved = errno; - - if (strerror_r (errsv, buf, buf_size) != 0) { - g_snprintf (buf, buf_size, "Unspecified errno %d", errsv); - errno = errno_saved; - } - buf2 = buf; - } + char *buf2; + + nm_assert(buf); + nm_assert(buf_size > 0); + +#if (_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE + /* XSI-compliant */ + { + int errno_saved = errno; + + if (strerror_r(errsv, buf, buf_size) != 0) { + g_snprintf(buf, buf_size, "Unspecified errno %d", errsv); + errno = errno_saved; + } + buf2 = buf; + } #else - /* GNU-specific */ - buf2 = strerror_r (errsv, buf, buf_size); + /* GNU-specific */ + buf2 = strerror_r(errsv, buf, buf_size); #endif - /* like g_strerror(), ensure that the error message is UTF-8. */ - if ( !g_get_charset (NULL) - && !g_utf8_validate (buf2, -1, NULL)) { - gs_free char *msg = NULL; + /* like g_strerror(), ensure that the error message is UTF-8. */ + if (!g_get_charset(NULL) && !g_utf8_validate(buf2, -1, NULL)) { + gs_free char *msg = NULL; - msg = g_locale_to_utf8 (buf2, -1, NULL, NULL, NULL); - if (msg) { - g_strlcpy (buf, msg, buf_size); - buf2 = buf; - } - } + msg = g_locale_to_utf8(buf2, -1, NULL, NULL, NULL); + if (msg) { + g_strlcpy(buf, msg, buf_size); + buf2 = buf; + } + } - return buf2; + return buf2; } /** @@ -157,28 +155,27 @@ nm_strerror_native_r (int errsv, char *buf, gsize buf_size) * Returns: (transfer none): the text representation of the error number. */ const char * -nm_strerror_native (int errsv) +nm_strerror_native(int errsv) { - static _nm_thread_local char *buf_static = NULL; - char *buf; - - buf = buf_static; - if (G_UNLIKELY (!buf)) { - int errno_saved = errno; - pthread_key_t key; - - buf = g_malloc (NM_STRERROR_BUFSIZE); - buf_static = buf; - - if ( pthread_key_create (&key, g_free) != 0 - || pthread_setspecific (key, buf) != 0) { - /* Failure. We will leak the buffer when the thread exits. - * - * Nothing we can do about it really. For Debug builds we fail with an assertion. */ - nm_assert_not_reached (); - } - errno = errno_saved; - } - - return nm_strerror_native_r (errsv, buf, NM_STRERROR_BUFSIZE); + static _nm_thread_local char *buf_static = NULL; + char * buf; + + buf = buf_static; + if (G_UNLIKELY(!buf)) { + int errno_saved = errno; + pthread_key_t key; + + buf = g_malloc(NM_STRERROR_BUFSIZE); + buf_static = buf; + + if (pthread_key_create(&key, g_free) != 0 || pthread_setspecific(key, buf) != 0) { + /* Failure. We will leak the buffer when the thread exits. + * + * Nothing we can do about it really. For Debug builds we fail with an assertion. */ + nm_assert_not_reached(); + } + errno = errno_saved; + } + + return nm_strerror_native_r(errsv, buf, NM_STRERROR_BUFSIZE); } diff --git a/shared/nm-glib-aux/nm-errno.h b/shared/nm-glib-aux/nm-errno.h index 1d329b25..bf7189c0 100644 --- a/shared/nm-glib-aux/nm-errno.h +++ b/shared/nm-glib-aux/nm-errno.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -11,56 +11,54 @@ /*****************************************************************************/ enum _NMErrno { - _NM_ERRNO_MININT = G_MININT, - _NM_ERRNO_MAXINT = G_MAXINT, - _NM_ERRNO_RESERVED_FIRST = 100000, - - - /* when we cannot represent a number as positive number, we resort to this - * number. Basically, the values G_MININT, -NME_ERRNO_SUCCESS, NME_ERRNO_SUCCESS - * and G_MAXINT all map to the same value. */ - NME_ERRNO_OUT_OF_RANGE = G_MAXINT, - - /* Indicate that the original errno was zero. Zero denotes *no error*, but we know something - * went wrong and we want to report some error. This is a placeholder to mean, something - * was wrong, but errno was zero. */ - NME_ERRNO_SUCCESS = G_MAXINT - 1, - - - /* an unspecified error. */ - NME_UNSPEC = _NM_ERRNO_RESERVED_FIRST, - - /* A bug, for example when an assertion failed. - * Should never happen. */ - NME_BUG, - - /* a native error number (from <errno.h>) cannot be mapped as - * an nm-error, because it is in the range [_NM_ERRNO_RESERVED_FIRST, - * _NM_ERRNO_RESERVED_LAST]. */ - NME_NATIVE_ERRNO, - - /* netlink errors. */ - NME_NL_SEQ_MISMATCH, - NME_NL_MSG_TRUNC, - NME_NL_MSG_TOOSHORT, - NME_NL_DUMP_INTR, - NME_NL_ATTRSIZE, - NME_NL_BAD_SOCK, - NME_NL_NOADDR, - NME_NL_MSG_OVERFLOW, - - /* platform errors. */ - NME_PL_NOT_FOUND, - NME_PL_EXISTS, - NME_PL_WRONG_TYPE, - NME_PL_NOT_SLAVE, - NME_PL_NO_FIRMWARE, - NME_PL_OPNOTSUPP, - NME_PL_NETLINK, - NME_PL_CANT_SET_MTU, - - _NM_ERRNO_RESERVED_LAST_PLUS_1, - _NM_ERRNO_RESERVED_LAST = _NM_ERRNO_RESERVED_LAST_PLUS_1 - 1, + _NM_ERRNO_MININT = G_MININT, + _NM_ERRNO_MAXINT = G_MAXINT, + _NM_ERRNO_RESERVED_FIRST = 100000, + + /* when we cannot represent a number as positive number, we resort to this + * number. Basically, the values G_MININT, -NME_ERRNO_SUCCESS, NME_ERRNO_SUCCESS + * and G_MAXINT all map to the same value. */ + NME_ERRNO_OUT_OF_RANGE = G_MAXINT, + + /* Indicate that the original errno was zero. Zero denotes *no error*, but we know something + * went wrong and we want to report some error. This is a placeholder to mean, something + * was wrong, but errno was zero. */ + NME_ERRNO_SUCCESS = G_MAXINT - 1, + + /* an unspecified error. */ + NME_UNSPEC = _NM_ERRNO_RESERVED_FIRST, + + /* A bug, for example when an assertion failed. + * Should never happen. */ + NME_BUG, + + /* a native error number (from <errno.h>) cannot be mapped as + * an nm-error, because it is in the range [_NM_ERRNO_RESERVED_FIRST, + * _NM_ERRNO_RESERVED_LAST]. */ + NME_NATIVE_ERRNO, + + /* netlink errors. */ + NME_NL_SEQ_MISMATCH, + NME_NL_MSG_TRUNC, + NME_NL_MSG_TOOSHORT, + NME_NL_DUMP_INTR, + NME_NL_ATTRSIZE, + NME_NL_BAD_SOCK, + NME_NL_NOADDR, + NME_NL_MSG_OVERFLOW, + + /* platform errors. */ + NME_PL_NOT_FOUND, + NME_PL_EXISTS, + NME_PL_WRONG_TYPE, + NME_PL_NOT_SLAVE, + NME_PL_NO_FIRMWARE, + NME_PL_OPNOTSUPP, + NME_PL_NETLINK, + NME_PL_CANT_SET_MTU, + + _NM_ERRNO_RESERVED_LAST_PLUS_1, + _NM_ERRNO_RESERVED_LAST = _NM_ERRNO_RESERVED_LAST_PLUS_1 - 1, }; /*****************************************************************************/ @@ -77,13 +75,13 @@ enum _NMErrno { * In a sense, the macro is related to nm_errno_native() function, but the difference * is that this macro asserts that @errsv is positive, while nm_errno_native() coerces * negative values to be non-negative. */ -#define NM_ERRNO_NATIVE(errsv) \ - ({ \ - const int _errsv_x = (errsv); \ - \ - nm_assert (_errsv_x > 0); \ - _errsv_x; \ - }) +#define NM_ERRNO_NATIVE(errsv) \ + ({ \ + const int _errsv_x = (errsv); \ + \ + nm_assert(_errsv_x > 0); \ + _errsv_x; \ + }) /* Normalize native errno. * @@ -98,14 +96,16 @@ enum _NMErrno { * Basically, this normalizes errsv to be positive (taking care of two pathological cases). */ static inline int -nm_errno_native (int errsv) +nm_errno_native(int errsv) { - switch (errsv) { - case 0: return NME_ERRNO_SUCCESS; - case G_MININT: return NME_ERRNO_OUT_OF_RANGE; - default: - return errsv >= 0 ? errsv : -errsv; - } + switch (errsv) { + case 0: + return NME_ERRNO_SUCCESS; + case G_MININT: + return NME_ERRNO_OUT_OF_RANGE; + default: + return errsv >= 0 ? errsv : -errsv; + } } /* Normalizes an nm-error to be positive. @@ -118,9 +118,9 @@ nm_errno_native (int errsv) * as far as normalizing goes, nm_errno() does exactly the same remapping as * nm_errno_native(). */ static inline int -nm_errno (int nmerr) +nm_errno(int nmerr) { - return nm_errno_native (nmerr); + return nm_errno_native(nmerr); } /* this maps a native errno to a (always non-negative) nm-error number. @@ -141,29 +141,30 @@ nm_errno (int nmerr) * - all other values are their (positive) absolute value. */ static inline int -nm_errno_from_native (int errsv) +nm_errno_from_native(int errsv) { - switch (errsv) { - case 0: return NME_ERRNO_SUCCESS; - case G_MININT: return NME_ERRNO_OUT_OF_RANGE; - default: - if (errsv < 0) - errsv = -errsv; - return G_UNLIKELY ( errsv >= _NM_ERRNO_RESERVED_FIRST - && errsv <= _NM_ERRNO_RESERVED_LAST) - ? NME_NATIVE_ERRNO - : errsv; - } + switch (errsv) { + case 0: + return NME_ERRNO_SUCCESS; + case G_MININT: + return NME_ERRNO_OUT_OF_RANGE; + default: + if (errsv < 0) + errsv = -errsv; + return G_UNLIKELY(errsv >= _NM_ERRNO_RESERVED_FIRST && errsv <= _NM_ERRNO_RESERVED_LAST) + ? NME_NATIVE_ERRNO + : errsv; + } } -const char *nm_strerror (int nmerr); +const char *nm_strerror(int nmerr); /*****************************************************************************/ #define NM_STRERROR_BUFSIZE 1024 -const char *nm_strerror_native_r (int errsv, char *buf, gsize buf_size); -const char *nm_strerror_native (int errsv); +const char *nm_strerror_native_r(int errsv, char *buf, gsize buf_size); +const char *nm_strerror_native(int errsv); /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-glib.h b/shared/nm-glib-aux/nm-glib.h index 2df51795..5125617d 100644 --- a/shared/nm-glib-aux/nm-glib.h +++ b/shared/nm-glib-aux/nm-glib.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2008 - 2018 Red Hat, Inc. */ @@ -9,129 +9,156 @@ /*****************************************************************************/ #ifndef __NM_MACROS_INTERNAL_H__ -#error "nm-glib.h requires nm-macros-internal.h. Do not include this directly" + #error "nm-glib.h requires nm-macros-internal.h. Do not include this directly" #endif /*****************************************************************************/ #ifdef __clang__ -#undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS -#undef G_GNUC_END_IGNORE_DEPRECATIONS + #undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS + #undef G_GNUC_END_IGNORE_DEPRECATIONS -#define G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") + #define G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#define G_GNUC_END_IGNORE_DEPRECATIONS \ - _Pragma("clang diagnostic pop") + #define G_GNUC_END_IGNORE_DEPRECATIONS _Pragma("clang diagnostic pop") #endif /*****************************************************************************/ static inline void -__g_type_ensure (GType type) +__g_type_ensure(GType type) { -#if !GLIB_CHECK_VERSION(2,34,0) - if (G_UNLIKELY (type == (GType)-1)) - g_error ("can't happen"); +#if !GLIB_CHECK_VERSION(2, 34, 0) + if (G_UNLIKELY(type == (GType) -1)) + g_error("can't happen"); #else - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - g_type_ensure (type); - G_GNUC_END_IGNORE_DEPRECATIONS; + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + g_type_ensure(type); + G_GNUC_END_IGNORE_DEPRECATIONS; #endif } #define g_type_ensure __g_type_ensure /*****************************************************************************/ -#if !GLIB_CHECK_VERSION(2,34,0) - -#define g_clear_pointer(pp, destroy) \ - G_STMT_START { \ - G_STATIC_ASSERT (sizeof *(pp) == sizeof (gpointer)); \ - /* Only one access, please */ \ - gpointer *_pp = (gpointer *) (pp); \ - gpointer _p; \ - /* This assignment is needed to avoid a gcc warning */ \ - GDestroyNotify _destroy = (GDestroyNotify) (destroy); \ - \ - _p = *_pp; \ - if (_p) \ - { \ - *_pp = NULL; \ - _destroy (_p); \ - } \ - } G_STMT_END +#if !GLIB_CHECK_VERSION(2, 34, 0) + + #define g_clear_pointer(pp, destroy) \ + G_STMT_START \ + { \ + G_STATIC_ASSERT(sizeof *(pp) == sizeof(gpointer)); \ + /* Only one access, please */ \ + gpointer *_pp = (gpointer *) (pp); \ + gpointer _p; \ + /* This assignment is needed to avoid a gcc warning */ \ + GDestroyNotify _destroy = (GDestroyNotify)(destroy); \ + \ + _p = *_pp; \ + if (_p) { \ + *_pp = NULL; \ + _destroy(_p); \ + } \ + } \ + G_STMT_END #endif /*****************************************************************************/ -#if !GLIB_CHECK_VERSION(2,34,0) +#if !GLIB_CHECK_VERSION(2, 34, 0) -/* These are used to clean up the output of test programs; we can just let + /* These are used to clean up the output of test programs; we can just let * them no-op in older glib. */ -#define g_test_expect_message(log_domain, log_level, pattern) -#define g_test_assert_expected_messages() + #define g_test_expect_message(log_domain, log_level, pattern) + #define g_test_assert_expected_messages() #else -/* We build with -DGLIB_MAX_ALLOWED_VERSION set to 2.32 to make sure we don't + /* We build with -DGLIB_MAX_ALLOWED_VERSION set to 2.32 to make sure we don't * accidentally use new API that we shouldn't. But we don't want warnings for * the APIs that we emulate above. */ -#define g_test_expect_message(domain, level, format...) \ - G_STMT_START { \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - g_test_expect_message (domain, level, format); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - } G_STMT_END - -#define g_test_assert_expected_messages_internal(domain, file, line, func) \ - G_STMT_START { \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - g_test_assert_expected_messages_internal (domain, file, line, func); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - } G_STMT_END + #define g_test_expect_message(domain, level, format...) \ + G_STMT_START \ + { \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_test_expect_message(domain, level, format); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + } \ + G_STMT_END + + #define g_test_assert_expected_messages_internal(domain, file, line, func) \ + G_STMT_START \ + { \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_test_assert_expected_messages_internal(domain, file, line, func); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + } \ + G_STMT_END #endif /*****************************************************************************/ -#if GLIB_CHECK_VERSION (2, 35, 0) -/* For glib >= 2.36, g_type_init() is deprecated. +#if GLIB_CHECK_VERSION(2, 35, 0) + /* For glib >= 2.36, g_type_init() is deprecated. * But since 2.35.1 (7c42ab23b55c43ab96d0ac2124b550bf1f49c1ec) this function * does nothing. Replace the call with empty statement. */ -#define nm_g_type_init() G_STMT_START { (void) 0; } G_STMT_END + #define nm_g_type_init() \ + G_STMT_START \ + { \ + (void) 0; \ + } \ + G_STMT_END #else -#define nm_g_type_init() G_STMT_START { g_type_init (); } G_STMT_END + #define nm_g_type_init() \ + G_STMT_START \ + { \ + g_type_init(); \ + } \ + G_STMT_END #endif /*****************************************************************************/ /* g_test_initialized() is only available since glib 2.36. */ -#if !GLIB_CHECK_VERSION (2, 36, 0) -#define g_test_initialized() (g_test_config_vars->test_initialized) +#if !GLIB_CHECK_VERSION(2, 36, 0) + #define g_test_initialized() (g_test_config_vars->test_initialized) #endif /*****************************************************************************/ /* g_assert_cmpmem() is only available since glib 2.46. */ -#if !GLIB_CHECK_VERSION (2, 45, 7) -#define g_assert_cmpmem(m1, l1, m2, l2) G_STMT_START {\ - gconstpointer __m1 = m1, __m2 = m2; \ - int __l1 = l1, __l2 = l2; \ - if (__l1 != __l2) \ - g_assertion_message_cmpnum (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ - #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", __l1, "==", __l2, 'i'); \ - else if (memcmp (__m1, __m2, __l1) != 0) \ - g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ - "assertion failed (" #m1 " == " #m2 ")"); \ - } G_STMT_END +#if !GLIB_CHECK_VERSION(2, 45, 7) + #define g_assert_cmpmem(m1, l1, m2, l2) \ + G_STMT_START \ + { \ + gconstpointer __m1 = m1, __m2 = m2; \ + int __l1 = l1, __l2 = l2; \ + if (__l1 != __l2) \ + g_assertion_message_cmpnum(G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", \ + __l1, \ + "==", \ + __l2, \ + 'i'); \ + else if (memcmp(__m1, __m2, __l1) != 0) \ + g_assertion_message(G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "assertion failed (" #m1 " == " #m2 ")"); \ + } \ + G_STMT_END #endif /*****************************************************************************/ @@ -139,29 +166,27 @@ __g_type_ensure (GType type) /* Rumtime check for glib version. First do a compile time check which * (if satisfied) shortcuts the runtime check. */ static inline gboolean -nm_glib_check_version (guint major, guint minor, guint micro) +nm_glib_check_version(guint major, guint minor, guint micro) { - return GLIB_CHECK_VERSION (major, minor, micro) - || ( ( glib_major_version > major) - || ( glib_major_version == major - && glib_minor_version > minor) - || ( glib_major_version == major - && glib_minor_version == minor - && glib_micro_version < micro)); + return GLIB_CHECK_VERSION(major, minor, micro) + || ((glib_major_version > major) + || (glib_major_version == major && glib_minor_version > minor) + || (glib_major_version == major && glib_minor_version == minor + && glib_micro_version < micro)); } /*****************************************************************************/ /* g_test_skip() is only available since glib 2.38. Add a compatibility wrapper. */ static inline void -__nmtst_g_test_skip (const char *msg) +__nmtst_g_test_skip(const char *msg) { -#if GLIB_CHECK_VERSION (2, 38, 0) - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - g_test_skip (msg); - G_GNUC_END_IGNORE_DEPRECATIONS +#if GLIB_CHECK_VERSION(2, 38, 0) + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + g_test_skip(msg); + G_GNUC_END_IGNORE_DEPRECATIONS #else - g_debug ("%s", msg); + g_debug("%s", msg); #endif } #define g_test_skip __nmtst_g_test_skip @@ -170,23 +195,26 @@ __nmtst_g_test_skip (const char *msg) /* g_test_add_data_func_full() is only available since glib 2.34. Add a compatibility wrapper. */ static inline void -__g_test_add_data_func_full (const char *testpath, - gpointer test_data, - GTestDataFunc test_func, - GDestroyNotify data_free_func) +__g_test_add_data_func_full(const char * testpath, + gpointer test_data, + GTestDataFunc test_func, + GDestroyNotify data_free_func) { -#if GLIB_CHECK_VERSION (2, 34, 0) - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - g_test_add_data_func_full (testpath, test_data, test_func, data_free_func); - G_GNUC_END_IGNORE_DEPRECATIONS +#if GLIB_CHECK_VERSION(2, 34, 0) + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + g_test_add_data_func_full(testpath, test_data, test_func, data_free_func); + G_GNUC_END_IGNORE_DEPRECATIONS #else - g_return_if_fail (testpath != NULL); - g_return_if_fail (testpath[0] == '/'); - g_return_if_fail (test_func != NULL); - - g_test_add_vtable (testpath, 0, test_data, NULL, - (GTestFixtureFunc) test_func, - (GTestFixtureFunc) data_free_func); + g_return_if_fail(testpath != NULL); + g_return_if_fail(testpath[0] == '/'); + g_return_if_fail(test_func != NULL); + + g_test_add_vtable(testpath, + 0, + test_data, + NULL, + (GTestFixtureFunc) test_func, + (GTestFixtureFunc) data_free_func); #endif } #define g_test_add_data_func_full __g_test_add_data_func_full @@ -194,240 +222,235 @@ __g_test_add_data_func_full (const char *testpath, /*****************************************************************************/ static inline gboolean -nm_g_hash_table_replace (GHashTable *hash, gpointer key, gpointer value) +nm_g_hash_table_replace(GHashTable *hash, gpointer key, gpointer value) { - /* glib 2.40 added a return value indicating whether the key already existed - * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */ + /* glib 2.40 added a return value indicating whether the key already existed + * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */ #if GLIB_CHECK_VERSION(2, 40, 0) - return g_hash_table_replace (hash, key, value); + return g_hash_table_replace(hash, key, value); #else - gboolean contained = g_hash_table_contains (hash, key); + gboolean contained = g_hash_table_contains(hash, key); - g_hash_table_replace (hash, key, value); - return !contained; + g_hash_table_replace(hash, key, value); + return !contained; #endif } static inline gboolean -nm_g_hash_table_insert (GHashTable *hash, gpointer key, gpointer value) +nm_g_hash_table_insert(GHashTable *hash, gpointer key, gpointer value) { - /* glib 2.40 added a return value indicating whether the key already existed - * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */ + /* glib 2.40 added a return value indicating whether the key already existed + * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */ #if GLIB_CHECK_VERSION(2, 40, 0) - return g_hash_table_insert (hash, key, value); + return g_hash_table_insert(hash, key, value); #else - gboolean contained = g_hash_table_contains (hash, key); + gboolean contained = g_hash_table_contains(hash, key); - g_hash_table_insert (hash, key, value); - return !contained; + g_hash_table_insert(hash, key, value); + return !contained; #endif } static inline gboolean -nm_g_hash_table_add (GHashTable *hash, gpointer key) +nm_g_hash_table_add(GHashTable *hash, gpointer key) { - /* glib 2.40 added a return value indicating whether the key already existed - * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */ + /* glib 2.40 added a return value indicating whether the key already existed + * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */ #if GLIB_CHECK_VERSION(2, 40, 0) - return g_hash_table_add (hash, key); + return g_hash_table_add(hash, key); #else - gboolean contained = g_hash_table_contains (hash, key); + gboolean contained = g_hash_table_contains(hash, key); - g_hash_table_add (hash, key); - return !contained; + g_hash_table_add(hash, key); + return !contained; #endif } /*****************************************************************************/ -#if !GLIB_CHECK_VERSION(2, 40, 0) || defined (NM_GLIB_COMPAT_H_TEST) +#if !GLIB_CHECK_VERSION(2, 40, 0) || defined(NM_GLIB_COMPAT_H_TEST) static inline void -_nm_g_ptr_array_insert (GPtrArray *array, - int index_, - gpointer data) +_nm_g_ptr_array_insert(GPtrArray *array, int index_, gpointer data) { - g_return_if_fail (array); - g_return_if_fail (index_ >= -1); - g_return_if_fail (index_ <= (int) array->len); - - g_ptr_array_add (array, data); - - if (index_ != -1 && index_ != (int) (array->len - 1)) { - memmove (&(array->pdata[index_ + 1]), - &(array->pdata[index_]), - (array->len - index_ - 1) * sizeof (gpointer)); - array->pdata[index_] = data; - } + g_return_if_fail(array); + g_return_if_fail(index_ >= -1); + g_return_if_fail(index_ <= (int) array->len); + + g_ptr_array_add(array, data); + + if (index_ != -1 && index_ != (int) (array->len - 1)) { + memmove(&(array->pdata[index_ + 1]), + &(array->pdata[index_]), + (array->len - index_ - 1) * sizeof(gpointer)); + array->pdata[index_] = data; + } } #endif #if !GLIB_CHECK_VERSION(2, 40, 0) -#define g_ptr_array_insert(array, index, data) G_STMT_START { _nm_g_ptr_array_insert (array, index, data); } G_STMT_END + #define g_ptr_array_insert(array, index, data) \ + G_STMT_START \ + { \ + _nm_g_ptr_array_insert(array, index, data); \ + } \ + G_STMT_END #else -#define g_ptr_array_insert(array, index, data) \ - G_STMT_START { \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - g_ptr_array_insert (array, index, data); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - } G_STMT_END + #define g_ptr_array_insert(array, index, data) \ + G_STMT_START \ + { \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_ptr_array_insert(array, index, data); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + } \ + G_STMT_END #endif /*****************************************************************************/ -#if !GLIB_CHECK_VERSION (2, 40, 0) +#if !GLIB_CHECK_VERSION(2, 40, 0) static inline gboolean -_g_key_file_save_to_file (GKeyFile *key_file, - const char *filename, - GError **error) +_g_key_file_save_to_file(GKeyFile *key_file, const char *filename, GError **error) { - char *contents; - gboolean success; - gsize length; + char * contents; + gboolean success; + gsize length; - g_return_val_if_fail (key_file != NULL, FALSE); - g_return_val_if_fail (filename != NULL, FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail(key_file != NULL, FALSE); + g_return_val_if_fail(filename != NULL, FALSE); + g_return_val_if_fail(error == NULL || *error == NULL, FALSE); - contents = g_key_file_to_data (key_file, &length, NULL); - g_assert (contents != NULL); + contents = g_key_file_to_data(key_file, &length, NULL); + g_assert(contents != NULL); - success = g_file_set_contents (filename, contents, length, error); - g_free (contents); + success = g_file_set_contents(filename, contents, length, error); + g_free(contents); - return success; + return success; } -#define g_key_file_save_to_file(key_file, filename, error) \ - _g_key_file_save_to_file (key_file, filename, error) + #define g_key_file_save_to_file(key_file, filename, error) \ + _g_key_file_save_to_file(key_file, filename, error) #else -#define g_key_file_save_to_file(key_file, filename, error) \ - ({ \ - gboolean _success; \ - \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - _success = g_key_file_save_to_file (key_file, filename, error); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - _success; \ - }) + #define g_key_file_save_to_file(key_file, filename, error) \ + ({ \ + gboolean _success; \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + _success = g_key_file_save_to_file(key_file, filename, error); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + _success; \ + }) #endif /*****************************************************************************/ -#if GLIB_CHECK_VERSION (2, 36, 0) -#define g_credentials_get_unix_pid(creds, error) \ - ({ \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - (g_credentials_get_unix_pid) ((creds), (error)); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - }) +#if GLIB_CHECK_VERSION(2, 36, 0) + #define g_credentials_get_unix_pid(creds, error) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_credentials_get_unix_pid)((creds), (error)); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) #else -#define g_credentials_get_unix_pid(creds, error) \ - ({ \ - struct ucred *native_creds; \ - \ - native_creds = g_credentials_get_native ((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \ - g_assert (native_creds); \ - native_creds->pid; \ - }) + #define g_credentials_get_unix_pid(creds, error) \ + ({ \ + struct ucred *native_creds; \ + \ + native_creds = g_credentials_get_native((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \ + g_assert(native_creds); \ + native_creds->pid; \ + }) #endif /*****************************************************************************/ -#if !GLIB_CHECK_VERSION(2, 40, 0) || defined (NM_GLIB_COMPAT_H_TEST) +#if !GLIB_CHECK_VERSION(2, 40, 0) || defined(NM_GLIB_COMPAT_H_TEST) static inline gpointer * -_nm_g_hash_table_get_keys_as_array (GHashTable *hash_table, - guint *length) +_nm_g_hash_table_get_keys_as_array(GHashTable *hash_table, guint *length) { - GHashTableIter iter; - gpointer key, *ret; - guint i = 0; + GHashTableIter iter; + gpointer key, *ret; + guint i = 0; - g_return_val_if_fail (hash_table, NULL); + g_return_val_if_fail(hash_table, NULL); - ret = g_new0 (gpointer, g_hash_table_size (hash_table) + 1); - g_hash_table_iter_init (&iter, hash_table); + ret = g_new0(gpointer, g_hash_table_size(hash_table) + 1); + g_hash_table_iter_init(&iter, hash_table); - while (g_hash_table_iter_next (&iter, &key, NULL)) - ret[i++] = key; + while (g_hash_table_iter_next(&iter, &key, NULL)) + ret[i++] = key; - ret[i] = NULL; + ret[i] = NULL; - if (length) - *length = i; + if (length) + *length = i; - return ret; + return ret; } #endif #if !GLIB_CHECK_VERSION(2, 40, 0) -#define g_hash_table_get_keys_as_array(hash_table, length) \ - ({ \ - _nm_g_hash_table_get_keys_as_array (hash_table, length); \ - }) + #define g_hash_table_get_keys_as_array(hash_table, length) \ + ({ _nm_g_hash_table_get_keys_as_array(hash_table, length); }) #else -#define g_hash_table_get_keys_as_array(hash_table, length) \ - ({ \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - (g_hash_table_get_keys_as_array) ((hash_table), (length)); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - }) + #define g_hash_table_get_keys_as_array(hash_table, length) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_hash_table_get_keys_as_array) \ + ((hash_table), (length)); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) #endif /*****************************************************************************/ #ifndef g_info -/* g_info was only added with 2.39.2 */ -#define g_info(...) g_log (G_LOG_DOMAIN, \ - G_LOG_LEVEL_INFO, \ - __VA_ARGS__) + /* g_info was only added with 2.39.2 */ + #define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__) #endif /*****************************************************************************/ static inline gpointer -_nm_g_steal_pointer (gpointer pp) +_nm_g_steal_pointer(gpointer pp) { - gpointer *ptr = (gpointer *) pp; - gpointer ref; + gpointer *ptr = (gpointer *) pp; + gpointer ref; - ref = *ptr; - *ptr = NULL; + ref = *ptr; + *ptr = NULL; - return ref; + return ref; } #if !GLIB_CHECK_VERSION(2, 44, 0) static inline gpointer -g_steal_pointer (gpointer pp) +g_steal_pointer(gpointer pp) { - return _nm_g_steal_pointer (pp); + return _nm_g_steal_pointer(pp); } #endif #ifdef g_steal_pointer -#undef g_steal_pointer + #undef g_steal_pointer #endif -#define g_steal_pointer(pp) \ - ((typeof (*(pp))) _nm_g_steal_pointer (pp)) +#define g_steal_pointer(pp) ((typeof(*(pp))) _nm_g_steal_pointer(pp)) /*****************************************************************************/ static inline gboolean -_nm_g_strv_contains (const char * const *strv, - const char *str) +_nm_g_strv_contains(const char *const *strv, const char *str) { #if !GLIB_CHECK_VERSION(2, 44, 0) - g_return_val_if_fail (strv != NULL, FALSE); - g_return_val_if_fail (str != NULL, FALSE); + g_return_val_if_fail(strv != NULL, FALSE); + g_return_val_if_fail(str != NULL, FALSE); - for (; *strv != NULL; strv++) { - if (g_str_equal (str, *strv)) - return TRUE; - } + for (; *strv != NULL; strv++) { + if (g_str_equal(str, *strv)) + return TRUE; + } - return FALSE; + return FALSE; #else - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - return g_strv_contains (strv, str); - G_GNUC_END_IGNORE_DEPRECATIONS + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + return g_strv_contains(strv, str); + G_GNUC_END_IGNORE_DEPRECATIONS #endif } #define g_strv_contains _nm_g_strv_contains @@ -435,33 +458,33 @@ _nm_g_strv_contains (const char * const *strv, /*****************************************************************************/ static inline GVariant * -_nm_g_variant_new_take_string (char *string) +_nm_g_variant_new_take_string(char *string) { #if !GLIB_CHECK_VERSION(2, 36, 0) - GVariant *value; + GVariant *value; - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (g_utf8_validate (string, -1, NULL), NULL); + g_return_val_if_fail(string != NULL, NULL); + g_return_val_if_fail(g_utf8_validate(string, -1, NULL), NULL); - value = g_variant_new_string (string); - g_free (string); - return value; + value = g_variant_new_string(string); + g_free(string); + return value; #elif !GLIB_CHECK_VERSION(2, 38, 0) - GVariant *value; - GBytes *bytes; + GVariant *value; + GBytes * bytes; - g_return_val_if_fail (string != NULL, NULL); - g_return_val_if_fail (g_utf8_validate (string, -1, NULL), NULL); + g_return_val_if_fail(string != NULL, NULL); + g_return_val_if_fail(g_utf8_validate(string, -1, NULL), NULL); - bytes = g_bytes_new_take (string, strlen (string) + 1); - value = g_variant_new_from_bytes (G_VARIANT_TYPE_STRING, bytes, TRUE); - g_bytes_unref (bytes); + bytes = g_bytes_new_take(string, strlen(string) + 1); + value = g_variant_new_from_bytes(G_VARIANT_TYPE_STRING, bytes, TRUE); + g_bytes_unref(bytes); - return value; + return value; #else - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - return g_variant_new_take_string (string); - G_GNUC_END_IGNORE_DEPRECATIONS + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + return g_variant_new_take_string(string); + G_GNUC_END_IGNORE_DEPRECATIONS #endif } #define g_variant_new_take_string _nm_g_variant_new_take_string @@ -469,32 +492,30 @@ _nm_g_variant_new_take_string (char *string) /*****************************************************************************/ #if !GLIB_CHECK_VERSION(2, 38, 0) -_nm_printf (1, 2) -static inline GVariant * -_nm_g_variant_new_printf (const char *format_string, ...) +_nm_printf(1, 2) static inline GVariant *_nm_g_variant_new_printf(const char *format_string, ...) { - char *string; - va_list ap; + char * string; + va_list ap; - g_return_val_if_fail (format_string, NULL); + g_return_val_if_fail(format_string, NULL); - va_start (ap, format_string); - string = g_strdup_vprintf (format_string, ap); - va_end (ap); + va_start(ap, format_string); + string = g_strdup_vprintf(format_string, ap); + va_end(ap); - return g_variant_new_take_string (string); + return g_variant_new_take_string(string); } -#define g_variant_new_printf(...) _nm_g_variant_new_printf(__VA_ARGS__) + #define g_variant_new_printf(...) _nm_g_variant_new_printf(__VA_ARGS__) #else -#define g_variant_new_printf(...) \ - ({ \ - GVariant *_v; \ - \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - _v = g_variant_new_printf (__VA_ARGS__); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - _v; \ - }) + #define g_variant_new_printf(...) \ + ({ \ + GVariant *_v; \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + _v = g_variant_new_printf(__VA_ARGS__); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + _v; \ + }) #endif /*****************************************************************************/ @@ -509,22 +530,22 @@ _nm_g_variant_new_printf (const char *format_string, ...) * Override this. */ #undef g_object_ref #undef g_object_ref_sink -#define g_object_ref(Obj) ((typeof(Obj)) g_object_ref (Obj)) -#define g_object_ref_sink(Obj) ((typeof(Obj)) g_object_ref_sink (Obj)) +#define g_object_ref(Obj) ((typeof(Obj)) g_object_ref(Obj)) +#define g_object_ref_sink(Obj) ((typeof(Obj)) g_object_ref_sink(Obj)) /*****************************************************************************/ #ifndef g_autofree -/* we still don't rely on recent glib to provide g_autofree. Hence, we continue + /* we still don't rely on recent glib to provide g_autofree. Hence, we continue * to use our gs_* free macros that we took from libgsystem. * * To ease migration towards g_auto*, add a compat define for g_autofree. */ -#define g_autofree gs_free + #define g_autofree gs_free #endif /*****************************************************************************/ -#if !GLIB_CHECK_VERSION (2, 47, 1) +#if !GLIB_CHECK_VERSION(2, 47, 1) /* Older versions of g_value_unset() only allowed to unset a GValue which * was initialized previously. This was relaxed ([1], [2], [3]). * @@ -536,14 +557,14 @@ _nm_g_variant_new_printf (const char *format_string, ...) * [3] https://bugzilla.gnome.org/show_bug.cgi?id=755766 */ static inline void -_nm_g_value_unset (GValue *value) +_nm_g_value_unset(GValue *value) { - g_return_if_fail (value); + g_return_if_fail(value); - if (value->g_type != 0) - g_value_unset (value); + if (value->g_type != 0) + g_value_unset(value); } -#define g_value_unset _nm_g_value_unset + #define g_value_unset _nm_g_value_unset #endif /* G_PID_FORMAT was added only in 2.53.5. Define it ourself. @@ -561,7 +582,7 @@ _nm_g_value_unset (GValue *value) /* G_SOURCE_FUNC was added in 2.57.2. */ #undef G_SOURCE_FUNC -#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f)) +#define G_SOURCE_FUNC(f) ((GSourceFunc)(void (*)(void))(f)) /*****************************************************************************/ @@ -573,67 +594,70 @@ _nm_g_value_unset (GValue *value) * pointers there. Reimplement the macro to get that right, but with stronger * type checks (as we use typeof()). Had one job. */ static inline gboolean -_g_atomic_pointer_compare_and_exchange (volatile void *atomic, - gconstpointer oldval, - gconstpointer newval) +_g_atomic_pointer_compare_and_exchange(volatile void *atomic, + gconstpointer oldval, + gconstpointer newval) { - return g_atomic_pointer_compare_and_exchange ((void **) atomic, (void *) oldval, (void *) newval); + return g_atomic_pointer_compare_and_exchange((void **) atomic, + (void *) oldval, + (void *) newval); } #undef g_atomic_pointer_compare_and_exchange -#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \ - ({ \ - typeof (atomic) const _atomic = (atomic); \ - typeof (*_atomic) const _oldval = (oldval); \ - typeof (*_atomic) const _newval = (newval); \ - \ - _g_atomic_pointer_compare_and_exchange (_atomic, _oldval, _newval); \ - }) +#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \ + ({ \ + typeof(atomic) const _atomic = (atomic); \ + typeof(*_atomic) const _oldval = (oldval); \ + typeof(*_atomic) const _newval = (newval); \ + \ + _g_atomic_pointer_compare_and_exchange(_atomic, _oldval, _newval); \ + }) /*****************************************************************************/ -#if !GLIB_CHECK_VERSION (2, 58, 0) +#if !GLIB_CHECK_VERSION(2, 58, 0) static inline gboolean -g_hash_table_steal_extended (GHashTable *hash_table, - gconstpointer lookup_key, - gpointer *stolen_key, - gpointer *stolen_value) +g_hash_table_steal_extended(GHashTable * hash_table, + gconstpointer lookup_key, + gpointer * stolen_key, + gpointer * stolen_value) { - g_assert (stolen_key); - g_assert (stolen_value); - - if (g_hash_table_lookup_extended (hash_table, lookup_key, stolen_key, stolen_value)) { - g_hash_table_steal (hash_table, lookup_key); - return TRUE; - } - *stolen_key = NULL; - *stolen_value = NULL; - return FALSE; + g_assert(stolen_key); + g_assert(stolen_value); + + if (g_hash_table_lookup_extended(hash_table, lookup_key, stolen_key, stolen_value)) { + g_hash_table_steal(hash_table, lookup_key); + return TRUE; + } + *stolen_key = NULL; + *stolen_value = NULL; + return FALSE; } #else -#define g_hash_table_steal_extended(hash_table, lookup_key, stolen_key, stolen_value) \ - ({ \ - gpointer *_stolen_key = (stolen_key); \ - gpointer *_stolen_value = (stolen_value); \ - \ - /* we cannot allow NULL arguments, because then we would leak the values in - * the compat implementation. */ \ - g_assert (_stolen_key); \ - g_assert (_stolen_value); \ - \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - g_hash_table_steal_extended (hash_table, lookup_key, _stolen_key, _stolen_value); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - }) + #define g_hash_table_steal_extended(hash_table, lookup_key, stolen_key, stolen_value) \ + ({ \ + gpointer *_stolen_key = (stolen_key); \ + gpointer *_stolen_value = (stolen_value); \ + \ + /* we cannot allow NULL arguments, because then we would leak the values in + * the compat implementation. */ \ + g_assert(_stolen_key); \ + g_assert(_stolen_value); \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_hash_table_steal_extended(hash_table, lookup_key, _stolen_key, _stolen_value); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) #endif /*****************************************************************************/ -__attribute__((__deprecated__("Don't use g_cancellable_reset(). Create a new cancellable instead."))) -void _nm_g_cancellable_reset (GCancellable *cancellable); +__attribute__(( + __deprecated__("Don't use g_cancellable_reset(). Create a new cancellable instead."))) void +_nm_g_cancellable_reset(GCancellable *cancellable); #undef g_cancellable_reset #define g_cancellable_reset(cancellable) _nm_g_cancellable_reset(cancellable) /*****************************************************************************/ -#endif /* __NM_GLIB_H__ */ +#endif /* __NM_GLIB_H__ */ diff --git a/shared/nm-glib-aux/nm-hash-utils.c b/shared/nm-glib-aux/nm-hash-utils.c index 232c62c0..8a1c87fd 100644 --- a/shared/nm-glib-aux/nm-hash-utils.c +++ b/shared/nm-glib-aux/nm-hash-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -14,283 +14,273 @@ /*****************************************************************************/ -#define HASH_KEY_SIZE 16u -#define HASH_KEY_SIZE_GUINT ((HASH_KEY_SIZE + sizeof (guint) - 1) / sizeof (guint)) +#define HASH_KEY_SIZE 16u +#define HASH_KEY_SIZE_GUINT ((HASH_KEY_SIZE + sizeof(guint) - 1) / sizeof(guint)) -G_STATIC_ASSERT (sizeof (guint) * HASH_KEY_SIZE_GUINT >= HASH_KEY_SIZE); +G_STATIC_ASSERT(sizeof(guint) * HASH_KEY_SIZE_GUINT >= HASH_KEY_SIZE); static const guint8 *volatile global_seed = NULL; static const guint8 * -_get_hash_key_init (void) +_get_hash_key_init(void) { - /* the returned hash is aligned to guin64, hence, it is safe - * to use it as guint* or guint64* pointer. */ - static union { - guint8 v8[HASH_KEY_SIZE]; - guint _align_as_uint; - guint32 _align_as_uint32; - guint64 _align_as_uint64; - } g_arr; - const guint8 *g; + /* the returned hash is aligned to guin64, hence, it is safe + * to use it as guint* or guint64* pointer. */ + static union { + guint8 v8[HASH_KEY_SIZE]; + guint _align_as_uint; + guint32 _align_as_uint32; + guint64 _align_as_uint64; + } g_arr; + const guint8 *g; again: - g = g_atomic_pointer_get (&global_seed); - if (!G_UNLIKELY (g)) { - static gsize g_lock; - uint64_t h; - union { - guint vuint; - guint8 v8[HASH_KEY_SIZE]; - guint8 _extra_entropy[3 * HASH_KEY_SIZE]; - } t_arr; - - nm_utils_random_bytes (&t_arr, sizeof (t_arr)); - - /* We only initialize one random hash key. So we can spend some effort - * of getting this right. For one, we collect more random bytes than - * necessary. - * - * Then, the first guint of the seed should have all the entropy that we could - * obtain in sizeof(t_arr). For that, siphash(t_arr) and xor the first guint - * with hash. - * The first guint is especially interesting for nm_hash_static() below that - * doesn't use siphash itself. */ - h = c_siphash_hash (t_arr.v8, - (const guint8 *) &t_arr, - sizeof (t_arr)); - if (sizeof (h) > sizeof (guint)) - t_arr.vuint = t_arr.vuint ^ ((guint) (h & G_MAXUINT)) ^ ((guint) (h >> 32)); - else - t_arr.vuint = t_arr.vuint ^ ((guint) (h & G_MAXUINT)); - - if (!g_once_init_enter (&g_lock)) { - /* lost a race. The random key is already initialized. */ - goto again; - } - - memcpy (g_arr.v8, t_arr.v8, HASH_KEY_SIZE); - g = g_arr.v8; - g_atomic_pointer_set (&global_seed, g); - g_once_init_leave (&g_lock, 1); - } - - nm_assert (g == g_arr.v8); - return g; + g = g_atomic_pointer_get(&global_seed); + if (!G_UNLIKELY(g)) { + static gsize g_lock; + uint64_t h; + union { + guint vuint; + guint8 v8[HASH_KEY_SIZE]; + guint8 _extra_entropy[3 * HASH_KEY_SIZE]; + } t_arr; + + nm_utils_random_bytes(&t_arr, sizeof(t_arr)); + + /* We only initialize one random hash key. So we can spend some effort + * of getting this right. For one, we collect more random bytes than + * necessary. + * + * Then, the first guint of the seed should have all the entropy that we could + * obtain in sizeof(t_arr). For that, siphash(t_arr) and xor the first guint + * with hash. + * The first guint is especially interesting for nm_hash_static() below that + * doesn't use siphash itself. */ + h = c_siphash_hash(t_arr.v8, (const guint8 *) &t_arr, sizeof(t_arr)); + if (sizeof(h) > sizeof(guint)) + t_arr.vuint = t_arr.vuint ^ ((guint)(h & G_MAXUINT)) ^ ((guint)(h >> 32)); + else + t_arr.vuint = t_arr.vuint ^ ((guint)(h & G_MAXUINT)); + + if (!g_once_init_enter(&g_lock)) { + /* lost a race. The random key is already initialized. */ + goto again; + } + + memcpy(g_arr.v8, t_arr.v8, HASH_KEY_SIZE); + g = g_arr.v8; + g_atomic_pointer_set(&global_seed, g); + g_once_init_leave(&g_lock, 1); + } + + nm_assert(g == g_arr.v8); + return g; } -#define _get_hash_key() \ - ({ \ - const guint8 *_g; \ - \ - _g = g_atomic_pointer_get (&global_seed); \ - if (G_UNLIKELY (!_g)) \ - _g = _get_hash_key_init (); \ - _g; \ - }) +#define _get_hash_key() \ + ({ \ + const guint8 *_g; \ + \ + _g = g_atomic_pointer_get(&global_seed); \ + if (G_UNLIKELY(!_g)) \ + _g = _get_hash_key_init(); \ + _g; \ + }) guint -nm_hash_static (guint static_seed) +nm_hash_static(guint static_seed) { - /* Note that we only xor the static_seed with the first guint of the key. - * - * We don't use siphash, which would mix the bits better with _get_hash_key(). - * Note that nm_hash_static() isn't used to hash the static_seed. Instead, it - * is used to get a unique hash value in a static context. That means, every - * caller is responsible to choose a static_seed that is sufficiently - * distinct from all other callers. In other words, static_seed should be a - * unique constant with good entropy. - * - * Note that _get_hash_key_init() already xored the first guint of the - * key with the siphash of the entire static key. That means, even if - * we got bad randomness for the first guint, the first guint is also - * mixed with the randomness of the entire random key. - * - * Also, ensure that we don't return zero (like for nm_hash_complete()). - */ - return ((*((const guint *) _get_hash_key ())) ^ static_seed) - ?: 3679500967u; + /* Note that we only xor the static_seed with the first guint of the key. + * + * We don't use siphash, which would mix the bits better with _get_hash_key(). + * Note that nm_hash_static() isn't used to hash the static_seed. Instead, it + * is used to get a unique hash value in a static context. That means, every + * caller is responsible to choose a static_seed that is sufficiently + * distinct from all other callers. In other words, static_seed should be a + * unique constant with good entropy. + * + * Note that _get_hash_key_init() already xored the first guint of the + * key with the siphash of the entire static key. That means, even if + * we got bad randomness for the first guint, the first guint is also + * mixed with the randomness of the entire random key. + * + * Also, ensure that we don't return zero (like for nm_hash_complete()). + */ + return ((*((const guint *) _get_hash_key())) ^ static_seed) ?: 3679500967u; } void -nm_hash_siphash42_init (CSipHash *h, guint static_seed) +nm_hash_siphash42_init(CSipHash *h, guint static_seed) { - const guint8 *g; - union { - guint64 _align_as_uint64; - guint arr[HASH_KEY_SIZE_GUINT]; - } seed; - - nm_assert (h); - - g = _get_hash_key (); - memcpy (&seed, g, HASH_KEY_SIZE); - seed.arr[0] ^= static_seed; - c_siphash_init (h, (const guint8 *) &seed); + const guint8 *g; + union { + guint64 _align_as_uint64; + guint arr[HASH_KEY_SIZE_GUINT]; + } seed; + + nm_assert(h); + + g = _get_hash_key(); + memcpy(&seed, g, HASH_KEY_SIZE); + seed.arr[0] ^= static_seed; + c_siphash_init(h, (const guint8 *) &seed); } guint -nm_hash_str (const char *str) +nm_hash_str(const char *str) { - NMHashState h; + NMHashState h; - if (!str) - return nm_hash_static (1867854211u); - nm_hash_init (&h, 1867854211u); - nm_hash_update_str (&h, str); - return nm_hash_complete (&h); + if (!str) + return nm_hash_static(1867854211u); + nm_hash_init(&h, 1867854211u); + nm_hash_update_str(&h, str); + return nm_hash_complete(&h); } guint -nm_str_hash (gconstpointer str) +nm_str_hash(gconstpointer str) { - return nm_hash_str (str); + return nm_hash_str(str); } guint -nm_hash_ptr (gconstpointer ptr) +nm_hash_ptr(gconstpointer ptr) { - NMHashState h; + NMHashState h; - if (!ptr) - return nm_hash_static (2907677551u); - nm_hash_init (&h, 2907677551u); - nm_hash_update (&h, &ptr, sizeof (ptr)); - return nm_hash_complete (&h); + if (!ptr) + return nm_hash_static(2907677551u); + nm_hash_init(&h, 2907677551u); + nm_hash_update(&h, &ptr, sizeof(ptr)); + return nm_hash_complete(&h); } guint -nm_direct_hash (gconstpointer ptr) +nm_direct_hash(gconstpointer ptr) { - return nm_hash_ptr (ptr); + return nm_hash_ptr(ptr); } /*****************************************************************************/ guint -nm_pstr_hash (gconstpointer p) +nm_pstr_hash(gconstpointer p) { - const char *const*s = p; + const char *const *s = p; - if (!s) - return nm_hash_static (101061439u); - return nm_hash_str (*s); + if (!s) + return nm_hash_static(101061439u); + return nm_hash_str(*s); } gboolean -nm_pstr_equal (gconstpointer a, gconstpointer b) +nm_pstr_equal(gconstpointer a, gconstpointer b) { - const char *const*s1 = a; - const char *const*s2 = b; + const char *const *s1 = a; + const char *const *s2 = b; - return (s1 == s2) - || ( s1 - && s2 - && nm_streq0 (*s1, *s2)); + return (s1 == s2) || (s1 && s2 && nm_streq0(*s1, *s2)); } guint -nm_pint_hash (gconstpointer p) +nm_pint_hash(gconstpointer p) { - const int *s = p; + const int *s = p; - if (!s) - return nm_hash_static (298377461u); - return nm_hash_val (1208815757u, *s); + if (!s) + return nm_hash_static(298377461u); + return nm_hash_val(1208815757u, *s); } gboolean -nm_pint_equals (gconstpointer a, gconstpointer b) +nm_pint_equals(gconstpointer a, gconstpointer b) { - const int *s1 = a; - const int *s2 = a; + const int *s1 = a; + const int *s2 = a; - return s1 == s2 - || (s1 && s2 && *s1 == *s2); + return s1 == s2 || (s1 && s2 && *s1 == *s2); } guint -nm_pdirect_hash (gconstpointer p) +nm_pdirect_hash(gconstpointer p) { - const void *const*s = p; + const void *const *s = p; - if (!s) - return nm_hash_static (1852748873u); - return nm_direct_hash (*s); + if (!s) + return nm_hash_static(1852748873u); + return nm_direct_hash(*s); } gboolean -nm_pdirect_equal (gconstpointer a, gconstpointer b) +nm_pdirect_equal(gconstpointer a, gconstpointer b) { - const void *const*s1 = a; - const void *const*s2 = b; + const void *const *s1 = a; + const void *const *s2 = b; - return (s1 == s2) - || ( s1 - && s2 - && *s1 == *s2); + return (s1 == s2) || (s1 && s2 && *s1 == *s2); } guint -nm_ppdirect_hash (gconstpointer p) +nm_ppdirect_hash(gconstpointer p) { - const void *const*const*s = p; + const void *const *const *s = p; - if (!s) - return nm_hash_static (396534869u); - if (!*s) - return nm_hash_static (1476102263u); - return nm_direct_hash (**s); + if (!s) + return nm_hash_static(396534869u); + if (!*s) + return nm_hash_static(1476102263u); + return nm_direct_hash(**s); } gboolean -nm_ppdirect_equal (gconstpointer a, gconstpointer b) +nm_ppdirect_equal(gconstpointer a, gconstpointer b) { - const void *const*const*s1 = a; - const void *const*const*s2 = b; + const void *const *const *s1 = a; + const void *const *const *s2 = b; - if (s1 == s2) - return TRUE; - if (!s1 || !s2) - return FALSE; + if (s1 == s2) + return TRUE; + if (!s1 || !s2) + return FALSE; - if (*s1 == *s2) - return TRUE; - if (!*s1 || !*s2) - return FALSE; + if (*s1 == *s2) + return TRUE; + if (!*s1 || !*s2) + return FALSE; - return **s1 == **s2; + return **s1 == **s2; } /*****************************************************************************/ guint -nm_gbytes_hash (gconstpointer p) +nm_gbytes_hash(gconstpointer p) { - GBytes *ptr = (GBytes *) p; - gconstpointer arr; - gsize len; + GBytes * ptr = (GBytes *) p; + gconstpointer arr; + gsize len; - arr = g_bytes_get_data (ptr, &len); - return nm_hash_mem (792701303u, arr, len); + arr = g_bytes_get_data(ptr, &len); + return nm_hash_mem(792701303u, arr, len); } guint -nm_pgbytes_hash (gconstpointer p) +nm_pgbytes_hash(gconstpointer p) { - GBytes *const*ptr = p; - gconstpointer arr; - gsize len; + GBytes *const *ptr = p; + gconstpointer arr; + gsize len; - arr = g_bytes_get_data (*ptr, &len); - return nm_hash_mem (1470631313u, arr, len); + arr = g_bytes_get_data(*ptr, &len); + return nm_hash_mem(1470631313u, arr, len); } gboolean -nm_pgbytes_equal (gconstpointer a, gconstpointer b) +nm_pgbytes_equal(gconstpointer a, gconstpointer b) { - GBytes *const*ptr_a = a; - GBytes *const*ptr_b = b; + GBytes *const *ptr_a = a; + GBytes *const *ptr_b = b; - return g_bytes_equal (*ptr_a, *ptr_b); + return g_bytes_equal(*ptr_a, *ptr_b); } diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h index be69bfa8..1cfdcaf6 100644 --- a/shared/nm-glib-aux/nm-hash-utils.h +++ b/shared/nm-glib-aux/nm-hash-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -12,9 +12,9 @@ /*****************************************************************************/ #define NM_HASH_SEED_16(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \ - ((const guint8[16]) { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af }) + ((const guint8[16]){a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af}) -void nm_hash_siphash42_init (CSipHash *h, guint static_seed); +void nm_hash_siphash42_init(CSipHash *h, guint static_seed); /* Siphash24 of binary buffer @arr and @len, using the randomized seed from * other NMHash functions. @@ -34,249 +34,309 @@ void nm_hash_siphash42_init (CSipHash *h, guint static_seed); * seed (which is cached for the current run of the program). */ static inline guint64 -nm_hash_siphash42 (guint static_seed, const void *ptr, gsize n) +nm_hash_siphash42(guint static_seed, const void *ptr, gsize n) { - CSipHash h; + CSipHash h; - nm_hash_siphash42_init (&h, static_seed); - c_siphash_append (&h, ptr, n); - return c_siphash_finalize (&h); + nm_hash_siphash42_init(&h, static_seed); + c_siphash_append(&h, ptr, n); + return c_siphash_finalize(&h); } /*****************************************************************************/ struct _NMHashState { - CSipHash _state; + CSipHash _state; }; typedef struct _NMHashState NMHashState; -guint nm_hash_static (guint static_seed); +guint nm_hash_static(guint static_seed); static inline void -nm_hash_init (NMHashState *state, guint static_seed) +nm_hash_init(NMHashState *state, guint static_seed) { - nm_assert (state); + nm_assert(state); - nm_hash_siphash42_init (&state->_state, static_seed); + nm_hash_siphash42_init(&state->_state, static_seed); } static inline guint64 -nm_hash_complete_u64 (NMHashState *state) +nm_hash_complete_u64(NMHashState *state) { - nm_assert (state); - - /* this returns the native u64 hash value. Note that this differs - * from nm_hash_complete() in two ways: - * - * - the type, guint64 vs. guint. - * - nm_hash_complete() never returns zero. - * - * In practice, nm_hash*() API is implemented via siphash24, so this returns - * the siphash24 value. But that is not guaranteed by the API, and if you need - * siphash24 directly, use c_siphash_*() and nm_hash_siphash42*() API. */ - return c_siphash_finalize (&state->_state); + nm_assert(state); + + /* this returns the native u64 hash value. Note that this differs + * from nm_hash_complete() in two ways: + * + * - the type, guint64 vs. guint. + * - nm_hash_complete() never returns zero. + * + * In practice, nm_hash*() API is implemented via siphash24, so this returns + * the siphash24 value. But that is not guaranteed by the API, and if you need + * siphash24 directly, use c_siphash_*() and nm_hash_siphash42*() API. */ + return c_siphash_finalize(&state->_state); } static inline guint -nm_hash_complete (NMHashState *state) +nm_hash_complete(NMHashState *state) { - guint64 h; + guint64 h; - h = nm_hash_complete_u64 (state); + h = nm_hash_complete_u64(state); - /* we don't ever want to return a zero hash. - * - * NMPObject requires that in _idx_obj_part(), and it's just a good idea. */ - return (((guint) (h >> 32)) ^ ((guint) h)) - ?: 1396707757u; + /* we don't ever want to return a zero hash. + * + * NMPObject requires that in _idx_obj_part(), and it's just a good idea. */ + return (((guint)(h >> 32)) ^ ((guint) h)) ?: 1396707757u; } static inline void -nm_hash_update (NMHashState *state, const void *ptr, gsize n) +nm_hash_update(NMHashState *state, const void *ptr, gsize n) { - nm_assert (state); - 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 - * 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. */ - c_siphash_append (&state->_state, ptr, n); + nm_assert(state); + nm_assert(n == 0 || ptr); + + /* Note: the data passed in here might be sensitive data (secrets), + * 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. */ + c_siphash_append(&state->_state, ptr, n); } -#define nm_hash_update_val(state, val) \ - G_STMT_START { \ - typeof (val) _val = (val); \ - \ - nm_hash_update ((state), &_val, sizeof (_val)); \ - } G_STMT_END +#define nm_hash_update_val(state, val) \ + G_STMT_START \ + { \ + typeof(val) _val = (val); \ + \ + nm_hash_update((state), &_val, sizeof(_val)); \ + } \ + G_STMT_END -#define nm_hash_update_valp(state, val) \ - nm_hash_update ((state), (val), sizeof (*(val))) \ +#define nm_hash_update_valp(state, val) nm_hash_update((state), (val), sizeof(*(val))) static inline void -nm_hash_update_bool (NMHashState *state, bool val) +nm_hash_update_bool(NMHashState *state, bool val) { - nm_hash_update (state, &val, sizeof (val)); + nm_hash_update(state, &val, sizeof(val)); } -#define _NM_HASH_COMBINE_BOOLS_x_1( t, y) ((y) ? ((t) (1ull << 0)) : ((t) 0ull)) -#define _NM_HASH_COMBINE_BOOLS_x_2( t, y, ...) ((y) ? ((t) (1ull << 1)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_1 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_3( t, y, ...) ((y) ? ((t) (1ull << 2)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_2 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_4( t, y, ...) ((y) ? ((t) (1ull << 3)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_3 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_5( t, y, ...) ((y) ? ((t) (1ull << 4)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_4 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_6( t, y, ...) ((y) ? ((t) (1ull << 5)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_5 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_7( t, y, ...) ((y) ? ((t) (1ull << 6)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_6 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_8( t, y, ...) ((y) ? ((t) (1ull << 7)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_7 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_9( t, y, ...) ((y) ? ((t) (1ull << 8)) : ((t) 0ull)) | (G_STATIC_ASSERT_EXPR (sizeof (t) >= 2), (_NM_HASH_COMBINE_BOOLS_x_8 (t, __VA_ARGS__))) -#define _NM_HASH_COMBINE_BOOLS_x_10(t, y, ...) ((y) ? ((t) (1ull << 9)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_9 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_x_11(t, y, ...) ((y) ? ((t) (1ull << 10)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_10 (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_n2(t, n, ...) _NM_HASH_COMBINE_BOOLS_x_##n (t, __VA_ARGS__) -#define _NM_HASH_COMBINE_BOOLS_n(t, n, ...) _NM_HASH_COMBINE_BOOLS_n2(t, n, __VA_ARGS__) - -#define NM_HASH_COMBINE_BOOLS(type, ...) ((type) (_NM_HASH_COMBINE_BOOLS_n(type, NM_NARG (__VA_ARGS__), __VA_ARGS__))) +#define _NM_HASH_COMBINE_BOOLS_x_1(t, y) ((y) ? ((t)(1ull << 0)) : ((t) 0ull)) +#define _NM_HASH_COMBINE_BOOLS_x_2(t, y, ...) \ + ((y) ? ((t)(1ull << 1)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_1(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_3(t, y, ...) \ + ((y) ? ((t)(1ull << 2)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_2(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_4(t, y, ...) \ + ((y) ? ((t)(1ull << 3)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_3(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_5(t, y, ...) \ + ((y) ? ((t)(1ull << 4)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_4(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_6(t, y, ...) \ + ((y) ? ((t)(1ull << 5)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_5(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_7(t, y, ...) \ + ((y) ? ((t)(1ull << 6)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_6(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_8(t, y, ...) \ + ((y) ? ((t)(1ull << 7)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_7(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_9(t, y, ...) \ + ((y) ? ((t)(1ull << 8)) : ((t) 0ull)) \ + | (G_STATIC_ASSERT_EXPR(sizeof(t) >= 2), (_NM_HASH_COMBINE_BOOLS_x_8(t, __VA_ARGS__))) +#define _NM_HASH_COMBINE_BOOLS_x_10(t, y, ...) \ + ((y) ? ((t)(1ull << 9)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_9(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_x_11(t, y, ...) \ + ((y) ? ((t)(1ull << 10)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_10(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_n2(t, n, ...) _NM_HASH_COMBINE_BOOLS_x_##n(t, __VA_ARGS__) +#define _NM_HASH_COMBINE_BOOLS_n(t, n, ...) _NM_HASH_COMBINE_BOOLS_n2(t, n, __VA_ARGS__) + +#define NM_HASH_COMBINE_BOOLS(type, ...) \ + ((type)(_NM_HASH_COMBINE_BOOLS_n(type, NM_NARG(__VA_ARGS__), __VA_ARGS__))) #define nm_hash_update_bools(state, ...) \ - nm_hash_update_val (state, NM_HASH_COMBINE_BOOLS (guint8, __VA_ARGS__)) - -#define _NM_HASH_COMBINE_VALS_typ_x_1( y) typeof (y) _v1; -#define _NM_HASH_COMBINE_VALS_typ_x_2( y, ...) typeof (y) _v2; _NM_HASH_COMBINE_VALS_typ_x_1 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_3( y, ...) typeof (y) _v3; _NM_HASH_COMBINE_VALS_typ_x_2 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_4( y, ...) typeof (y) _v4; _NM_HASH_COMBINE_VALS_typ_x_3 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_5( y, ...) typeof (y) _v5; _NM_HASH_COMBINE_VALS_typ_x_4 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_6( y, ...) typeof (y) _v6; _NM_HASH_COMBINE_VALS_typ_x_5 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_7( y, ...) typeof (y) _v7; _NM_HASH_COMBINE_VALS_typ_x_6 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_8( y, ...) typeof (y) _v8; _NM_HASH_COMBINE_VALS_typ_x_7 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_9( y, ...) typeof (y) _v9; _NM_HASH_COMBINE_VALS_typ_x_8 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_10(y, ...) typeof (y) _v10; _NM_HASH_COMBINE_VALS_typ_x_9 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_11(y, ...) typeof (y) _v11; _NM_HASH_COMBINE_VALS_typ_x_10 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_12(y, ...) typeof (y) _v12; _NM_HASH_COMBINE_VALS_typ_x_11 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_13(y, ...) typeof (y) _v13; _NM_HASH_COMBINE_VALS_typ_x_12 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_14(y, ...) typeof (y) _v14; _NM_HASH_COMBINE_VALS_typ_x_13 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_15(y, ...) typeof (y) _v15; _NM_HASH_COMBINE_VALS_typ_x_14 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_16(y, ...) typeof (y) _v16; _NM_HASH_COMBINE_VALS_typ_x_15 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_17(y, ...) typeof (y) _v17; _NM_HASH_COMBINE_VALS_typ_x_16 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_18(y, ...) typeof (y) _v18; _NM_HASH_COMBINE_VALS_typ_x_17 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_19(y, ...) typeof (y) _v19; _NM_HASH_COMBINE_VALS_typ_x_18 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_x_20(y, ...) typeof (y) _v20; _NM_HASH_COMBINE_VALS_typ_x_19 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_n2(n, ...) _NM_HASH_COMBINE_VALS_typ_x_##n (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_typ_n(n, ...) _NM_HASH_COMBINE_VALS_typ_n2(n, __VA_ARGS__) - -#define _NM_HASH_COMBINE_VALS_val_x_1( y) ._v1 = (y), -#define _NM_HASH_COMBINE_VALS_val_x_2( y, ...) ._v2 = (y), _NM_HASH_COMBINE_VALS_val_x_1 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_3( y, ...) ._v3 = (y), _NM_HASH_COMBINE_VALS_val_x_2 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_4( y, ...) ._v4 = (y), _NM_HASH_COMBINE_VALS_val_x_3 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_5( y, ...) ._v5 = (y), _NM_HASH_COMBINE_VALS_val_x_4 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_6( y, ...) ._v6 = (y), _NM_HASH_COMBINE_VALS_val_x_5 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_7( y, ...) ._v7 = (y), _NM_HASH_COMBINE_VALS_val_x_6 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_8( y, ...) ._v8 = (y), _NM_HASH_COMBINE_VALS_val_x_7 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_9( y, ...) ._v9 = (y), _NM_HASH_COMBINE_VALS_val_x_8 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_10(y, ...) ._v10 = (y), _NM_HASH_COMBINE_VALS_val_x_9 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_11(y, ...) ._v11 = (y), _NM_HASH_COMBINE_VALS_val_x_10 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_12(y, ...) ._v12 = (y), _NM_HASH_COMBINE_VALS_val_x_11 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_13(y, ...) ._v13 = (y), _NM_HASH_COMBINE_VALS_val_x_12 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_14(y, ...) ._v14 = (y), _NM_HASH_COMBINE_VALS_val_x_13 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_15(y, ...) ._v15 = (y), _NM_HASH_COMBINE_VALS_val_x_14 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_16(y, ...) ._v16 = (y), _NM_HASH_COMBINE_VALS_val_x_15 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_17(y, ...) ._v17 = (y), _NM_HASH_COMBINE_VALS_val_x_16 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_18(y, ...) ._v18 = (y), _NM_HASH_COMBINE_VALS_val_x_17 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_19(y, ...) ._v19 = (y), _NM_HASH_COMBINE_VALS_val_x_18 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_x_20(y, ...) ._v20 = (y), _NM_HASH_COMBINE_VALS_val_x_19 (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_n2(n, ...) _NM_HASH_COMBINE_VALS_val_x_##n (__VA_ARGS__) -#define _NM_HASH_COMBINE_VALS_val_n(n, ...) _NM_HASH_COMBINE_VALS_val_n2(n, __VA_ARGS__) + nm_hash_update_val(state, NM_HASH_COMBINE_BOOLS(guint8, __VA_ARGS__)) + +#define _NM_HASH_COMBINE_VALS_typ_x_1(y) typeof(y) _v1; +#define _NM_HASH_COMBINE_VALS_typ_x_2(y, ...) \ + typeof(y) _v2; \ + _NM_HASH_COMBINE_VALS_typ_x_1(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_3(y, ...) \ + typeof(y) _v3; \ + _NM_HASH_COMBINE_VALS_typ_x_2(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_4(y, ...) \ + typeof(y) _v4; \ + _NM_HASH_COMBINE_VALS_typ_x_3(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_5(y, ...) \ + typeof(y) _v5; \ + _NM_HASH_COMBINE_VALS_typ_x_4(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_6(y, ...) \ + typeof(y) _v6; \ + _NM_HASH_COMBINE_VALS_typ_x_5(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_7(y, ...) \ + typeof(y) _v7; \ + _NM_HASH_COMBINE_VALS_typ_x_6(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_8(y, ...) \ + typeof(y) _v8; \ + _NM_HASH_COMBINE_VALS_typ_x_7(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_9(y, ...) \ + typeof(y) _v9; \ + _NM_HASH_COMBINE_VALS_typ_x_8(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_10(y, ...) \ + typeof(y) _v10; \ + _NM_HASH_COMBINE_VALS_typ_x_9(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_11(y, ...) \ + typeof(y) _v11; \ + _NM_HASH_COMBINE_VALS_typ_x_10(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_12(y, ...) \ + typeof(y) _v12; \ + _NM_HASH_COMBINE_VALS_typ_x_11(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_13(y, ...) \ + typeof(y) _v13; \ + _NM_HASH_COMBINE_VALS_typ_x_12(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_14(y, ...) \ + typeof(y) _v14; \ + _NM_HASH_COMBINE_VALS_typ_x_13(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_15(y, ...) \ + typeof(y) _v15; \ + _NM_HASH_COMBINE_VALS_typ_x_14(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_16(y, ...) \ + typeof(y) _v16; \ + _NM_HASH_COMBINE_VALS_typ_x_15(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_17(y, ...) \ + typeof(y) _v17; \ + _NM_HASH_COMBINE_VALS_typ_x_16(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_18(y, ...) \ + typeof(y) _v18; \ + _NM_HASH_COMBINE_VALS_typ_x_17(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_19(y, ...) \ + typeof(y) _v19; \ + _NM_HASH_COMBINE_VALS_typ_x_18(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_x_20(y, ...) \ + typeof(y) _v20; \ + _NM_HASH_COMBINE_VALS_typ_x_19(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_n2(n, ...) _NM_HASH_COMBINE_VALS_typ_x_##n(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_typ_n(n, ...) _NM_HASH_COMBINE_VALS_typ_n2(n, __VA_ARGS__) + +#define _NM_HASH_COMBINE_VALS_val_x_1(y) ._v1 = (y), +#define _NM_HASH_COMBINE_VALS_val_x_2(y, ...) ._v2 = (y), _NM_HASH_COMBINE_VALS_val_x_1(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_3(y, ...) ._v3 = (y), _NM_HASH_COMBINE_VALS_val_x_2(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_4(y, ...) ._v4 = (y), _NM_HASH_COMBINE_VALS_val_x_3(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_5(y, ...) ._v5 = (y), _NM_HASH_COMBINE_VALS_val_x_4(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_6(y, ...) ._v6 = (y), _NM_HASH_COMBINE_VALS_val_x_5(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_7(y, ...) ._v7 = (y), _NM_HASH_COMBINE_VALS_val_x_6(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_8(y, ...) ._v8 = (y), _NM_HASH_COMBINE_VALS_val_x_7(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_9(y, ...) ._v9 = (y), _NM_HASH_COMBINE_VALS_val_x_8(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_10(y, ...) \ + ._v10 = (y), _NM_HASH_COMBINE_VALS_val_x_9(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_11(y, ...) \ + ._v11 = (y), _NM_HASH_COMBINE_VALS_val_x_10(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_12(y, ...) \ + ._v12 = (y), _NM_HASH_COMBINE_VALS_val_x_11(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_13(y, ...) \ + ._v13 = (y), _NM_HASH_COMBINE_VALS_val_x_12(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_14(y, ...) \ + ._v14 = (y), _NM_HASH_COMBINE_VALS_val_x_13(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_15(y, ...) \ + ._v15 = (y), _NM_HASH_COMBINE_VALS_val_x_14(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_16(y, ...) \ + ._v16 = (y), _NM_HASH_COMBINE_VALS_val_x_15(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_17(y, ...) \ + ._v17 = (y), _NM_HASH_COMBINE_VALS_val_x_16(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_18(y, ...) \ + ._v18 = (y), _NM_HASH_COMBINE_VALS_val_x_17(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_19(y, ...) \ + ._v19 = (y), _NM_HASH_COMBINE_VALS_val_x_18(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_x_20(y, ...) \ + ._v20 = (y), _NM_HASH_COMBINE_VALS_val_x_19(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_n2(n, ...) _NM_HASH_COMBINE_VALS_val_x_##n(__VA_ARGS__) +#define _NM_HASH_COMBINE_VALS_val_n(n, ...) _NM_HASH_COMBINE_VALS_val_n2(n, __VA_ARGS__) /* NM_HASH_COMBINE_VALS() is faster then nm_hash_update_val() as it combines multiple * calls to nm_hash_update() using a packed structure. */ -#define NM_HASH_COMBINE_VALS(var, ...) \ - const struct _nm_packed { \ - _NM_HASH_COMBINE_VALS_typ_n (NM_NARG (__VA_ARGS__), __VA_ARGS__) \ - } var _nm_alignas (guint64) = { \ - _NM_HASH_COMBINE_VALS_val_n (NM_NARG (__VA_ARGS__), __VA_ARGS__) \ - } +#define NM_HASH_COMBINE_VALS(var, ...) \ + const struct _nm_packed { \ + _NM_HASH_COMBINE_VALS_typ_n(NM_NARG(__VA_ARGS__), __VA_ARGS__) \ + } var _nm_alignas(guint64) = {_NM_HASH_COMBINE_VALS_val_n(NM_NARG(__VA_ARGS__), __VA_ARGS__)} /* nm_hash_update_vals() is faster then nm_hash_update_val() as it combines multiple * calls to nm_hash_update() using a packed structure. */ -#define nm_hash_update_vals(state, ...) \ - G_STMT_START { \ - NM_HASH_COMBINE_VALS (_val, __VA_ARGS__); \ - \ - nm_hash_update ((state), &_val, sizeof (_val)); \ - } G_STMT_END +#define nm_hash_update_vals(state, ...) \ + G_STMT_START \ + { \ + NM_HASH_COMBINE_VALS(_val, __VA_ARGS__); \ + \ + nm_hash_update((state), &_val, sizeof(_val)); \ + } \ + G_STMT_END static inline void -nm_hash_update_mem (NMHashState *state, const void *ptr, gsize n) +nm_hash_update_mem(NMHashState *state, const void *ptr, gsize n) { - /* This also hashes the length of the data. That means, - * hashing two consecutive binary fields (of arbitrary - * length), will hash differently. That is, - * [[1,1], []] differs from [[1],[1]]. - * - * If you have a constant length (sizeof), use nm_hash_update() - * instead. */ - nm_hash_update (state, &n, sizeof (n)); - if (n > 0) - nm_hash_update (state, ptr, n); + /* This also hashes the length of the data. That means, + * hashing two consecutive binary fields (of arbitrary + * length), will hash differently. That is, + * [[1,1], []] differs from [[1],[1]]. + * + * If you have a constant length (sizeof), use nm_hash_update() + * instead. */ + nm_hash_update(state, &n, sizeof(n)); + if (n > 0) + nm_hash_update(state, ptr, n); } static inline void -nm_hash_update_str0 (NMHashState *state, const char *str) +nm_hash_update_str0(NMHashState *state, const char *str) { - if (str) - nm_hash_update_mem (state, str, strlen (str)); - else { - gsize n = G_MAXSIZE; + if (str) + nm_hash_update_mem(state, str, strlen(str)); + else { + gsize n = G_MAXSIZE; - nm_hash_update (state, &n, sizeof (n)); - } + nm_hash_update(state, &n, sizeof(n)); + } } static inline void -nm_hash_update_str (NMHashState *state, const char *str) +nm_hash_update_str(NMHashState *state, const char *str) { - nm_assert (str); - nm_hash_update (state, str, strlen (str) + 1); + nm_assert(str); + nm_hash_update(state, str, strlen(str) + 1); } #if _NM_CC_SUPPORT_GENERIC -/* Like nm_hash_update_str(), but restricted to arrays only. nm_hash_update_str() only works + /* Like nm_hash_update_str(), but restricted to arrays only. nm_hash_update_str() only works * with a @str argument that cannot be NULL. If you have a string pointer, that is never NULL, use * nm_hash_update() instead. */ -#define nm_hash_update_strarr(state, str) \ - (_Generic (&(str), \ - const char (*) [sizeof (str)]: nm_hash_update_str ((state), (str)), \ - char (*) [sizeof (str)]: nm_hash_update_str ((state), (str))) \ - ) + #define nm_hash_update_strarr(state, str) \ + (_Generic(&(str), const char(*)[sizeof(str)] \ + : nm_hash_update_str((state), (str)), char(*)[sizeof(str)] \ + : nm_hash_update_str((state), (str)))) #else -#define nm_hash_update_strarr(state, str) nm_hash_update_str ((state), (str)) + #define nm_hash_update_strarr(state, str) nm_hash_update_str((state), (str)) #endif -guint nm_hash_ptr (gconstpointer ptr); -guint nm_direct_hash (gconstpointer str); +guint nm_hash_ptr(gconstpointer ptr); +guint nm_direct_hash(gconstpointer str); -guint nm_hash_str (const char *str); -guint nm_str_hash (gconstpointer str); +guint nm_hash_str(const char *str); +guint nm_str_hash(gconstpointer str); -#define nm_hash_val(static_seed, val) \ - ({ \ - NMHashState _h; \ - \ - nm_hash_init (&_h, (static_seed)); \ - nm_hash_update_val (&_h, (val)); \ - nm_hash_complete (&_h); \ - }) +#define nm_hash_val(static_seed, val) \ + ({ \ + NMHashState _h; \ + \ + nm_hash_init(&_h, (static_seed)); \ + nm_hash_update_val(&_h, (val)); \ + nm_hash_complete(&_h); \ + }) static inline guint -nm_hash_mem (guint static_seed, const void *ptr, gsize n) +nm_hash_mem(guint static_seed, const void *ptr, gsize n) { - NMHashState h; + NMHashState h; - if (n == 0) - return nm_hash_static (static_seed); - nm_hash_init (&h, static_seed); - nm_hash_update (&h, ptr, n); - return nm_hash_complete (&h); + if (n == 0) + return nm_hash_static(static_seed); + nm_hash_init(&h, static_seed); + nm_hash_update(&h, ptr, n); + return nm_hash_complete(&h); } /*****************************************************************************/ @@ -284,42 +344,46 @@ nm_hash_mem (guint static_seed, const void *ptr, gsize n) /* nm_pstr_*() are for hashing keys that are pointers to strings, * that is, "const char *const*" types, using strcmp(). */ -guint nm_pstr_hash (gconstpointer p); +guint nm_pstr_hash(gconstpointer p); -gboolean nm_pstr_equal (gconstpointer a, gconstpointer b); +gboolean nm_pstr_equal(gconstpointer a, gconstpointer b); /*****************************************************************************/ /* nm_pint_*() are for hashing keys that are pointers to int values, * that is, "const int *" types. */ -guint nm_pint_hash (gconstpointer p); -gboolean nm_pint_equals (gconstpointer a, gconstpointer b); +guint nm_pint_hash(gconstpointer p); +gboolean nm_pint_equals(gconstpointer a, gconstpointer b); + +G_STATIC_ASSERT(sizeof(int) == sizeof(guint32)); +#define nm_puint32_hash nm_pint_hash +#define nm_puint32_equals nm_pint_equals /*****************************************************************************/ /* this hashes/compares the pointer value that we point to. Basically, * (*((const void *const*) a) == *((const void *const*) b)). */ -guint nm_pdirect_hash (gconstpointer p); +guint nm_pdirect_hash(gconstpointer p); -gboolean nm_pdirect_equal (gconstpointer a, gconstpointer b); +gboolean nm_pdirect_equal(gconstpointer a, gconstpointer b); /* this hashes/compares the direct pointer value by following pointers to * pointers 2 times. * (**((const void *const*const*) a) == **((const void *const*const*) b)). */ -guint nm_ppdirect_hash (gconstpointer p); +guint nm_ppdirect_hash(gconstpointer p); -gboolean nm_ppdirect_equal (gconstpointer a, gconstpointer b); +gboolean nm_ppdirect_equal(gconstpointer a, gconstpointer b); /*****************************************************************************/ -guint nm_gbytes_hash (gconstpointer p); +guint nm_gbytes_hash(gconstpointer p); #define nm_gbytes_equal g_bytes_equal -guint nm_pgbytes_hash (gconstpointer p); -gboolean nm_pgbytes_equal (gconstpointer a, gconstpointer b); +guint nm_pgbytes_hash(gconstpointer p); +gboolean nm_pgbytes_equal(gconstpointer a, gconstpointer b); /*****************************************************************************/ @@ -333,13 +397,13 @@ gboolean nm_pgbytes_equal (gconstpointer a, gconstpointer b); * Note that there is a chance that two different pointer values hash to the same obfuscated * value. So beware of that when reviewing logs. However, such a collision is very unlikely. */ static inline guint64 -nm_hash_obfuscate_ptr (guint static_seed, gconstpointer val) +nm_hash_obfuscate_ptr(guint static_seed, gconstpointer val) { - NMHashState h; + NMHashState h; - nm_hash_init (&h, static_seed); - nm_hash_update_val (&h, val); - return nm_hash_complete_u64 (&h); + nm_hash_init(&h, static_seed); + nm_hash_update_val(&h, val); + return nm_hash_complete_u64(&h); } /* if you want to log obfuscated pointer for a certain context (like, NMPRuleManager @@ -350,7 +414,20 @@ nm_hash_obfuscate_ptr (guint static_seed, gconstpointer val) * for all singletons, so they must all be obfuscated with the same seed. So, this * macro uses a particular static seed that should be used by when comparing pointer * values in a global context. */ -#define NM_HASH_OBFUSCATE_PTR(ptr) (nm_hash_obfuscate_ptr (1678382159u, ptr)) +#define NM_HASH_OBFUSCATE_PTR(ptr) (nm_hash_obfuscate_ptr(1678382159u, ptr)) + +static inline const char * +nm_hash_obfuscated_ptr_str(gconstpointer ptr, char buf[static 17]) +{ + int l; + + nm_assert(buf); + l = g_snprintf(buf, 17, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(ptr)); + nm_assert(l < 17); + return buf; +} + +#define nm_hash_obfuscated_ptr_str_a(ptr) (nm_hash_obfuscated_ptr_str((ptr), g_alloca(17))) /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-io-utils.c b/shared/nm-glib-aux/nm-io-utils.c index 776c63e1..32f92156 100644 --- a/shared/nm-glib-aux/nm-io-utils.c +++ b/shared/nm-glib-aux/nm-io-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -18,39 +18,41 @@ /*****************************************************************************/ -_nm_printf (4, 5) -static int -_get_contents_error (GError **error, int errsv, int *out_errsv, const char *format, ...) +_nm_printf(4, 5) static int _get_contents_error(GError ** error, + int errsv, + int * out_errsv, + const char *format, + ...) { - nm_assert (NM_ERRNO_NATIVE (errsv)); - - if (error) { - gs_free char *msg = NULL; - va_list args; - char bstrerr[NM_STRERROR_BUFSIZE]; - - va_start (args, format); - msg = g_strdup_vprintf (format, args); - va_end (args); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "%s: %s", - msg, - nm_strerror_native_r (errsv, bstrerr, sizeof (bstrerr))); - } - - nm_assert (errsv > 0); - NM_SET_OUT (out_errsv, errsv); - - return FALSE; + nm_assert(NM_ERRNO_NATIVE(errsv)); + + if (error) { + gs_free char *msg = NULL; + va_list args; + char bstrerr[NM_STRERROR_BUFSIZE]; + + va_start(args, format); + msg = g_strdup_vprintf(format, args); + va_end(args); + g_set_error(error, + G_FILE_ERROR, + g_file_error_from_errno(errsv), + "%s: %s", + msg, + nm_strerror_native_r(errsv, bstrerr, sizeof(bstrerr))); + } + + nm_assert(errsv > 0); + NM_SET_OUT(out_errsv, errsv); + + return FALSE; } -#define _get_contents_error_errno(error, out_errsv, ...) \ - ({ \ - int _errsv = (errno); \ - \ - _get_contents_error (error, _errsv, out_errsv, __VA_ARGS__); \ - }) +#define _get_contents_error_errno(error, out_errsv, ...) \ + ({ \ + int _errsv = (errno); \ + \ + _get_contents_error(error, _errsv, out_errsv, __VA_ARGS__); \ + }) /** * nm_utils_fd_get_contents: @@ -86,147 +88,177 @@ _get_contents_error (GError **error, int errsv, int *out_errsv, const char *form * Returns: TRUE on success. */ gboolean -nm_utils_fd_get_contents (int fd, - gboolean close_fd, - gsize max_length, - NMUtilsFileGetContentsFlags flags, - char **contents, - gsize *length, - int *out_errsv, - GError **error) +nm_utils_fd_get_contents(int fd, + gboolean close_fd, + gsize max_length, + NMUtilsFileGetContentsFlags flags, + char ** contents, + gsize * length, + int * out_errsv, + GError ** error) { - nm_auto_close int fd_keeper = close_fd ? fd : -1; - struct stat stat_buf; - gs_free char *str = NULL; - const bool do_bzero_mem = NM_FLAGS_HAS (flags, NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET); - int errsv; - - g_return_val_if_fail (fd >= 0, FALSE); - g_return_val_if_fail (contents && !*contents, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - NM_SET_OUT (length, 0); - - if (fstat (fd, &stat_buf) < 0) - return _get_contents_error_errno (error, out_errsv, "failure during fstat"); - - if (!max_length) { - /* default to a very large size, but not extreme */ - max_length = 2 * 1024 * 1024; - } - - if ( stat_buf.st_size > 0 - && S_ISREG (stat_buf.st_mode)) { - const gsize n_stat = stat_buf.st_size; - ssize_t n_read; - - if (n_stat > max_length - 1) - return _get_contents_error (error, EMSGSIZE, out_errsv, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length); - - str = g_try_malloc (n_stat + 1); - if (!str) - return _get_contents_error (error, ENOMEM, out_errsv, "failure to allocate buffer of %zu+1 bytes", n_stat); - - n_read = nm_utils_fd_read_loop (fd, str, n_stat, TRUE); - if (n_read < 0) { - if (do_bzero_mem) - nm_explicit_bzero (str, n_stat); - return _get_contents_error (error, -n_read, out_errsv, "error reading %zu bytes from file descriptor", n_stat); - } - str[n_read] = '\0'; - - if (n_read < n_stat) { - if (!(str = nm_secret_mem_try_realloc_take (str, do_bzero_mem, n_stat + 1, n_read + 1))) - return _get_contents_error (error, ENOMEM, out_errsv, "failure to reallocate buffer with %zu bytes", n_read + 1); - } - NM_SET_OUT (length, n_read); - } else { - nm_auto_fclose FILE *f = NULL; - char buf[4096]; - gsize n_have, n_alloc; - int fd2; - - if (fd_keeper >= 0) - fd2 = nm_steal_fd (&fd_keeper); - else { - fd2 = fcntl (fd, F_DUPFD_CLOEXEC, 0); - if (fd2 < 0) - return _get_contents_error_errno (error, out_errsv, "error during dup"); - } - - if (!(f = fdopen (fd2, "r"))) { - errsv = errno; - nm_close (fd2); - return _get_contents_error (error, errsv, out_errsv, "failure during fdopen"); - } - - n_have = 0; - n_alloc = 0; - - while (!feof (f)) { - gsize n_read; - - n_read = fread (buf, 1, sizeof (buf), f); - errsv = errno; - if (ferror (f)) { - if (do_bzero_mem) - nm_explicit_bzero (buf, sizeof (buf)); - return _get_contents_error (error, errsv, out_errsv, "error during fread"); - } - - if ( n_have > G_MAXSIZE - 1 - n_read - || n_have + n_read + 1 > max_length) { - if (do_bzero_mem) - nm_explicit_bzero (buf, sizeof (buf)); - return _get_contents_error (error, EMSGSIZE, out_errsv, "file stream too large (%zu+1 bytes with maximum %zu bytes)", - (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read, - max_length); - } - - if (n_have + n_read + 1 >= n_alloc) { - gsize old_n_alloc = n_alloc; - - if (n_alloc != 0) { - nm_assert (str); - if (n_alloc >= max_length / 2) - n_alloc = max_length; - else - n_alloc *= 2; - } else { - nm_assert (!str); - n_alloc = NM_MIN (n_read + 1, sizeof (buf)); - } - - if (!(str = nm_secret_mem_try_realloc_take (str, do_bzero_mem, old_n_alloc, n_alloc))) { - if (do_bzero_mem) - nm_explicit_bzero (buf, sizeof (buf)); - return _get_contents_error (error, ENOMEM, out_errsv, "failure to allocate buffer of %zu bytes", n_alloc); - } - } - - memcpy (str + n_have, buf, n_read); - n_have += n_read; - } - - if (do_bzero_mem) - nm_explicit_bzero (buf, sizeof (buf)); - - if (n_alloc == 0) - str = g_new0 (char, 1); - else { - str[n_have] = '\0'; - if (n_have + 1 < n_alloc) { - if (!(str = nm_secret_mem_try_realloc_take (str, do_bzero_mem, n_alloc, n_have + 1))) - return _get_contents_error (error, ENOMEM, out_errsv, "failure to truncate buffer to %zu bytes", n_have + 1); - } - } - - NM_SET_OUT (length, n_have); - } - - *contents = g_steal_pointer (&str); - NM_SET_OUT (out_errsv, 0); - return TRUE; + nm_auto_close int fd_keeper = close_fd ? fd : -1; + struct stat stat_buf; + gs_free char * str = NULL; + const bool do_bzero_mem = NM_FLAGS_HAS(flags, NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET); + int errsv; + + g_return_val_if_fail(fd >= 0, FALSE); + g_return_val_if_fail(contents && !*contents, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + + NM_SET_OUT(length, 0); + + if (fstat(fd, &stat_buf) < 0) + return _get_contents_error_errno(error, out_errsv, "failure during fstat"); + + if (!max_length) { + /* default to a very large size, but not extreme */ + max_length = 2 * 1024 * 1024; + } + + if (stat_buf.st_size > 0 && S_ISREG(stat_buf.st_mode)) { + const gsize n_stat = stat_buf.st_size; + ssize_t n_read; + + if (n_stat > max_length - 1) + return _get_contents_error(error, + EMSGSIZE, + out_errsv, + "file too large (%zu+1 bytes with maximum %zu bytes)", + n_stat, + max_length); + + str = g_try_malloc(n_stat + 1); + if (!str) + return _get_contents_error(error, + ENOMEM, + out_errsv, + "failure to allocate buffer of %zu+1 bytes", + n_stat); + + n_read = nm_utils_fd_read_loop(fd, str, n_stat, TRUE); + if (n_read < 0) { + if (do_bzero_mem) + nm_explicit_bzero(str, n_stat); + return _get_contents_error(error, + -n_read, + out_errsv, + "error reading %zu bytes from file descriptor", + n_stat); + } + str[n_read] = '\0'; + + if (n_read < n_stat) { + if (!(str = nm_secret_mem_try_realloc_take(str, do_bzero_mem, n_stat + 1, n_read + 1))) + return _get_contents_error(error, + ENOMEM, + out_errsv, + "failure to reallocate buffer with %zu bytes", + n_read + 1); + } + NM_SET_OUT(length, n_read); + } else { + nm_auto_fclose FILE *f = NULL; + char buf[4096]; + gsize n_have, n_alloc; + int fd2; + + if (fd_keeper >= 0) + fd2 = nm_steal_fd(&fd_keeper); + else { + fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0); + if (fd2 < 0) + return _get_contents_error_errno(error, out_errsv, "error during dup"); + } + + if (!(f = fdopen(fd2, "r"))) { + errsv = errno; + nm_close(fd2); + return _get_contents_error(error, errsv, out_errsv, "failure during fdopen"); + } + + n_have = 0; + n_alloc = 0; + + while (!feof(f)) { + gsize n_read; + + n_read = fread(buf, 1, sizeof(buf), f); + errsv = errno; + if (ferror(f)) { + if (do_bzero_mem) + nm_explicit_bzero(buf, sizeof(buf)); + return _get_contents_error(error, errsv, out_errsv, "error during fread"); + } + + if (n_have > G_MAXSIZE - 1 - n_read || n_have + n_read + 1 > max_length) { + if (do_bzero_mem) + nm_explicit_bzero(buf, sizeof(buf)); + return _get_contents_error( + error, + EMSGSIZE, + out_errsv, + "file stream too large (%zu+1 bytes with maximum %zu bytes)", + (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read, + max_length); + } + + if (n_have + n_read + 1 >= n_alloc) { + gsize old_n_alloc = n_alloc; + + if (n_alloc != 0) { + nm_assert(str); + if (n_alloc >= max_length / 2) + n_alloc = max_length; + else + n_alloc *= 2; + } else { + nm_assert(!str); + n_alloc = NM_MIN(n_read + 1, sizeof(buf)); + } + + if (!(str = nm_secret_mem_try_realloc_take(str, + do_bzero_mem, + old_n_alloc, + n_alloc))) { + if (do_bzero_mem) + nm_explicit_bzero(buf, sizeof(buf)); + return _get_contents_error(error, + ENOMEM, + out_errsv, + "failure to allocate buffer of %zu bytes", + n_alloc); + } + } + + memcpy(str + n_have, buf, n_read); + n_have += n_read; + } + + if (do_bzero_mem) + nm_explicit_bzero(buf, sizeof(buf)); + + if (n_alloc == 0) + str = g_new0(char, 1); + else { + str[n_have] = '\0'; + if (n_have + 1 < n_alloc) { + if (!(str = nm_secret_mem_try_realloc_take(str, do_bzero_mem, n_alloc, n_have + 1))) + return _get_contents_error(error, + ENOMEM, + out_errsv, + "failure to truncate buffer to %zu bytes", + n_have + 1); + } + } + + NM_SET_OUT(length, n_have); + } + + *contents = g_steal_pointer(&str); + NM_SET_OUT(out_errsv, 0); + return TRUE; } /** @@ -253,47 +285,47 @@ nm_utils_fd_get_contents (int fd, * Returns: TRUE on success. */ gboolean -nm_utils_file_get_contents (int dirfd, - const char *filename, - gsize max_length, - NMUtilsFileGetContentsFlags flags, - char **contents, - gsize *length, - int *out_errsv, - GError **error) +nm_utils_file_get_contents(int dirfd, + const char * filename, + gsize max_length, + NMUtilsFileGetContentsFlags flags, + char ** contents, + gsize * length, + int * out_errsv, + GError ** error) { - int fd; - - g_return_val_if_fail (filename && filename[0], FALSE); - g_return_val_if_fail (contents && !*contents, FALSE); - - NM_SET_OUT (length, 0); - - if (dirfd >= 0) { - fd = openat (dirfd, filename, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - return _get_contents_error_errno (error, - out_errsv, - "Failed to open file \"%s\" with openat", - filename); - } - } else { - fd = open (filename, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - return _get_contents_error_errno (error, - out_errsv, - "Failed to open file \"%s\"", - filename); - } - } - return nm_utils_fd_get_contents (fd, - TRUE, - max_length, - flags, - contents, - length, - out_errsv, - error); + int fd; + + g_return_val_if_fail(filename && filename[0], FALSE); + g_return_val_if_fail(contents && !*contents, FALSE); + + NM_SET_OUT(length, 0); + + if (dirfd >= 0) { + fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return _get_contents_error_errno(error, + out_errsv, + "Failed to open file \"%s\" with openat", + filename); + } + } else { + fd = open(filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return _get_contents_error_errno(error, + out_errsv, + "Failed to open file \"%s\"", + filename); + } + } + return nm_utils_fd_get_contents(fd, + TRUE, + max_length, + flags, + contents, + length, + out_errsv, + error); } /*****************************************************************************/ @@ -303,92 +335,84 @@ nm_utils_file_get_contents (int dirfd, * specifying a mode for the new file. */ gboolean -nm_utils_file_set_contents (const char *filename, - const char *contents, - gssize length, - mode_t mode, - int *out_errsv, - GError **error) +nm_utils_file_set_contents(const char *filename, + const char *contents, + gssize length, + mode_t mode, + int * out_errsv, + GError ** error) { - gs_free char *tmp_name = NULL; - struct stat statbuf; - int errsv; - gssize s; - int fd; - - g_return_val_if_fail (filename, FALSE); - g_return_val_if_fail (contents || !length, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - g_return_val_if_fail (length >= -1, FALSE); - - if (length == -1) - length = strlen (contents); - - tmp_name = g_strdup_printf ("%s.XXXXXX", filename); - fd = g_mkstemp_full (tmp_name, O_RDWR | O_CLOEXEC, mode); - if (fd < 0) { - return _get_contents_error_errno (error, - out_errsv, - "failed to create file %s", - tmp_name); - } - - while (length > 0) { - s = write (fd, contents, length); - if (s < 0) { - errsv = NM_ERRNO_NATIVE (errno); - if (errsv == EINTR) - continue; - - nm_close (fd); - unlink (tmp_name); - return _get_contents_error (error, - errsv, - out_errsv, - "failed to write to file %s", - tmp_name); - } - - g_assert (s <= length); - - contents += s; - length -= s; - } - - /* 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 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.) - */ - if ( lstat (filename, &statbuf) == 0 - && statbuf.st_size > 0) { - if (fsync (fd) != 0) { - errsv = NM_ERRNO_NATIVE (errno); - nm_close (fd); - unlink (tmp_name); - return _get_contents_error (error, - errsv, - out_errsv, - "failed to fsync %s", - tmp_name); - } - } - - nm_close (fd); - - if (rename (tmp_name, filename)) { - errsv = NM_ERRNO_NATIVE (errno); - unlink (tmp_name); - return _get_contents_error (error, - errsv, - out_errsv, - "failed rename %s to %s", - tmp_name, - filename); - } - - return TRUE; + gs_free char *tmp_name = NULL; + struct stat statbuf; + int errsv; + gssize s; + int fd; + + g_return_val_if_fail(filename, FALSE); + g_return_val_if_fail(contents || !length, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + g_return_val_if_fail(length >= -1, FALSE); + + if (length == -1) + length = strlen(contents); + + tmp_name = g_strdup_printf("%s.XXXXXX", filename); + fd = g_mkstemp_full(tmp_name, O_RDWR | O_CLOEXEC, mode); + if (fd < 0) { + return _get_contents_error_errno(error, out_errsv, "failed to create file %s", tmp_name); + } + + while (length > 0) { + s = write(fd, contents, length); + if (s < 0) { + errsv = NM_ERRNO_NATIVE(errno); + if (errsv == EINTR) + continue; + + nm_close(fd); + unlink(tmp_name); + return _get_contents_error(error, + errsv, + out_errsv, + "failed to write to file %s", + tmp_name); + } + + g_assert(s <= length); + + contents += s; + length -= s; + } + + /* 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 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.) + */ + if (lstat(filename, &statbuf) == 0 && statbuf.st_size > 0) { + if (fsync(fd) != 0) { + errsv = NM_ERRNO_NATIVE(errno); + nm_close(fd); + unlink(tmp_name); + return _get_contents_error(error, errsv, out_errsv, "failed to fsync %s", tmp_name); + } + } + + nm_close(fd); + + if (rename(tmp_name, filename)) { + errsv = NM_ERRNO_NATIVE(errno); + unlink(tmp_name); + return _get_contents_error(error, + errsv, + out_errsv, + "failed rename %s to %s", + tmp_name, + filename); + } + + return TRUE; } /** @@ -405,13 +429,13 @@ nm_utils_file_set_contents (const char *filename, * * Returns: 0 on success a negative errno on failure. */ int -nm_utils_file_stat (const char *filename, struct stat *out_st) +nm_utils_file_stat(const char *filename, struct stat *out_st) { - struct stat st; + struct stat st; - if (stat (filename, out_st ?: &st) != 0) - return -NM_ERRNO_NATIVE (errno); - return 0; + if (stat(filename, out_st ?: &st) != 0) + return -NM_ERRNO_NATIVE(errno); + return 0; } /** @@ -423,36 +447,34 @@ nm_utils_file_stat (const char *filename, struct stat *out_st) * 0 on EOF. * >0 on success, which is the number of bytes read. */ gssize -nm_utils_fd_read (int fd, NMStrBuf *out_string) +nm_utils_fd_read(int fd, NMStrBuf *out_string) { - gsize buf_available; - gssize n_read; - int errsv; - - g_return_val_if_fail (fd >= 0, -1); - g_return_val_if_fail (out_string, -1); - - /* If the buffer size is 0, we allocate NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 (1000 bytes) - * the first time. Afterwards, the buffer grows exponentially. - * - * Note that with @buf_available, we always would read as much buffer as we actually - * have reserved. */ - nm_str_buf_maybe_expand (out_string, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); - - buf_available = out_string->allocated - out_string->len; - - n_read = read (fd, - &((nm_str_buf_get_str_unsafe (out_string))[out_string->len]), - buf_available); - if (n_read < 0) { - errsv = errno; - return -NM_ERRNO_NATIVE (errsv); - } - - if (n_read > 0) { - nm_assert ((gsize) n_read <= buf_available); - nm_str_buf_set_size (out_string, out_string->len + (gsize) n_read, TRUE, FALSE); - } - - return n_read; + gsize buf_available; + gssize n_read; + int errsv; + + g_return_val_if_fail(fd >= 0, -1); + g_return_val_if_fail(out_string, -1); + + /* If the buffer size is 0, we allocate NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 (1000 bytes) + * the first time. Afterwards, the buffer grows exponentially. + * + * Note that with @buf_available, we always would read as much buffer as we actually + * have reserved. */ + nm_str_buf_maybe_expand(out_string, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + + buf_available = out_string->allocated - out_string->len; + + n_read = read(fd, &((nm_str_buf_get_str_unsafe(out_string))[out_string->len]), buf_available); + if (n_read < 0) { + errsv = errno; + return -NM_ERRNO_NATIVE(errsv); + } + + if (n_read > 0) { + nm_assert((gsize) n_read <= buf_available); + nm_str_buf_set_size(out_string, out_string->len + (gsize) n_read, TRUE, FALSE); + } + + return n_read; } diff --git a/shared/nm-glib-aux/nm-io-utils.h b/shared/nm-glib-aux/nm-io-utils.h index 31326fc7..81be7b60 100644 --- a/shared/nm-glib-aux/nm-io-utils.h +++ b/shared/nm-glib-aux/nm-io-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -14,45 +14,45 @@ * 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 { - NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE = 0, - NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET = (1 << 0), + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE = 0, + NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET = (1 << 0), } NMUtilsFileGetContentsFlags; -gboolean nm_utils_fd_get_contents (int fd, - gboolean close_fd, - gsize max_length, - NMUtilsFileGetContentsFlags flags, - char **contents, - gsize *length, - int *out_errsv, - GError **error); - -gboolean nm_utils_file_get_contents (int dirfd, - const char *filename, - gsize max_length, - NMUtilsFileGetContentsFlags flags, - char **contents, - gsize *length, - int *out_errsv, - GError **error); - -gboolean nm_utils_file_set_contents (const char *filename, - const char *contents, - gssize length, - mode_t mode, - int *out_errsv, - GError **error); +gboolean nm_utils_fd_get_contents(int fd, + gboolean close_fd, + gsize max_length, + NMUtilsFileGetContentsFlags flags, + char ** contents, + gsize * length, + int * out_errsv, + GError ** error); + +gboolean nm_utils_file_get_contents(int dirfd, + const char * filename, + gsize max_length, + NMUtilsFileGetContentsFlags flags, + char ** contents, + gsize * length, + int * out_errsv, + GError ** error); + +gboolean nm_utils_file_set_contents(const char *filename, + const char *contents, + gssize length, + mode_t mode, + int * out_errsv, + GError ** error); struct _NMStrBuf; -gssize nm_utils_fd_read (int fd, struct _NMStrBuf *out_string); +gssize nm_utils_fd_read(int fd, struct _NMStrBuf *out_string); struct stat; -int nm_utils_file_stat (const char *filename, struct stat *out_st); +int nm_utils_file_stat(const char *filename, struct stat *out_st); #endif /* __NM_IO_UTILS_H__ */ diff --git a/shared/nm-glib-aux/nm-jansson.h b/shared/nm-glib-aux/nm-jansson.h index 7c034222..9b7731a4 100644 --- a/shared/nm-glib-aux/nm-jansson.h +++ b/shared/nm-glib-aux/nm-jansson.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -10,126 +10,21 @@ #if WITH_JANSSON -#include <jansson.h> + #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) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + #endif -/* Added in Jansson v2.8 */ -#ifndef json_object_foreach_safe -#define json_object_foreach_safe(object, n, key, value) \ - for (key = json_object_iter_key(json_object_iter(object)), \ - n = json_object_iter_next(object, json_object_key_to_iter(key)); \ - key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ - key = json_object_iter_key(n), \ - n = json_object_iter_next(object, json_object_key_to_iter(key))) -#endif - -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 - -/*****************************************************************************/ +NM_AUTO_DEFINE_FCN0(json_t *, _nm_auto_decref_json, json_decref); + #define nm_auto_decref_json nm_auto(_nm_auto_decref_json) #endif /* WITH_JANSON */ -#endif /* __NM_JANSSON_H__ */ +#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 a738ab72..4212e628 100644 --- a/shared/nm-glib-aux/nm-json-aux.c +++ b/shared/nm-glib-aux/nm-json-aux.c @@ -1,135 +1,276 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* 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 -_gstr_append_string_len (GString *gstr, - const char *str, - gsize len) +_gstr_append_string_len(GString *gstr, const char *str, gsize len) { - g_string_append_c (gstr, '\"'); - - while (len > 0) { - gsize n; - const char *end; - gboolean valid; - - nm_assert (len > 0); - - valid = g_utf8_validate (str, len, &end); - - nm_assert ( end - && end >= str - && end <= &str[len]); - - if (end > str) { - const char *s; - - for (s = str; s < end; s++) { - nm_assert (s[0] != '\0'); - - if (s[0] < 0x20) { - const char *text; - - switch (s[0]) { - case '\\': text = "\\\\"; break; - case '\"': text = "\\\""; break; - case '\b': text = "\\b"; break; - case '\f': text = "\\f"; break; - case '\n': text = "\\n"; break; - case '\r': text = "\\r"; break; - case '\t': text = "\\t"; break; - default: - g_string_append_printf (gstr, "\\u%04X", (guint) s[0]); - continue; - } - g_string_append (gstr, text); - continue; - } - - if (NM_IN_SET (s[0], '\\', '\"')) - g_string_append_c (gstr, '\\'); - g_string_append_c (gstr, s[0]); - } - } else - nm_assert (!valid); - - if (valid) { - nm_assert (end == &str[len]); - break; - } - - nm_assert (end < &str[len]); - - if (end[0] == '\0') { - /* there is a NUL byte in the string. Technically this is valid UTF-8, so we - * encode it there. However, this will likely result in a truncated string when - * parsing. */ - g_string_append (gstr, "\\u0000"); - } else { - /* the character is not valid UTF-8. There is nothing we can do about it, because - * 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 - * it as a JSON string (which are unicode strings). - * - * Print an underscore instead of the invalid char :) */ - g_string_append_c (gstr, '_'); - } - - n = str - end; - nm_assert (n < len); - n++; - str += n; - len -= n; - } - - g_string_append_c (gstr, '\"'); + g_string_append_c(gstr, '\"'); + + while (len > 0) { + gsize n; + const char *end; + gboolean valid; + + nm_assert(len > 0); + + valid = g_utf8_validate(str, len, &end); + + nm_assert(end && end >= str && end <= &str[len]); + + if (end > str) { + const char *s; + + for (s = str; s < end; s++) { + nm_assert(s[0] != '\0'); + + if (s[0] < 0x20) { + const char *text; + + switch (s[0]) { + case '\\': + text = "\\\\"; + break; + case '\"': + text = "\\\""; + break; + case '\b': + text = "\\b"; + break; + case '\f': + text = "\\f"; + break; + case '\n': + text = "\\n"; + break; + case '\r': + text = "\\r"; + break; + case '\t': + text = "\\t"; + break; + default: + g_string_append_printf(gstr, "\\u%04X", (guint) s[0]); + continue; + } + g_string_append(gstr, text); + continue; + } + + if (NM_IN_SET(s[0], '\\', '\"')) + g_string_append_c(gstr, '\\'); + g_string_append_c(gstr, s[0]); + } + } else + nm_assert(!valid); + + if (valid) { + nm_assert(end == &str[len]); + break; + } + + nm_assert(end < &str[len]); + + if (end[0] == '\0') { + /* there is a NUL byte in the string. Technically this is valid UTF-8, so we + * encode it there. However, this will likely result in a truncated string when + * parsing. */ + g_string_append(gstr, "\\u0000"); + } else { + /* the character is not valid UTF-8. There is nothing we can do about it, because + * JSON can only contain UTF-8 and even the escape sequences can only escape Unicode + * codepoints (but not binary). + * + * 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 :) */ + g_string_append_c(gstr, '_'); + } + + n = str - end; + nm_assert(n < len); + n++; + str += n; + len -= n; + } + + g_string_append_c(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); + g_return_if_fail(gstr); - _gstr_append_string_len (gstr, str, n); + _gstr_append_string_len(gstr, str, n); } 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); + g_return_if_fail(gstr); - if (!str) - g_string_append (gstr, "null"); - else - _gstr_append_string_len (gstr, str, strlen (str)); + if (!str) + g_string_append(gstr, "null"); + else + _gstr_append_string_len(gstr, str, strlen(str)); } 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_gstr_append_string(gstr, key); + + if (start_container != '\0') { + nm_assert(NM_IN_SET(start_container, '[', '{')); + g_string_append_printf(gstr, ": %c ", start_container); + } 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) { - g_return_if_fail (gstr); - g_return_if_fail (key); + 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(); - nm_json_aux_gstr_append_string (gstr, key); + if (v_old) { + if (v_old->dl_handle) + dlclose(v_old->dl_handle); + g_free((gpointer *) v_old); + } - if (start_container != '\0') { - nm_assert (NM_IN_SET (start_container, '[', '{')); - g_string_append_printf (gstr, ": %c ", start_container); - } else - g_string_append (gstr, ": "); + 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 ed3be376..348f0f58 100644 --- a/shared/nm-glib-aux/nm-json-aux.h +++ b/shared/nm-glib-aux/nm-json-aux.h @@ -1,69 +1,312 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* 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; + 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"); + 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); + 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); /*****************************************************************************/ -#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS -#include "nm-value-type.h" +#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_value_type_to_json (NMValueType value_type, - GString *gstr, - gconstpointer p_field) +_nm_auto_decref_json(nm_json_t **p_json) { - nm_assert (p_field); - 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_UNSPEC: - break; - } - nm_assert_not_reached (); + if (*p_json && (*p_json)->refcount != (size_t) -1 && --(*p_json)->refcount == 0) + nm_json_vt()->nm_json_delete(*p_json); } -#endif + +#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)))) /*****************************************************************************/ -#endif /* __NM_JSON_AUX_H__ */ +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 + +static inline void +nm_value_type_to_json(NMValueType value_type, GString *gstr, gconstpointer p_field) +{ + nm_assert(p_field); + nm_assert(gstr); + + switch (value_type) { + 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(); +} + +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__ */ diff --git a/shared/nm-glib-aux/nm-keyfile-aux.c b/shared/nm-glib-aux/nm-keyfile-aux.c index 8b2af7a8..ae90fb0d 100644 --- a/shared/nm-glib-aux/nm-keyfile-aux.c +++ b/shared/nm-glib-aux/nm-keyfile-aux.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2019 Red Hat, Inc. */ @@ -16,119 +16,112 @@ /*****************************************************************************/ struct _NMKeyFileDB { - NMKeyFileDBLogFcn log_fcn; - NMKeyFileDBGotDirtyFcn got_dirty_fcn; - gpointer user_data; - const char *group_name; - GKeyFile *kf; - guint ref_count; - - bool is_started:1; - bool dirty:1; - bool destroyed:1; - - char filename[]; + NMKeyFileDBLogFcn log_fcn; + NMKeyFileDBGotDirtyFcn got_dirty_fcn; + gpointer user_data; + const char * group_name; + GKeyFile * kf; + guint ref_count; + + bool is_started : 1; + bool dirty : 1; + bool destroyed : 1; + + char filename[]; }; -#define _NMLOG(self, \ - syslog_level, \ - fmt, \ - ...) \ - G_STMT_START { \ - NMKeyFileDB *_self = (self); \ - \ - nm_assert (_self); \ - nm_assert (!_self->destroyed); \ - \ - if (_self->log_fcn) { \ - _self->log_fcn (_self, \ - (syslog_level), \ - _self->user_data, \ - ""fmt"", \ - ##__VA_ARGS__); \ - }; \ - } G_STMT_END - -#define _LOGD(...) _NMLOG (self, LOG_DEBUG, __VA_ARGS__) +#define _NMLOG(self, syslog_level, fmt, ...) \ + G_STMT_START \ + { \ + NMKeyFileDB *_self = (self); \ + \ + nm_assert(_self); \ + nm_assert(!_self->destroyed); \ + \ + if (_self->log_fcn) { \ + _self->log_fcn(_self, (syslog_level), _self->user_data, "" fmt "", ##__VA_ARGS__); \ + }; \ + } \ + G_STMT_END + +#define _LOGD(...) _NMLOG(self, LOG_DEBUG, __VA_ARGS__) static gboolean -_IS_KEY_FILE_DB (NMKeyFileDB *self, gboolean require_is_started, gboolean allow_destroyed) +_IS_KEY_FILE_DB(NMKeyFileDB *self, gboolean require_is_started, gboolean allow_destroyed) { - if (self == NULL) - return FALSE; - if (self->ref_count <= 0) { - nm_assert_not_reached (); - return FALSE; - } - if ( require_is_started - && !self->is_started) - return FALSE; - if ( !allow_destroyed - && self->destroyed) - return FALSE; - return TRUE; + if (self == NULL) + return FALSE; + if (self->ref_count <= 0) { + nm_assert_not_reached(); + return FALSE; + } + if (require_is_started && !self->is_started) + return FALSE; + if (!allow_destroyed && self->destroyed) + return FALSE; + return TRUE; } /*****************************************************************************/ NMKeyFileDB * -nm_key_file_db_new (const char *filename, - const char *group_name, - NMKeyFileDBLogFcn log_fcn, - NMKeyFileDBGotDirtyFcn got_dirty_fcn, - gpointer user_data) +nm_key_file_db_new(const char * filename, + const char * group_name, + NMKeyFileDBLogFcn log_fcn, + NMKeyFileDBGotDirtyFcn got_dirty_fcn, + gpointer user_data) { - NMKeyFileDB *self; - gsize l_filename; - gsize l_group; - - g_return_val_if_fail (filename && filename[0], NULL); - g_return_val_if_fail (group_name && group_name[0], NULL); - - l_filename = strlen (filename); - l_group = strlen (group_name); - - self = g_malloc0 (sizeof (NMKeyFileDB) + l_filename + 1 + l_group + 1); - self->ref_count = 1; - self->log_fcn = log_fcn; - self->got_dirty_fcn = got_dirty_fcn; - self->user_data = user_data; - self->kf = g_key_file_new (); - g_key_file_set_list_separator (self->kf, ','); - memcpy (self->filename, filename, l_filename + 1); - self->group_name = &self->filename[l_filename + 1]; - memcpy ((char *) self->group_name, group_name, l_group + 1); - - return self; + NMKeyFileDB *self; + gsize l_filename; + gsize l_group; + + g_return_val_if_fail(filename && filename[0], NULL); + g_return_val_if_fail(group_name && group_name[0], NULL); + + l_filename = strlen(filename); + l_group = strlen(group_name); + + self = g_malloc0(sizeof(NMKeyFileDB) + l_filename + 1 + l_group + 1); + self->ref_count = 1; + self->log_fcn = log_fcn; + self->got_dirty_fcn = got_dirty_fcn; + self->user_data = user_data; + self->kf = g_key_file_new(); + g_key_file_set_list_separator(self->kf, ','); + memcpy(self->filename, filename, l_filename + 1); + self->group_name = &self->filename[l_filename + 1]; + memcpy((char *) self->group_name, group_name, l_group + 1); + + return self; } NMKeyFileDB * -nm_key_file_db_ref (NMKeyFileDB *self) +nm_key_file_db_ref(NMKeyFileDB *self) { - if (!self) - return NULL; + if (!self) + return NULL; - g_return_val_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE), NULL); + g_return_val_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE), NULL); - nm_assert (self->ref_count < G_MAXUINT); - self->ref_count++; - return self; + nm_assert(self->ref_count < G_MAXUINT); + self->ref_count++; + return self; } void -nm_key_file_db_unref (NMKeyFileDB *self) +nm_key_file_db_unref(NMKeyFileDB *self) { - if (!self) - return; + if (!self) + return; - g_return_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE)); + g_return_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE)); - if (--self->ref_count > 0) - return; + if (--self->ref_count > 0) + return; - g_key_file_unref (self->kf); + g_key_file_unref(self->kf); - g_free (self); + g_free(self); } /* destroy() is like unref, but it also makes the instance unusable. @@ -148,16 +141,16 @@ nm_key_file_db_unref (NMKeyFileDB *self) * asserting at that point. */ void -nm_key_file_db_destroy (NMKeyFileDB *self) +nm_key_file_db_destroy(NMKeyFileDB *self) { - if (!self) - return; + if (!self) + return; - g_return_if_fail (_IS_KEY_FILE_DB (self, FALSE, FALSE)); - g_return_if_fail (!self->destroyed); + g_return_if_fail(_IS_KEY_FILE_DB(self, FALSE, FALSE)); + g_return_if_fail(!self->destroyed); - self->destroyed = TRUE; - nm_key_file_db_unref (self); + self->destroyed = TRUE; + nm_key_file_db_unref(self); } /*****************************************************************************/ @@ -169,229 +162,212 @@ nm_key_file_db_destroy (NMKeyFileDB *self) * and the log_fcn returns the self pointer (which we should not expose before * nm_key_file_db_new() returns. */ void -nm_key_file_db_start (NMKeyFileDB *self) +nm_key_file_db_start(NMKeyFileDB *self) { - gs_free char *contents = NULL; - gsize contents_len; - gs_free_error GError *error = NULL; - - g_return_if_fail (_IS_KEY_FILE_DB (self, FALSE, FALSE)); - g_return_if_fail (!self->is_started); - - self->is_started = TRUE; - - if (!nm_utils_file_get_contents (-1, - self->filename, - 20*1024*1024, - NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, - &contents, - &contents_len, - NULL, - &error)) { - _LOGD ("failed to read \"%s\": %s", self->filename, error->message); - return; - } - - if (!g_key_file_load_from_data (self->kf, - contents, - contents_len, - G_KEY_FILE_KEEP_COMMENTS, - &error)) { - _LOGD ("failed to load keyfile \"%s\": %s", self->filename, error->message); - return; - } - - _LOGD ("loaded keyfile-db for \"%s\"", self->filename); + gs_free char *contents = NULL; + gsize contents_len; + gs_free_error GError *error = NULL; + + g_return_if_fail(_IS_KEY_FILE_DB(self, FALSE, FALSE)); + g_return_if_fail(!self->is_started); + + self->is_started = TRUE; + + if (!nm_utils_file_get_contents(-1, + self->filename, + 20 * 1024 * 1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, + &contents_len, + NULL, + &error)) { + _LOGD("failed to read \"%s\": %s", self->filename, error->message); + return; + } + + if (!g_key_file_load_from_data(self->kf, + contents, + contents_len, + G_KEY_FILE_KEEP_COMMENTS, + &error)) { + _LOGD("failed to load keyfile \"%s\": %s", self->filename, error->message); + return; + } + + _LOGD("loaded keyfile-db for \"%s\"", self->filename); } /*****************************************************************************/ const char * -nm_key_file_db_get_filename (NMKeyFileDB *self) +nm_key_file_db_get_filename(NMKeyFileDB *self) { - g_return_val_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE), NULL); + g_return_val_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE), NULL); - return self->filename; + return self->filename; } gboolean -nm_key_file_db_is_dirty (NMKeyFileDB *self) +nm_key_file_db_is_dirty(NMKeyFileDB *self) { - g_return_val_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE), FALSE); + g_return_val_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE), FALSE); - return self->dirty; + return self->dirty; } /*****************************************************************************/ char * -nm_key_file_db_get_value (NMKeyFileDB *self, - const char *key) +nm_key_file_db_get_value(NMKeyFileDB *self, const char *key) { - g_return_val_if_fail (_IS_KEY_FILE_DB (self, TRUE, TRUE), NULL); + g_return_val_if_fail(_IS_KEY_FILE_DB(self, TRUE, TRUE), NULL); - return g_key_file_get_value (self->kf, self->group_name, key, NULL); + return g_key_file_get_value(self->kf, self->group_name, key, NULL); } char ** -nm_key_file_db_get_string_list (NMKeyFileDB *self, - const char *key, - gsize *out_len) +nm_key_file_db_get_string_list(NMKeyFileDB *self, const char *key, gsize *out_len) { - g_return_val_if_fail (_IS_KEY_FILE_DB (self, TRUE, TRUE), NULL); + g_return_val_if_fail(_IS_KEY_FILE_DB(self, TRUE, TRUE), NULL); - return g_key_file_get_string_list (self->kf, self->group_name, key, out_len, NULL); + return g_key_file_get_string_list(self->kf, self->group_name, key, out_len, NULL); } /*****************************************************************************/ static void -_got_dirty (NMKeyFileDB *self, - const char *key) +_got_dirty(NMKeyFileDB *self, const char *key) { - nm_assert (_IS_KEY_FILE_DB (self, TRUE, FALSE)); - nm_assert (!self->dirty); + nm_assert(_IS_KEY_FILE_DB(self, TRUE, FALSE)); + nm_assert(!self->dirty); - _LOGD ("updated entry for %s.%s", self->group_name, key); + _LOGD("updated entry for %s.%s", self->group_name, key); - self->dirty = TRUE; - if (self->got_dirty_fcn) - self->got_dirty_fcn (self, self->user_data); + self->dirty = TRUE; + if (self->got_dirty_fcn) + self->got_dirty_fcn(self, self->user_data); } /*****************************************************************************/ void -nm_key_file_db_remove_key (NMKeyFileDB *self, - const char *key) +nm_key_file_db_remove_key(NMKeyFileDB *self, const char *key) { - gboolean got_dirty = FALSE; + gboolean got_dirty = FALSE; - g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE)); - if (!key) - return; + if (!key) + return; - if (!self->dirty) { - gs_free_error GError *error = NULL; + if (!self->dirty) { + gs_free_error GError *error = NULL; - g_key_file_has_key (self->kf, self->group_name, key, &error); - got_dirty = (error != NULL); - } - g_key_file_remove_key (self->kf, self->group_name, key, NULL); + g_key_file_has_key(self->kf, self->group_name, key, &error); + got_dirty = (error != NULL); + } + g_key_file_remove_key(self->kf, self->group_name, key, NULL); - if (got_dirty) - _got_dirty (self, key); + if (got_dirty) + _got_dirty(self, key); } void -nm_key_file_db_set_value (NMKeyFileDB *self, - const char *key, - const char *value) +nm_key_file_db_set_value(NMKeyFileDB *self, const char *key, const char *value) { - gs_free char *old_value = NULL; - gboolean got_dirty = FALSE; + gs_free char *old_value = NULL; + gboolean got_dirty = FALSE; - g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); - g_return_if_fail (key); + g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE)); + g_return_if_fail(key); - if (!value) { - nm_key_file_db_remove_key (self, key); - return; - } + if (!value) { + nm_key_file_db_remove_key(self, key); + return; + } - if (!self->dirty) { - gs_free_error GError *error = NULL; + if (!self->dirty) { + gs_free_error GError *error = NULL; - old_value = g_key_file_get_value (self->kf, self->group_name, key, &error); - if (error) - got_dirty = TRUE; - } + old_value = g_key_file_get_value(self->kf, self->group_name, key, &error); + if (error) + got_dirty = TRUE; + } - g_key_file_set_value (self->kf, self->group_name, key, value); + g_key_file_set_value(self->kf, self->group_name, key, value); - if ( !self->dirty - && !got_dirty) { - gs_free_error GError *error = NULL; - gs_free char *new_value = NULL; + if (!self->dirty && !got_dirty) { + gs_free_error GError *error = NULL; + gs_free char * new_value = NULL; - new_value = g_key_file_get_value (self->kf, self->group_name, key, &error); - if ( error - || !new_value - || !nm_streq0 (old_value, new_value)) - got_dirty = TRUE; - } + new_value = g_key_file_get_value(self->kf, self->group_name, key, &error); + if (error || !new_value || !nm_streq0(old_value, new_value)) + got_dirty = TRUE; + } - if (got_dirty) - _got_dirty (self, key); + if (got_dirty) + _got_dirty(self, key); } void -nm_key_file_db_set_string_list (NMKeyFileDB *self, - const char *key, - const char *const*value, - gssize len) +nm_key_file_db_set_string_list(NMKeyFileDB * self, + const char * key, + const char *const *value, + gssize len) { - gs_free char *old_value = NULL; - gboolean got_dirty = FALSE;; + gs_free char *old_value = NULL; + gboolean got_dirty = FALSE; - g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); - g_return_if_fail (key); + g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE)); + g_return_if_fail(key); - if (!value) { - nm_key_file_db_remove_key (self, key); - return; - } + if (!value) { + nm_key_file_db_remove_key(self, key); + return; + } - if (!self->dirty) { - gs_free_error GError *error = NULL; + if (!self->dirty) { + gs_free_error GError *error = NULL; - old_value = g_key_file_get_value (self->kf, self->group_name, key, &error); - if (error) - got_dirty = TRUE; - } + old_value = g_key_file_get_value(self->kf, self->group_name, key, &error); + if (error) + got_dirty = TRUE; + } - if (len < 0) - len = NM_PTRARRAY_LEN (value); + if (len < 0) + len = NM_PTRARRAY_LEN(value); - g_key_file_set_string_list (self->kf, self->group_name, key, value, len); + g_key_file_set_string_list(self->kf, self->group_name, key, value, len); - if ( !self->dirty - && !got_dirty) { - gs_free_error GError *error = NULL; - gs_free char *new_value = NULL; + if (!self->dirty && !got_dirty) { + gs_free_error GError *error = NULL; + gs_free char * new_value = NULL; - new_value = g_key_file_get_value (self->kf, self->group_name, key, &error); - if ( error - || !new_value - || !nm_streq0 (old_value, new_value)) - got_dirty = TRUE; - } + new_value = g_key_file_get_value(self->kf, self->group_name, key, &error); + if (error || !new_value || !nm_streq0(old_value, new_value)) + got_dirty = TRUE; + } - if (got_dirty) - _got_dirty (self, key); + if (got_dirty) + _got_dirty(self, key); } /*****************************************************************************/ void -nm_key_file_db_to_file (NMKeyFileDB *self, - gboolean force) +nm_key_file_db_to_file(NMKeyFileDB *self, gboolean force) { - gs_free_error GError *error = NULL; + gs_free_error GError *error = NULL; - g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE)); - if ( !force - && !self->dirty) - return; + if (!force && !self->dirty) + return; - self->dirty = FALSE; + self->dirty = FALSE; - if (!g_key_file_save_to_file (self->kf, - self->filename, - &error)) { - _LOGD ("failure to write keyfile \"%s\": %s", self->filename, error->message); - } else - _LOGD ("write keyfile: \"%s\"", self->filename); + if (!g_key_file_save_to_file(self->kf, self->filename, &error)) { + _LOGD("failure to write keyfile \"%s\": %s", self->filename, error->message); + } else + _LOGD("write keyfile: \"%s\"", self->filename); } diff --git a/shared/nm-glib-aux/nm-keyfile-aux.h b/shared/nm-glib-aux/nm-keyfile-aux.h index 0f729c72..198a2c53 100644 --- a/shared/nm-glib-aux/nm-keyfile-aux.h +++ b/shared/nm-glib-aux/nm-keyfile-aux.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2019 Red Hat, Inc. */ @@ -10,53 +10,45 @@ typedef struct _NMKeyFileDB NMKeyFileDB; -typedef void (*NMKeyFileDBLogFcn) (NMKeyFileDB *self, - int syslog_level, - gpointer user_data, - const char *fmt, - ...) G_GNUC_PRINTF (4, 5); +typedef void (*NMKeyFileDBLogFcn)(NMKeyFileDB *self, + int syslog_level, + gpointer user_data, + const char * fmt, + ...) G_GNUC_PRINTF(4, 5); -typedef void (*NMKeyFileDBGotDirtyFcn) (NMKeyFileDB *self, - gpointer user_data); +typedef void (*NMKeyFileDBGotDirtyFcn)(NMKeyFileDB *self, gpointer user_data); -NMKeyFileDB *nm_key_file_db_new (const char *filename, - const char *group, - NMKeyFileDBLogFcn log_fcn, - NMKeyFileDBGotDirtyFcn got_dirty_fcn, - gpointer user_data); +NMKeyFileDB *nm_key_file_db_new(const char * filename, + const char * group, + NMKeyFileDBLogFcn log_fcn, + NMKeyFileDBGotDirtyFcn got_dirty_fcn, + gpointer user_data); -void nm_key_file_db_start (NMKeyFileDB *self); +void nm_key_file_db_start(NMKeyFileDB *self); -NMKeyFileDB *nm_key_file_db_ref (NMKeyFileDB *self); -void nm_key_file_db_unref (NMKeyFileDB *self); +NMKeyFileDB *nm_key_file_db_ref(NMKeyFileDB *self); +void nm_key_file_db_unref(NMKeyFileDB *self); -void nm_key_file_db_destroy (NMKeyFileDB *self); +void nm_key_file_db_destroy(NMKeyFileDB *self); -const char *nm_key_file_db_get_filename (NMKeyFileDB *self); +const char *nm_key_file_db_get_filename(NMKeyFileDB *self); -gboolean nm_key_file_db_is_dirty (NMKeyFileDB *self); +gboolean nm_key_file_db_is_dirty(NMKeyFileDB *self); -char *nm_key_file_db_get_value (NMKeyFileDB *self, - const char *key); +char *nm_key_file_db_get_value(NMKeyFileDB *self, const char *key); -char **nm_key_file_db_get_string_list (NMKeyFileDB *self, - const char *key, - gsize *out_len); +char **nm_key_file_db_get_string_list(NMKeyFileDB *self, const char *key, gsize *out_len); -void nm_key_file_db_remove_key (NMKeyFileDB *self, - const char *key); +void nm_key_file_db_remove_key(NMKeyFileDB *self, const char *key); -void nm_key_file_db_set_value (NMKeyFileDB *self, - const char *key, - const char *value); +void nm_key_file_db_set_value(NMKeyFileDB *self, const char *key, const char *value); -void nm_key_file_db_set_string_list (NMKeyFileDB *self, - const char *key, - const char *const*value, - gssize len); +void nm_key_file_db_set_string_list(NMKeyFileDB * self, + const char * key, + const char *const *value, + gssize len); -void nm_key_file_db_to_file (NMKeyFileDB *self, - gboolean force); +void nm_key_file_db_to_file(NMKeyFileDB *self, gboolean force); /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-logging-base.c b/shared/nm-glib-aux/nm-logging-base.c index 47b3e993..229470f6 100644 --- a/shared/nm-glib-aux/nm-logging-base.c +++ b/shared/nm-glib-aux/nm-logging-base.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -9,30 +9,71 @@ /*****************************************************************************/ const LogLevelDesc level_desc[_LOGL_N] = { - [LOGL_TRACE] = { "TRACE", "<trace>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, - [LOGL_DEBUG] = { "DEBUG", "<debug>", LOG_DEBUG, G_LOG_LEVEL_DEBUG, }, - [LOGL_INFO] = { "INFO", "<info>", LOG_INFO, G_LOG_LEVEL_INFO, }, - [LOGL_WARN] = { "WARN", "<warn>", LOG_WARNING, G_LOG_LEVEL_MESSAGE, }, - [LOGL_ERR] = { "ERR", "<error>", LOG_ERR, G_LOG_LEVEL_MESSAGE, }, - [_LOGL_OFF] = { "OFF", NULL, 0, 0, }, - [_LOGL_KEEP] = { "KEEP", NULL, 0, 0, }, + [LOGL_TRACE] = + { + "TRACE", + "<trace>", + LOG_DEBUG, + G_LOG_LEVEL_DEBUG, + }, + [LOGL_DEBUG] = + { + "DEBUG", + "<debug>", + LOG_DEBUG, + G_LOG_LEVEL_DEBUG, + }, + [LOGL_INFO] = + { + "INFO", + "<info>", + LOG_INFO, + G_LOG_LEVEL_INFO, + }, + [LOGL_WARN] = + { + "WARN", + "<warn>", + LOG_WARNING, + G_LOG_LEVEL_MESSAGE, + }, + [LOGL_ERR] = + { + "ERR", + "<error>", + LOG_ERR, + G_LOG_LEVEL_MESSAGE, + }, + [_LOGL_OFF] = + { + "OFF", + NULL, + 0, + 0, + }, + [_LOGL_KEEP] = + { + "KEEP", + NULL, + 0, + 0, + }, }; gboolean -_nm_log_parse_level (const char *level, - NMLogLevel *out_level) +_nm_log_parse_level(const char *level, NMLogLevel *out_level) { - int i; + int i; - if (!level) - return FALSE; + if (!level) + return FALSE; - for (i = 0; i < (int) G_N_ELEMENTS (level_desc); i++) { - if (!g_ascii_strcasecmp (level_desc[i].name, level)) { - NM_SET_OUT (out_level, i); - return TRUE; - } - } + for (i = 0; i < (int) G_N_ELEMENTS(level_desc); i++) { + if (!g_ascii_strcasecmp(level_desc[i].name, level)) { + NM_SET_OUT(out_level, i); + return TRUE; + } + } - return FALSE; + return FALSE; } diff --git a/shared/nm-glib-aux/nm-logging-base.h b/shared/nm-glib-aux/nm-logging-base.h index 3d964a6e..eb71c2a4 100644 --- a/shared/nm-glib-aux/nm-logging-base.h +++ b/shared/nm-glib-aux/nm-logging-base.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NM_LOGGING_BASE_H__ #define __NM_LOGGING_BASE_H__ @@ -6,24 +6,23 @@ #include "nm-logging-fwd.h" typedef struct { - const char *name; - const char *level_str; - - /* nm-logging uses syslog internally. Note that the three most-verbose syslog levels - * are LOG_DEBUG, LOG_INFO and LOG_NOTICE. Journal already highlights LOG_NOTICE - * as special. - * - * On the other hand, we have three levels LOGL_TRACE, LOGL_DEBUG and LOGL_INFO, - * which are regular messages not to be highlighted. For that reason, we must map - * LOGL_TRACE and LOGL_DEBUG both to syslog level LOG_DEBUG. */ - int syslog_level; - - GLogLevelFlags g_log_level; + const char *name; + const char *level_str; + + /* nm-logging uses syslog internally. Note that the three most-verbose syslog levels + * are LOG_DEBUG, LOG_INFO and LOG_NOTICE. Journal already highlights LOG_NOTICE + * as special. + * + * On the other hand, we have three levels LOGL_TRACE, LOGL_DEBUG and LOGL_INFO, + * which are regular messages not to be highlighted. For that reason, we must map + * LOGL_TRACE and LOGL_DEBUG both to syslog level LOG_DEBUG. */ + int syslog_level; + + GLogLevelFlags g_log_level; } LogLevelDesc; extern const LogLevelDesc level_desc[_LOGL_N]; -gboolean _nm_log_parse_level (const char *level, - NMLogLevel *out_level); +gboolean _nm_log_parse_level(const char *level, NMLogLevel *out_level); #endif /* __NM_LOGGING_BASE_H__ */ diff --git a/shared/nm-glib-aux/nm-logging-fwd.h b/shared/nm-glib-aux/nm-logging-fwd.h index 2daa302f..ee75b713 100644 --- a/shared/nm-glib-aux/nm-logging-fwd.h +++ b/shared/nm-glib-aux/nm-logging-fwd.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2006 - 2018 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -9,128 +9,136 @@ /* Log domains */ -typedef enum { /*< skip >*/ - LOGD_NONE = 0LL, - LOGD_PLATFORM = (1LL << 0), /* Platform services */ - LOGD_RFKILL = (1LL << 1), - LOGD_ETHER = (1LL << 2), - LOGD_WIFI = (1LL << 3), - LOGD_BT = (1LL << 4), - LOGD_MB = (1LL << 5), /* mobile broadband */ - LOGD_DHCP4 = (1LL << 6), - LOGD_DHCP6 = (1LL << 7), - LOGD_PPP = (1LL << 8), - LOGD_WIFI_SCAN = (1LL << 9), - LOGD_IP4 = (1LL << 10), - LOGD_IP6 = (1LL << 11), - LOGD_AUTOIP4 = (1LL << 12), - LOGD_DNS = (1LL << 13), - LOGD_VPN = (1LL << 14), - LOGD_SHARING = (1LL << 15), /* Connection sharing/dnsmasq */ - LOGD_SUPPLICANT = (1LL << 16), /* Wi-Fi and 802.1x */ - LOGD_AGENTS = (1LL << 17), /* Secret agents */ - LOGD_SETTINGS = (1LL << 18), /* Settings */ - LOGD_SUSPEND = (1LL << 19), /* Suspend/Resume */ - LOGD_CORE = (1LL << 20), /* Core daemon and policy stuff */ - LOGD_DEVICE = (1LL << 21), /* Device state and activation */ - LOGD_OLPC = (1LL << 22), - LOGD_INFINIBAND = (1LL << 23), - LOGD_FIREWALL = (1LL << 24), - LOGD_ADSL = (1LL << 25), - LOGD_BOND = (1LL << 26), - LOGD_VLAN = (1LL << 27), - LOGD_BRIDGE = (1LL << 28), - LOGD_DBUS_PROPS = (1LL << 29), - LOGD_TEAM = (1LL << 30), - LOGD_CONCHECK = (1LL << 31), - LOGD_DCB = (1LL << 32), /* Data Center Bridging */ - LOGD_DISPATCH = (1LL << 33), - LOGD_AUDIT = (1LL << 34), - LOGD_SYSTEMD = (1LL << 35), - LOGD_VPN_PLUGIN = (1LL << 36), - LOGD_PROXY = (1LL << 37), - - __LOGD_MAX, - LOGD_ALL = (((__LOGD_MAX - 1LL) << 1) - 1LL), - LOGD_DEFAULT = LOGD_ALL & ~( - LOGD_DBUS_PROPS | - LOGD_WIFI_SCAN | - LOGD_VPN_PLUGIN | - 0), - - /* aliases: */ - LOGD_DHCP = LOGD_DHCP4 | LOGD_DHCP6, - LOGD_IP = LOGD_IP4 | LOGD_IP6, +typedef enum { /*< skip >*/ + LOGD_NONE = 0LL, + LOGD_PLATFORM = (1LL << 0), /* Platform services */ + LOGD_RFKILL = (1LL << 1), + LOGD_ETHER = (1LL << 2), + LOGD_WIFI = (1LL << 3), + LOGD_BT = (1LL << 4), + LOGD_MB = (1LL << 5), /* mobile broadband */ + LOGD_DHCP4 = (1LL << 6), + LOGD_DHCP6 = (1LL << 7), + LOGD_PPP = (1LL << 8), + LOGD_WIFI_SCAN = (1LL << 9), + LOGD_IP4 = (1LL << 10), + LOGD_IP6 = (1LL << 11), + LOGD_AUTOIP4 = (1LL << 12), + LOGD_DNS = (1LL << 13), + LOGD_VPN = (1LL << 14), + LOGD_SHARING = (1LL << 15), /* Connection sharing/dnsmasq */ + LOGD_SUPPLICANT = (1LL << 16), /* Wi-Fi and 802.1x */ + LOGD_AGENTS = (1LL << 17), /* Secret agents */ + LOGD_SETTINGS = (1LL << 18), /* Settings */ + LOGD_SUSPEND = (1LL << 19), /* Suspend/Resume */ + LOGD_CORE = (1LL << 20), /* Core daemon and policy stuff */ + LOGD_DEVICE = (1LL << 21), /* Device state and activation */ + LOGD_OLPC = (1LL << 22), + LOGD_INFINIBAND = (1LL << 23), + LOGD_FIREWALL = (1LL << 24), + LOGD_ADSL = (1LL << 25), + LOGD_BOND = (1LL << 26), + LOGD_VLAN = (1LL << 27), + LOGD_BRIDGE = (1LL << 28), + LOGD_DBUS_PROPS = (1LL << 29), + LOGD_TEAM = (1LL << 30), + LOGD_CONCHECK = (1LL << 31), + LOGD_DCB = (1LL << 32), /* Data Center Bridging */ + LOGD_DISPATCH = (1LL << 33), + LOGD_AUDIT = (1LL << 34), + LOGD_SYSTEMD = (1LL << 35), + LOGD_VPN_PLUGIN = (1LL << 36), + LOGD_PROXY = (1LL << 37), + + __LOGD_MAX, + LOGD_ALL = (((__LOGD_MAX - 1LL) << 1) - 1LL), + LOGD_DEFAULT = LOGD_ALL & ~(LOGD_DBUS_PROPS | LOGD_WIFI_SCAN | LOGD_VPN_PLUGIN | 0), + + /* aliases: */ + LOGD_DHCP = LOGD_DHCP4 | LOGD_DHCP6, + LOGD_IP = LOGD_IP4 | LOGD_IP6, } NMLogDomain; static inline NMLogDomain -LOGD_DHCP_from_addr_family (int addr_family) +LOGD_DHCP_from_addr_family(int addr_family) { - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - return addr_family == AF_INET6 ? LOGD_DHCP6 : LOGD_DHCP4; + return addr_family == AF_INET6 ? LOGD_DHCP6 : LOGD_DHCP4; } /* Log levels */ -typedef enum { /*< skip >*/ - LOGL_TRACE, - LOGL_DEBUG, - LOGL_INFO, - LOGL_WARN, - LOGL_ERR, +typedef enum { /*< skip >*/ + LOGL_TRACE, + LOGL_DEBUG, + LOGL_INFO, + LOGL_WARN, + LOGL_ERR, - _LOGL_N_REAL, /* the number of actual logging levels */ + _LOGL_N_REAL, /* the number of actual logging levels */ - _LOGL_OFF = _LOGL_N_REAL, /* special logging level that is always disabled. */ - _LOGL_KEEP, /* special logging level to indicate that the logging level should not be changed. */ + _LOGL_OFF = _LOGL_N_REAL, /* special logging level that is always disabled. */ + _LOGL_KEEP, /* special logging level to indicate that the logging level should not be changed. */ - _LOGL_N, /* the number of logging levels including "OFF" */ + _LOGL_N, /* the number of logging levels including "OFF" */ } NMLogLevel; -gboolean _nm_log_enabled_impl (gboolean mt_require_locking, - NMLogLevel level, - NMLogDomain domain); - -void _nm_log_impl (const char *file, - guint line, - const char *func, - gboolean mt_require_locking, - NMLogLevel level, - NMLogDomain domain, - int error, - const char *ifname, - const char *con_uuid, - const char *fmt, - ...) _nm_printf (10, 11); +gboolean _nm_log_enabled_impl(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain); + +void _nm_log_impl(const char *file, + guint line, + const char *func, + gboolean mt_require_locking, + NMLogLevel level, + NMLogDomain domain, + int error, + const char *ifname, + const char *con_uuid, + const char *fmt, + ...) _nm_printf(10, 11); static inline NMLogLevel -nm_log_level_from_syslog (int syslog_level) +nm_log_level_from_syslog(int syslog_level) { - switch (syslog_level) { - case 0 /* LOG_EMERG */ : return LOGL_ERR; - case 1 /* LOG_ALERT */ : return LOGL_ERR; - case 2 /* LOG_CRIT */ : return LOGL_ERR; - case 3 /* LOG_ERR */ : return LOGL_ERR; - case 4 /* LOG_WARNING */ : return LOGL_WARN; - case 5 /* LOG_NOTICE */ : return LOGL_INFO; - case 6 /* LOG_INFO */ : return LOGL_DEBUG; - case 7 /* LOG_DEBUG */ : return LOGL_TRACE; - default: - return syslog_level >= 0 ? LOGL_TRACE : LOGL_ERR; - } + switch (syslog_level) { + case 0 /* LOG_EMERG */: + return LOGL_ERR; + case 1 /* LOG_ALERT */: + return LOGL_ERR; + case 2 /* LOG_CRIT */: + return LOGL_ERR; + case 3 /* LOG_ERR */: + return LOGL_ERR; + case 4 /* LOG_WARNING */: + return LOGL_WARN; + case 5 /* LOG_NOTICE */: + return LOGL_INFO; + case 6 /* LOG_INFO */: + return LOGL_DEBUG; + case 7 /* LOG_DEBUG */: + return LOGL_TRACE; + default: + return syslog_level >= 0 ? LOGL_TRACE : LOGL_ERR; + } } static inline int -nm_log_level_to_syslog (NMLogLevel nm_level) +nm_log_level_to_syslog(NMLogLevel nm_level) { - switch (nm_level) { - case LOGL_ERR: return 3; /* LOG_ERR */ - case LOGL_WARN: return 4; /* LOG_WARN */ - case LOGL_INFO: return 5; /* LOG_NOTICE */ - case LOGL_DEBUG: return 6; /* LOG_INFO */ - case LOGL_TRACE: return 7; /* LOG_DEBUG */ - default: return 0; /* LOG_EMERG */ - } + switch (nm_level) { + case LOGL_ERR: + return 3; /* LOG_ERR */ + case LOGL_WARN: + return 4; /* LOG_WARN */ + case LOGL_INFO: + return 5; /* LOG_NOTICE */ + case LOGL_DEBUG: + return 6; /* LOG_INFO */ + case LOGL_TRACE: + return 7; /* LOG_DEBUG */ + default: + return 0; /* LOG_EMERG */ + } } /*****************************************************************************/ @@ -139,9 +147,9 @@ struct timespec; /* this function must be implemented to handle the notification when * the first monotonic-timestamp is fetched. */ -extern void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp, - gint64 offset_sec, - gboolean is_boottime); +extern void _nm_utils_monotonic_timestamp_initialized(const struct timespec *tp, + gint64 offset_sec, + gboolean is_boottime); /*****************************************************************************/ @@ -153,37 +161,51 @@ extern void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp /* This is the default definition of _NMLOG_ENABLED(). Special implementations * might want to undef this and redefine it. */ -#define _NMLOG_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG_DOMAIN)) ) - -#define _LOGT(...) _NMLOG (_LOGL_TRACE, __VA_ARGS__) -#define _LOGD(...) _NMLOG (_LOGL_DEBUG, __VA_ARGS__) -#define _LOGI(...) _NMLOG (_LOGL_INFO , __VA_ARGS__) -#define _LOGW(...) _NMLOG (_LOGL_WARN , __VA_ARGS__) -#define _LOGE(...) _NMLOG (_LOGL_ERR , __VA_ARGS__) - -#define _LOGT_ENABLED(...) _NMLOG_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) -#define _LOGD_ENABLED(...) _NMLOG_ENABLED (_LOGL_DEBUG, ##__VA_ARGS__) -#define _LOGI_ENABLED(...) _NMLOG_ENABLED (_LOGL_INFO , ##__VA_ARGS__) -#define _LOGW_ENABLED(...) _NMLOG_ENABLED (_LOGL_WARN , ##__VA_ARGS__) -#define _LOGE_ENABLED(...) _NMLOG_ENABLED (_LOGL_ERR , ##__VA_ARGS__) - -#define _LOGT_err(errsv, ...) _NMLOG_err (errsv, _LOGL_TRACE, __VA_ARGS__) -#define _LOGD_err(errsv, ...) _NMLOG_err (errsv, _LOGL_DEBUG, __VA_ARGS__) -#define _LOGI_err(errsv, ...) _NMLOG_err (errsv, _LOGL_INFO , __VA_ARGS__) -#define _LOGW_err(errsv, ...) _NMLOG_err (errsv, _LOGL_WARN , __VA_ARGS__) -#define _LOGE_err(errsv, ...) _NMLOG_err (errsv, _LOGL_ERR , __VA_ARGS__) +#define _NMLOG_ENABLED(level) (nm_logging_enabled((level), (_NMLOG_DOMAIN))) + +#define _LOGT(...) _NMLOG(_LOGL_TRACE, __VA_ARGS__) +#define _LOGD(...) _NMLOG(_LOGL_DEBUG, __VA_ARGS__) +#define _LOGI(...) _NMLOG(_LOGL_INFO, __VA_ARGS__) +#define _LOGW(...) _NMLOG(_LOGL_WARN, __VA_ARGS__) +#define _LOGE(...) _NMLOG(_LOGL_ERR, __VA_ARGS__) + +#define _LOGT_ENABLED(...) _NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__) +#define _LOGD_ENABLED(...) _NMLOG_ENABLED(_LOGL_DEBUG, ##__VA_ARGS__) +#define _LOGI_ENABLED(...) _NMLOG_ENABLED(_LOGL_INFO, ##__VA_ARGS__) +#define _LOGW_ENABLED(...) _NMLOG_ENABLED(_LOGL_WARN, ##__VA_ARGS__) +#define _LOGE_ENABLED(...) _NMLOG_ENABLED(_LOGL_ERR, ##__VA_ARGS__) + +#define _LOGT_err(errsv, ...) _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__) +#define _LOGD_err(errsv, ...) _NMLOG_err(errsv, _LOGL_DEBUG, __VA_ARGS__) +#define _LOGI_err(errsv, ...) _NMLOG_err(errsv, _LOGL_INFO, __VA_ARGS__) +#define _LOGW_err(errsv, ...) _NMLOG_err(errsv, _LOGL_WARN, __VA_ARGS__) +#define _LOGE_err(errsv, ...) _NMLOG_err(errsv, _LOGL_ERR, __VA_ARGS__) /* _LOGT() and _LOGt() both log with level TRACE, but the latter is disabled by default, * unless building with --with-more-logging. */ #if NM_MORE_LOGGING -#define _LOGt_ENABLED(...) _NMLOG_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) -#define _LOGt(...) _NMLOG (_LOGL_TRACE, __VA_ARGS__) -#define _LOGt_err(errsv, ...) _NMLOG_err (errsv, _LOGL_TRACE, __VA_ARGS__) + #define _LOGt_ENABLED(...) _NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__) + #define _LOGt(...) _NMLOG(_LOGL_TRACE, __VA_ARGS__) + #define _LOGt_err(errsv, ...) _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__) #else -/* still call the logging macros to get compile time checks, but they will be optimized out. */ -#define _LOGt_ENABLED(...) ( FALSE && (_NMLOG_ENABLED (_LOGL_TRACE, ##__VA_ARGS__)) ) -#define _LOGt(...) G_STMT_START { if (FALSE) { _NMLOG (_LOGL_TRACE, __VA_ARGS__); } } G_STMT_END -#define _LOGt_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG_err (errsv, _LOGL_TRACE, __VA_ARGS__); } } G_STMT_END + /* still call the logging macros to get compile time checks, but they will be optimized out. */ + #define _LOGt_ENABLED(...) (FALSE && (_NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__))) + #define _LOGt(...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + _NMLOG(_LOGL_TRACE, __VA_ARGS__); \ + } \ + } \ + G_STMT_END + #define _LOGt_err(errsv, ...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__); \ + } \ + } \ + G_STMT_END #endif /*****************************************************************************/ @@ -195,66 +217,94 @@ extern void _nm_utils_monotonic_timestamp_initialized (const struct timespec *tp * like _LOG2D(), _LOG2I(), etc. and have _LOG2t() which by default * is disabled at compile time. */ -#define _NMLOG2_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG2_DOMAIN)) ) +#define _NMLOG2_ENABLED(level) (nm_logging_enabled((level), (_NMLOG2_DOMAIN))) -#define _LOG2T(...) _NMLOG2 (_LOGL_TRACE, __VA_ARGS__) -#define _LOG2D(...) _NMLOG2 (_LOGL_DEBUG, __VA_ARGS__) -#define _LOG2I(...) _NMLOG2 (_LOGL_INFO , __VA_ARGS__) -#define _LOG2W(...) _NMLOG2 (_LOGL_WARN , __VA_ARGS__) -#define _LOG2E(...) _NMLOG2 (_LOGL_ERR , __VA_ARGS__) +#define _LOG2T(...) _NMLOG2(_LOGL_TRACE, __VA_ARGS__) +#define _LOG2D(...) _NMLOG2(_LOGL_DEBUG, __VA_ARGS__) +#define _LOG2I(...) _NMLOG2(_LOGL_INFO, __VA_ARGS__) +#define _LOG2W(...) _NMLOG2(_LOGL_WARN, __VA_ARGS__) +#define _LOG2E(...) _NMLOG2(_LOGL_ERR, __VA_ARGS__) -#define _LOG2T_ENABLED(...) _NMLOG2_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) -#define _LOG2D_ENABLED(...) _NMLOG2_ENABLED (_LOGL_DEBUG, ##__VA_ARGS__) -#define _LOG2I_ENABLED(...) _NMLOG2_ENABLED (_LOGL_INFO , ##__VA_ARGS__) -#define _LOG2W_ENABLED(...) _NMLOG2_ENABLED (_LOGL_WARN , ##__VA_ARGS__) -#define _LOG2E_ENABLED(...) _NMLOG2_ENABLED (_LOGL_ERR , ##__VA_ARGS__) +#define _LOG2T_ENABLED(...) _NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__) +#define _LOG2D_ENABLED(...) _NMLOG2_ENABLED(_LOGL_DEBUG, ##__VA_ARGS__) +#define _LOG2I_ENABLED(...) _NMLOG2_ENABLED(_LOGL_INFO, ##__VA_ARGS__) +#define _LOG2W_ENABLED(...) _NMLOG2_ENABLED(_LOGL_WARN, ##__VA_ARGS__) +#define _LOG2E_ENABLED(...) _NMLOG2_ENABLED(_LOGL_ERR, ##__VA_ARGS__) -#define _LOG2T_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_TRACE, __VA_ARGS__) -#define _LOG2D_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_DEBUG, __VA_ARGS__) -#define _LOG2I_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_INFO , __VA_ARGS__) -#define _LOG2W_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_WARN , __VA_ARGS__) -#define _LOG2E_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_ERR , __VA_ARGS__) +#define _LOG2T_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__) +#define _LOG2D_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_DEBUG, __VA_ARGS__) +#define _LOG2I_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_INFO, __VA_ARGS__) +#define _LOG2W_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_WARN, __VA_ARGS__) +#define _LOG2E_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_ERR, __VA_ARGS__) #if NM_MORE_LOGGING -#define _LOG2t_ENABLED(...) _NMLOG2_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) -#define _LOG2t(...) _NMLOG2 (_LOGL_TRACE, __VA_ARGS__) -#define _LOG2t_err(errsv, ...) _NMLOG2_err (errsv, _LOGL_TRACE, __VA_ARGS__) + #define _LOG2t_ENABLED(...) _NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__) + #define _LOG2t(...) _NMLOG2(_LOGL_TRACE, __VA_ARGS__) + #define _LOG2t_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__) #else -/* still call the logging macros to get compile time checks, but they will be optimized out. */ -#define _LOG2t_ENABLED(...) ( FALSE && (_NMLOG2_ENABLED (_LOGL_TRACE, ##__VA_ARGS__)) ) -#define _LOG2t(...) G_STMT_START { if (FALSE) { _NMLOG2 (_LOGL_TRACE, __VA_ARGS__); } } G_STMT_END -#define _LOG2t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG2_err (errsv, _LOGL_TRACE, __VA_ARGS__); } } G_STMT_END + /* still call the logging macros to get compile time checks, but they will be optimized out. */ + #define _LOG2t_ENABLED(...) (FALSE && (_NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__))) + #define _LOG2t(...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + _NMLOG2(_LOGL_TRACE, __VA_ARGS__); \ + } \ + } \ + G_STMT_END + #define _LOG2t_err(errsv, ...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__); \ + } \ + } \ + G_STMT_END #endif -#define _NMLOG3_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG3_DOMAIN)) ) +#define _NMLOG3_ENABLED(level) (nm_logging_enabled((level), (_NMLOG3_DOMAIN))) -#define _LOG3T(...) _NMLOG3 (_LOGL_TRACE, __VA_ARGS__) -#define _LOG3D(...) _NMLOG3 (_LOGL_DEBUG, __VA_ARGS__) -#define _LOG3I(...) _NMLOG3 (_LOGL_INFO , __VA_ARGS__) -#define _LOG3W(...) _NMLOG3 (_LOGL_WARN , __VA_ARGS__) -#define _LOG3E(...) _NMLOG3 (_LOGL_ERR , __VA_ARGS__) +#define _LOG3T(...) _NMLOG3(_LOGL_TRACE, __VA_ARGS__) +#define _LOG3D(...) _NMLOG3(_LOGL_DEBUG, __VA_ARGS__) +#define _LOG3I(...) _NMLOG3(_LOGL_INFO, __VA_ARGS__) +#define _LOG3W(...) _NMLOG3(_LOGL_WARN, __VA_ARGS__) +#define _LOG3E(...) _NMLOG3(_LOGL_ERR, __VA_ARGS__) -#define _LOG3T_ENABLED(...) _NMLOG3_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) -#define _LOG3D_ENABLED(...) _NMLOG3_ENABLED (_LOGL_DEBUG, ##__VA_ARGS__) -#define _LOG3I_ENABLED(...) _NMLOG3_ENABLED (_LOGL_INFO , ##__VA_ARGS__) -#define _LOG3W_ENABLED(...) _NMLOG3_ENABLED (_LOGL_WARN , ##__VA_ARGS__) -#define _LOG3E_ENABLED(...) _NMLOG3_ENABLED (_LOGL_ERR , ##__VA_ARGS__) +#define _LOG3T_ENABLED(...) _NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__) +#define _LOG3D_ENABLED(...) _NMLOG3_ENABLED(_LOGL_DEBUG, ##__VA_ARGS__) +#define _LOG3I_ENABLED(...) _NMLOG3_ENABLED(_LOGL_INFO, ##__VA_ARGS__) +#define _LOG3W_ENABLED(...) _NMLOG3_ENABLED(_LOGL_WARN, ##__VA_ARGS__) +#define _LOG3E_ENABLED(...) _NMLOG3_ENABLED(_LOGL_ERR, ##__VA_ARGS__) -#define _LOG3T_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_TRACE, __VA_ARGS__) -#define _LOG3D_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_DEBUG, __VA_ARGS__) -#define _LOG3I_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_INFO , __VA_ARGS__) -#define _LOG3W_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_WARN , __VA_ARGS__) -#define _LOG3E_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_ERR , __VA_ARGS__) +#define _LOG3T_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__) +#define _LOG3D_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_DEBUG, __VA_ARGS__) +#define _LOG3I_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_INFO, __VA_ARGS__) +#define _LOG3W_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_WARN, __VA_ARGS__) +#define _LOG3E_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_ERR, __VA_ARGS__) #if NM_MORE_LOGGING -#define _LOG3t_ENABLED(...) _NMLOG3_ENABLED (_LOGL_TRACE, ##__VA_ARGS__) -#define _LOG3t(...) _NMLOG3 (_LOGL_TRACE, __VA_ARGS__) -#define _LOG3t_err(errsv, ...) _NMLOG3_err (errsv, _LOGL_TRACE, __VA_ARGS__) + #define _LOG3t_ENABLED(...) _NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__) + #define _LOG3t(...) _NMLOG3(_LOGL_TRACE, __VA_ARGS__) + #define _LOG3t_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__) #else -/* still call the logging macros to get compile time checks, but they will be optimized out. */ -#define _LOG3t_ENABLED(...) ( FALSE && (_NMLOG3_ENABLED (_LOGL_TRACE, ##__VA_ARGS__)) ) -#define _LOG3t(...) G_STMT_START { if (FALSE) { _NMLOG3 (_LOGL_TRACE, __VA_ARGS__); } } G_STMT_END -#define _LOG3t_err(errsv, ...) G_STMT_START { if (FALSE) { _NMLOG3_err (errsv, _LOGL_TRACE, __VA_ARGS__); } } G_STMT_END + /* still call the logging macros to get compile time checks, but they will be optimized out. */ + #define _LOG3t_ENABLED(...) (FALSE && (_NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__))) + #define _LOG3t(...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + _NMLOG3(_LOGL_TRACE, __VA_ARGS__); \ + } \ + } \ + G_STMT_END + #define _LOG3t_err(errsv, ...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__); \ + } \ + } \ + G_STMT_END #endif /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h index 15bcd7e5..db1597fa 100644 --- a/shared/nm-glib-aux/nm-macros-internal.h +++ b/shared/nm-glib-aux/nm-macros-internal.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2012 Colin Walters <walters@verbum.org>. * Copyright (C) 2014 Red Hat, Inc. @@ -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,250 +38,123 @@ /*****************************************************************************/ -#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); \ -} +#include "nm-glib.h" /*****************************************************************************/ -/** - * gs_free: - * - * Call g_free() on a variable location when it goes out of scope. - */ -#define gs_free nm_auto(gs_local_free) -NM_AUTO_DEFINE_FCN_VOID0 (void *, gs_local_free, g_free) - -/** - * gs_unref_object: - * - * Call g_object_unref() on a variable location when it goes out of - * scope. Note that unlike g_object_unref(), the variable may be - * %NULL. - */ -#define gs_unref_object nm_auto(gs_local_obj_unref) -NM_AUTO_DEFINE_FCN_VOID0 (GObject *, gs_local_obj_unref, g_object_unref) - -/** - * gs_unref_variant: - * - * Call g_variant_unref() on a variable location when it goes out of - * scope. Note that unlike g_variant_unref(), the variable may be - * %NULL. - */ -#define gs_unref_variant nm_auto(gs_local_variant_unref) -NM_AUTO_DEFINE_FCN0 (GVariant *, gs_local_variant_unref, g_variant_unref) - -/** - * gs_unref_array: - * - * Call g_array_unref() on a variable location when it goes out of - * scope. Note that unlike g_array_unref(), the variable may be - * %NULL. +#define nm_offsetofend(t, m) (G_STRUCT_OFFSET(t, m) + sizeof(((t *) NULL)->m)) - */ -#define gs_unref_array nm_auto(gs_local_array_unref) -NM_AUTO_DEFINE_FCN0 (GArray *, gs_local_array_unref, g_array_unref) - -/** - * gs_unref_ptrarray: - * - * Call g_ptr_array_unref() on a variable location when it goes out of - * scope. Note that unlike g_ptr_array_unref(), the variable may be - * %NULL. - - */ -#define gs_unref_ptrarray nm_auto(gs_local_ptrarray_unref) -NM_AUTO_DEFINE_FCN0 (GPtrArray *, gs_local_ptrarray_unref, g_ptr_array_unref) +/*****************************************************************************/ -/** - * gs_unref_hashtable: - * - * Call g_hash_table_unref() on a variable location when it goes out - * of scope. Note that unlike g_hash_table_unref(), the variable may - * be %NULL. - */ -#define gs_unref_hashtable nm_auto(gs_local_hashtable_unref) -NM_AUTO_DEFINE_FCN0 (GHashTable *, gs_local_hashtable_unref, g_hash_table_unref) +#define gs_free nm_auto_g_free +#define gs_unref_object nm_auto_unref_object +#define gs_unref_variant nm_auto_unref_variant +#define gs_unref_array nm_auto_unref_array +#define gs_unref_ptrarray nm_auto_unref_ptrarray +#define gs_unref_hashtable nm_auto_unref_hashtable +#define gs_unref_bytes nm_auto_unref_bytes +#define gs_strfreev nm_auto_strfreev +#define gs_free_error nm_auto_free_error -/** - * gs_free_slist: - * - * Call g_slist_free() on a variable location when it goes out - * of scope. - */ -#define gs_free_slist nm_auto(gs_local_free_slist) -NM_AUTO_DEFINE_FCN0 (GSList *, gs_local_free_slist, g_slist_free) +/*****************************************************************************/ -/** - * gs_unref_bytes: - * - * Call g_bytes_unref() on a variable location when it goes out - * of scope. Note that unlike g_bytes_unref(), the variable may - * be %NULL. - */ -#define gs_unref_bytes nm_auto(gs_local_bytes_unref) -NM_AUTO_DEFINE_FCN0 (GBytes *, gs_local_bytes_unref, g_bytes_unref) +NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_g_free, g_free); +#define nm_auto_g_free nm_auto(_nm_auto_g_free) -/** - * gs_strfreev: - * - * Call g_strfreev() on a variable location when it goes out of scope. - */ -#define gs_strfreev nm_auto(gs_local_strfreev) -NM_AUTO_DEFINE_FCN0 (char **, gs_local_strfreev, g_strfreev) +NM_AUTO_DEFINE_FCN_VOID0(GObject *, _nm_auto_unref_object, g_object_unref); +#define nm_auto_unref_object nm_auto(_nm_auto_unref_object) -/** - * gs_free_error: - * - * Call g_error_free() on a variable location when it goes out of scope. - */ -#define gs_free_error nm_auto(gs_local_free_error) -NM_AUTO_DEFINE_FCN0 (GError *, gs_local_free_error, g_error_free) +NM_AUTO_DEFINE_FCN0(GVariant *, _nm_auto_unref_variant, g_variant_unref); +#define nm_auto_unref_variant nm_auto(_nm_auto_unref_variant) -/** - * gs_unref_keyfile: - * - * Call g_key_file_unref() on a variable location when it goes out of scope. - */ -#define gs_unref_keyfile nm_auto(gs_local_keyfile_unref) -NM_AUTO_DEFINE_FCN0 (GKeyFile *, gs_local_keyfile_unref, g_key_file_unref) +NM_AUTO_DEFINE_FCN0(GArray *, _nm_auto_unref_array, g_array_unref); +#define nm_auto_unref_array nm_auto(_nm_auto_unref_array) -/*****************************************************************************/ +NM_AUTO_DEFINE_FCN0(GPtrArray *, _nm_auto_unref_ptrarray, g_ptr_array_unref); +#define nm_auto_unref_ptrarray nm_auto(_nm_auto_unref_ptrarray) -#include "nm-glib.h" +NM_AUTO_DEFINE_FCN0(GHashTable *, _nm_auto_unref_hashtable, g_hash_table_unref); +#define nm_auto_unref_hashtable nm_auto(_nm_auto_unref_hashtable) -/*****************************************************************************/ +NM_AUTO_DEFINE_FCN0(GSList *, _nm_auto_free_slist, g_slist_free); +#define nm_auto_free_slist nm_auto(_nm_auto_free_slist) -#define nm_offsetofend(t,m) (G_STRUCT_OFFSET (t,m) + sizeof (((t *) NULL)->m)) +NM_AUTO_DEFINE_FCN0(GBytes *, _nm_auto_unref_bytes, g_bytes_unref); +#define nm_auto_unref_bytes nm_auto(_nm_auto_unref_bytes) -/*****************************************************************************/ +NM_AUTO_DEFINE_FCN0(char **, _nm_auto_strfreev, g_strfreev); +#define nm_auto_strfreev nm_auto(_nm_auto_strfreev) -static inline int nm_close (int fd); +NM_AUTO_DEFINE_FCN0(GError *, _nm_auto_free_error, g_error_free); +#define nm_auto_free_error nm_auto(_nm_auto_free_error) -/** - * 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(GKeyFile *, _nm_auto_unref_keyfile, g_key_file_unref); +#define nm_auto_unref_keyfile nm_auto(_nm_auto_unref_keyfile) -NM_AUTO_DEFINE_FCN0 (GVariantIter *, _nm_auto_free_variant_iter, g_variant_iter_free) +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) -NM_AUTO_DEFINE_FCN0 (GVariantBuilder *, _nm_auto_unref_variant_builder, g_variant_builder_unref) +NM_AUTO_DEFINE_FCN0(GVariantBuilder *, _nm_auto_unref_variant_builder, g_variant_builder_unref); #define nm_auto_unref_variant_builder nm_auto(_nm_auto_unref_variant_builder) #define nm_auto_clear_variant_builder nm_auto(g_variant_builder_clear) -NM_AUTO_DEFINE_FCN0 (GList *, _nm_auto_free_list, g_list_free) +NM_AUTO_DEFINE_FCN0(GList *, _nm_auto_free_list, g_list_free); #define nm_auto_free_list nm_auto(_nm_auto_free_list) -NM_AUTO_DEFINE_FCN0 (GChecksum *, _nm_auto_checksum_free, g_checksum_free) +NM_AUTO_DEFINE_FCN0(GChecksum *, _nm_auto_checksum_free, g_checksum_free); #define nm_auto_free_checksum nm_auto(_nm_auto_checksum_free) #define nm_auto_unset_gvalue nm_auto(g_value_unset) -NM_AUTO_DEFINE_FCN_VOID0 (void *, _nm_auto_unref_gtypeclass, g_type_class_unref) +NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_unref_gtypeclass, g_type_class_unref); #define nm_auto_unref_gtypeclass nm_auto(_nm_auto_unref_gtypeclass) -NM_AUTO_DEFINE_FCN0 (GByteArray *, _nm_auto_unref_bytearray, g_byte_array_unref) +NM_AUTO_DEFINE_FCN0(GByteArray *, _nm_auto_unref_bytearray, g_byte_array_unref); #define nm_auto_unref_bytearray nm_auto(_nm_auto_unref_bytearray) static inline void -_nm_auto_free_gstring (GString **str) +_nm_auto_free_gstring(GString **str) { - if (*str) - g_string_free (*str, TRUE); + if (*str) + g_string_free(*str, TRUE); } #define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring) static inline void -_nm_auto_close (int *pfd) +_nm_auto_protect_errno(int *p_saved_errno) { - if (*pfd >= 0) { - int errsv = errno; - - (void) nm_close (*pfd); - errno = errsv; - } + errno = *p_saved_errno; } -#define nm_auto_close nm_auto(_nm_auto_close) +#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \ + nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) -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; -} -#define NM_AUTO_PROTECT_ERRNO(errsv_saved) nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) - -NM_AUTO_DEFINE_FCN0 (GSource *, _nm_auto_unref_gsource, g_source_unref); +NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_unref_gsource, g_source_unref); #define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource) -NM_AUTO_DEFINE_FCN0 (guint, _nm_auto_remove_source, g_source_remove); +NM_AUTO_DEFINE_FCN0(guint, _nm_auto_remove_source, g_source_remove); #define nm_auto_remove_source nm_auto(_nm_auto_remove_source) -NM_AUTO_DEFINE_FCN0 (GIOChannel *, _nm_auto_unref_io_channel, g_io_channel_unref) +NM_AUTO_DEFINE_FCN0(GIOChannel *, _nm_auto_unref_io_channel, g_io_channel_unref); #define nm_auto_unref_io_channel nm_auto(_nm_auto_unref_io_channel) -NM_AUTO_DEFINE_FCN0 (GMainLoop *, _nm_auto_unref_gmainloop, g_main_loop_unref); +NM_AUTO_DEFINE_FCN0(GMainLoop *, _nm_auto_unref_gmainloop, g_main_loop_unref); #define nm_auto_unref_gmainloop nm_auto(_nm_auto_unref_gmainloop) +NM_AUTO_DEFINE_FCN0(GOptionContext *, _nm_auto_free_option_context, g_option_context_free); +#define nm_auto_free_option_context nm_auto(_nm_auto_free_option_context) + static inline void -_nm_auto_freev (gpointer ptr) +_nm_auto_freev(gpointer ptr) { - gpointer **p = ptr; - gpointer *_ptr; - - if (*p) { - for (_ptr = *p; *_ptr; _ptr++) - g_free (*_ptr); - g_free (*p); - } + gpointer **p = ptr; + gpointer * _ptr; + + if (*p) { + for (_ptr = *p; *_ptr; _ptr++) + g_free(*_ptr); + g_free(*p); + } } /* g_free a NULL terminated array of pointers, with also freeing each * pointer with g_free(). It essentially does the same as @@ -337,72 +163,303 @@ _nm_auto_freev (gpointer ptr) /*****************************************************************************/ -#define _NM_MACRO_SELECT_ARG_64( \ - _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ - _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ - _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ - _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ - _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ - _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ - _61,_62,_63, N,...) N +#define _NM_MACRO_SELECT_ARG_64(_1, \ + _2, \ + _3, \ + _4, \ + _5, \ + _6, \ + _7, \ + _8, \ + _9, \ + _10, \ + _11, \ + _12, \ + _13, \ + _14, \ + _15, \ + _16, \ + _17, \ + _18, \ + _19, \ + _20, \ + _21, \ + _22, \ + _23, \ + _24, \ + _25, \ + _26, \ + _27, \ + _28, \ + _29, \ + _30, \ + _31, \ + _32, \ + _33, \ + _34, \ + _35, \ + _36, \ + _37, \ + _38, \ + _39, \ + _40, \ + _41, \ + _42, \ + _43, \ + _44, \ + _45, \ + _46, \ + _47, \ + _48, \ + _49, \ + _50, \ + _51, \ + _52, \ + _53, \ + _54, \ + _55, \ + _56, \ + _57, \ + _58, \ + _59, \ + _60, \ + _61, \ + _62, \ + _63, \ + N, \ + ...) \ + N /* http://stackoverflow.com/a/2124385/354393 * https://stackoverflow.com/questions/11317474/macro-to-count-number-of-arguments */ -#define NM_NARG(...) \ - _NM_MACRO_SELECT_ARG_64(, ##__VA_ARGS__, \ - 62,61,60, \ - 59,58,57,56,55,54,53,52,51,50, \ - 49,48,47,46,45,44,43,42,41,40, \ - 39,38,37,36,35,34,33,32,31,30, \ - 29,28,27,26,25,24,23,22,21,20, \ - 19,18,17,16,15,14,13,12,11,10, \ - 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#define NM_NARG_MAX1(...) \ - _NM_MACRO_SELECT_ARG_64(, ##__VA_ARGS__, \ - 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) -#define NM_NARG_MAX2(...) \ - _NM_MACRO_SELECT_ARG_64(, ##__VA_ARGS__, \ - 2, 2, 2, \ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, \ - 2, 2, 2, 2, 2, 2, 2, 2, 1, 0) - -#define _NM_MACRO_CALL(macro, ...) macro (__VA_ARGS__) +#define NM_NARG(...) \ + _NM_MACRO_SELECT_ARG_64(, \ + ##__VA_ARGS__, \ + 62, \ + 61, \ + 60, \ + 59, \ + 58, \ + 57, \ + 56, \ + 55, \ + 54, \ + 53, \ + 52, \ + 51, \ + 50, \ + 49, \ + 48, \ + 47, \ + 46, \ + 45, \ + 44, \ + 43, \ + 42, \ + 41, \ + 40, \ + 39, \ + 38, \ + 37, \ + 36, \ + 35, \ + 34, \ + 33, \ + 32, \ + 31, \ + 30, \ + 29, \ + 28, \ + 27, \ + 26, \ + 25, \ + 24, \ + 23, \ + 22, \ + 21, \ + 20, \ + 19, \ + 18, \ + 17, \ + 16, \ + 15, \ + 14, \ + 13, \ + 12, \ + 11, \ + 10, \ + 9, \ + 8, \ + 7, \ + 6, \ + 5, \ + 4, \ + 3, \ + 2, \ + 1, \ + 0) +#define NM_NARG_MAX1(...) \ + _NM_MACRO_SELECT_ARG_64(, \ + ##__VA_ARGS__, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 1, \ + 0) +#define NM_NARG_MAX2(...) \ + _NM_MACRO_SELECT_ARG_64(, \ + ##__VA_ARGS__, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 2, \ + 1, \ + 0) + +#define _NM_MACRO_CALL(macro, ...) macro(__VA_ARGS__) /*****************************************************************************/ -#define _NM_MACRO_COMMA_IF_ARGS(...) _NM_MACRO_CALL (G_PASTE (__NM_MACRO_COMMA_IF_ARGS_, NM_NARG_MAX1(__VA_ARGS__)), __VA_ARGS__) +#define _NM_MACRO_COMMA_IF_ARGS(...) \ + _NM_MACRO_CALL(G_PASTE(__NM_MACRO_COMMA_IF_ARGS_, NM_NARG_MAX1(__VA_ARGS__)), __VA_ARGS__) #define __NM_MACRO_COMMA_IF_ARGS_0() -#define __NM_MACRO_COMMA_IF_ARGS_1(...) , +#define __NM_MACRO_COMMA_IF_ARGS_1(...) , /*****************************************************************************/ /* http://stackoverflow.com/a/11172679 */ -#define _NM_UTILS_MACRO_FIRST(...) __NM_UTILS_MACRO_FIRST_HELPER(__VA_ARGS__, throwaway) -#define __NM_UTILS_MACRO_FIRST_HELPER(first, ...) first +#define _NM_UTILS_MACRO_FIRST(...) __NM_UTILS_MACRO_FIRST_HELPER(__VA_ARGS__, throwaway) +#define __NM_UTILS_MACRO_FIRST_HELPER(first, ...) first -#define _NM_UTILS_MACRO_REST(...) _NM_MACRO_CALL (G_PASTE (__NM_UTILS_MACRO_REST_, NM_NARG_MAX2(__VA_ARGS__)), __VA_ARGS__) +#define _NM_UTILS_MACRO_REST(...) \ + _NM_MACRO_CALL(G_PASTE(__NM_UTILS_MACRO_REST_, NM_NARG_MAX2(__VA_ARGS__)), __VA_ARGS__) #define __NM_UTILS_MACRO_REST_0() #define __NM_UTILS_MACRO_REST_1(first) -#define __NM_UTILS_MACRO_REST_2(first, ...) , __VA_ARGS__ +#define __NM_UTILS_MACRO_REST_2(first, ...) , __VA_ARGS__ /*****************************************************************************/ -#if defined (__GNUC__) -#define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(GCC diagnostic ignored warning) -#elif defined (__clang__) -#define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(clang diagnostic ignored warning) +#if defined(__GNUC__) + #define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(GCC diagnostic ignored warning) +#elif defined(__clang__) + #define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(clang diagnostic ignored warning) #endif /* you can only suppress a specific warning that the compiler @@ -411,27 +468,24 @@ _nm_auto_freev (gpointer ptr) * It's not that bad however, because gcc and clang often have the * same name for the same warning. */ -#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define NM_PRAGMA_WARNING_DISABLE(warning) \ - _Pragma("GCC diagnostic push") \ - _Pragma(_NM_PRAGMA_WARNING_DO(warning)) -#elif defined (__clang__) -#define NM_PRAGMA_WARNING_DISABLE(warning) \ - _Pragma("clang diagnostic push") \ - _Pragma(_NM_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \ - _Pragma(_NM_PRAGMA_WARNING_DO(warning)) +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) + #define NM_PRAGMA_WARNING_DISABLE(warning) \ + _Pragma("GCC diagnostic push") _Pragma(_NM_PRAGMA_WARNING_DO(warning)) +#elif defined(__clang__) + #define NM_PRAGMA_WARNING_DISABLE(warning) \ + _Pragma("clang diagnostic push") \ + _Pragma(_NM_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \ + _Pragma(_NM_PRAGMA_WARNING_DO(warning)) #else -#define NM_PRAGMA_WARNING_DISABLE(warning) + #define NM_PRAGMA_WARNING_DISABLE(warning) #endif -#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define NM_PRAGMA_WARNING_REENABLE \ - _Pragma("GCC diagnostic pop") -#elif defined (__clang__) -#define NM_PRAGMA_WARNING_REENABLE \ - _Pragma("clang diagnostic pop") +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) + #define NM_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop") +#elif defined(__clang__) + #define NM_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop") #else -#define NM_PRAGMA_WARNING_REENABLE + #define NM_PRAGMA_WARNING_REENABLE #endif /*****************************************************************************/ @@ -449,222 +503,185 @@ _nm_auto_freev (gpointer ptr) * Returns: the error message. **/ static inline const char * -NM_G_ERROR_MSG (GError *error) +NM_G_ERROR_MSG(GError *error) { - return error ? (error->message ?: "(null)") : "(no-error)"; \ + return error ? (error->message ?: "(null)") : "(no-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 -#else -#define _NM_CC_SUPPORT_AUTO_TYPE 0 -#endif + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))) + #define _NM_CC_SUPPORT_AUTO_TYPE 1 + #else + #define _NM_CC_SUPPORT_AUTO_TYPE 0 + #endif #endif #ifndef _NM_CC_SUPPORT_GENERIC -/* In the meantime, NetworkManager requires C11 and _Generic() should always be available. + /* In the meantime, NetworkManager requires C11 and _Generic() should always be available. * However, shared/nm-utils may also be used in VPN/applet, which possibly did not yet * bump the C standard requirement. Leave this for the moment, but eventually we can * drop it. */ -#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__)) -#define _NM_CC_SUPPORT_GENERIC 1 -#else -#define _NM_CC_SUPPORT_GENERIC 0 -#endif + #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))) \ + || (defined(__clang__)) + #define _NM_CC_SUPPORT_GENERIC 1 + #else + #define _NM_CC_SUPPORT_GENERIC 0 + #endif #endif #if _NM_CC_SUPPORT_AUTO_TYPE -#define _nm_auto_type __auto_type + #define _nm_auto_type __auto_type #endif #if _NM_CC_SUPPORT_GENERIC -#define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \ - (_Generic ((obj_expr), \ - const void *const: ((const type *) (obj)), \ - const void * : ((const type *) (obj)), \ - void *const: (( type *) (obj)), \ - void * : (( type *) (obj)), \ - const type *const: ((const type *) (obj)), \ - const type * : ((const type *) (obj)), \ - type *const: (( type *) (obj)), \ - type * : (( type *) (obj)))) -#define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \ - (_Generic ((obj_expr), \ - const void *const: ((const type *) (obj)), \ - const void * : ((const type *) (obj)), \ - void *const: (( type *) (obj)), \ - void * : (( type *) (obj)), \ - const alias_type2 *const: ((const type *) (obj)), \ - const alias_type2 * : ((const type *) (obj)), \ - alias_type2 *const: (( type *) (obj)), \ - alias_type2 * : (( type *) (obj)), \ - const type *const: ((const type *) (obj)), \ - const type * : ((const type *) (obj)), \ - type *const: (( type *) (obj)), \ - type * : (( type *) (obj)))) -#define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \ - (_Generic ((obj_expr), \ - const void *const: ((const type *) (obj)), \ - const void * : ((const type *) (obj)), \ - void *const: (( type *) (obj)), \ - void * : (( type *) (obj)), \ - const alias_type2 *const: ((const type *) (obj)), \ - const alias_type2 * : ((const type *) (obj)), \ - alias_type2 *const: (( type *) (obj)), \ - alias_type2 * : (( type *) (obj)), \ - const alias_type3 *const: ((const type *) (obj)), \ - const alias_type3 * : ((const type *) (obj)), \ - alias_type3 *const: (( type *) (obj)), \ - alias_type3 * : (( type *) (obj)), \ - const type *const: ((const type *) (obj)), \ - const type * : ((const type *) (obj)), \ - type *const: (( type *) (obj)), \ - type * : (( type *) (obj)))) -#define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \ - (_Generic ((obj_expr), \ - const void *const: ((const type *) (obj)), \ - const void * : ((const type *) (obj)), \ - void *const: (( type *) (obj)), \ - void * : (( type *) (obj)), \ - const alias_type2 *const: ((const type *) (obj)), \ - const alias_type2 * : ((const type *) (obj)), \ - alias_type2 *const: (( type *) (obj)), \ - alias_type2 * : (( type *) (obj)), \ - const alias_type3 *const: ((const type *) (obj)), \ - const alias_type3 * : ((const type *) (obj)), \ - alias_type3 *const: (( type *) (obj)), \ - alias_type3 * : (( type *) (obj)), \ - const alias_type4 *const: ((const type *) (obj)), \ - const alias_type4 * : ((const type *) (obj)), \ - alias_type4 *const: (( type *) (obj)), \ - alias_type4 * : (( type *) (obj)), \ - const type *const: ((const type *) (obj)), \ - const type * : ((const type *) (obj)), \ - type *const: (( type *) (obj)), \ - type * : (( type *) (obj)))) -#define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) (_NM_CONSTCAST_FULL_##n (type, obj_expr, obj, ##__VA_ARGS__)) -#define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) (_NM_CONSTCAST_FULL_x (type, obj_expr, obj, n, ##__VA_ARGS__)) -#define NM_CONSTCAST_FULL( type, obj_expr, obj, ...) (_NM_CONSTCAST_FULL_y (type, obj_expr, obj, NM_NARG (dummy, ##__VA_ARGS__), ##__VA_ARGS__)) + #define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) + #define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const alias_type2 *const: ((const type *) (obj)), \ + const alias_type2 * : ((const type *) (obj)), \ + alias_type2 *const: (( type *) (obj)), \ + alias_type2 * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) + #define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const alias_type2 *const: ((const type *) (obj)), \ + const alias_type2 * : ((const type *) (obj)), \ + alias_type2 *const: (( type *) (obj)), \ + alias_type2 * : (( type *) (obj)), \ + const alias_type3 *const: ((const type *) (obj)), \ + const alias_type3 * : ((const type *) (obj)), \ + alias_type3 *const: (( type *) (obj)), \ + alias_type3 * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) + #define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const alias_type2 *const: ((const type *) (obj)), \ + const alias_type2 * : ((const type *) (obj)), \ + alias_type2 *const: (( type *) (obj)), \ + alias_type2 * : (( type *) (obj)), \ + const alias_type3 *const: ((const type *) (obj)), \ + const alias_type3 * : ((const type *) (obj)), \ + alias_type3 *const: (( type *) (obj)), \ + alias_type3 * : (( type *) (obj)), \ + const alias_type4 *const: ((const type *) (obj)), \ + const alias_type4 * : ((const type *) (obj)), \ + alias_type4 *const: (( type *) (obj)), \ + alias_type4 * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) + #define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) \ + (_NM_CONSTCAST_FULL_##n(type, obj_expr, obj, ##__VA_ARGS__)) + #define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) \ + (_NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ##__VA_ARGS__)) + #define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) \ + (_NM_CONSTCAST_FULL_y(type, obj_expr, obj, NM_NARG(dummy, ##__VA_ARGS__), ##__VA_ARGS__)) #else -#define NM_CONSTCAST_FULL( type, obj_expr, obj, ...) ((type *) (obj)) + #define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) ((type *) (obj)) #endif -#define NM_CONSTCAST(type, obj, ...) \ - NM_CONSTCAST_FULL(type, (obj), (obj), ##__VA_ARGS__) +#define NM_CONSTCAST(type, obj, ...) NM_CONSTCAST_FULL(type, (obj), (obj), ##__VA_ARGS__) #if _NM_CC_SUPPORT_GENERIC -#define NM_UNCONST_PTR(type, arg) \ - _Generic ((arg), \ - const type *: ((type *) (arg)), \ - type *: ((type *) (arg))) + #define NM_UNCONST_PTR(type, arg) \ + _Generic((arg), const type * : ((type *) (arg)), type * : ((type *) (arg))) #else -#define NM_UNCONST_PTR(type, arg) \ - ((type *) (arg)) + #define NM_UNCONST_PTR(type, arg) ((type *) (arg)) #endif #if _NM_CC_SUPPORT_GENERIC -#define NM_UNCONST_PPTR(type, arg) \ - _Generic ((arg), \ - const type * *: ((type **) (arg)), \ - type * *: ((type **) (arg)), \ - const type *const*: ((type **) (arg)), \ - type *const*: ((type **) (arg))) + #define NM_UNCONST_PPTR(type, arg) \ + _Generic ((arg), \ + const type * *: ((type **) (arg)), \ + type * *: ((type **) (arg)), \ + const type *const*: ((type **) (arg)), \ + type *const*: ((type **) (arg))) #else -#define NM_UNCONST_PPTR(type, arg) \ - ((type **) (arg)) + #define NM_UNCONST_PPTR(type, arg) ((type **) (arg)) #endif -#define NM_GOBJECT_CAST(type, obj, is_check, ...) \ - ({ \ - const void *_obj = (obj); \ - \ - nm_assert (_obj || (is_check (_obj))); \ - NM_CONSTCAST_FULL (type, (obj), _obj, GObject, ##__VA_ARGS__); \ - }) - -#define NM_GOBJECT_CAST_NON_NULL(type, obj, is_check, ...) \ - ({ \ - const void *_obj = (obj); \ - \ - nm_assert (is_check (_obj)); \ - NM_CONSTCAST_FULL (type, (obj), _obj, GObject, ##__VA_ARGS__); \ - }) - -#define NM_ENSURE_NOT_NULL(ptr) \ - ({ \ - typeof (ptr) _ptr = (ptr); \ - \ - nm_assert (_ptr != NULL); \ - _ptr; \ - }) +#define NM_GOBJECT_CAST(type, obj, is_check, ...) \ + ({ \ + const void *_obj = (obj); \ + \ + nm_assert(_obj || (is_check(_obj))); \ + NM_CONSTCAST_FULL(type, (obj), _obj, GObject, ##__VA_ARGS__); \ + }) + +#define NM_GOBJECT_CAST_NON_NULL(type, obj, is_check, ...) \ + ({ \ + const void *_obj = (obj); \ + \ + nm_assert(is_check(_obj)); \ + NM_CONSTCAST_FULL(type, (obj), _obj, GObject, ##__VA_ARGS__); \ + }) + +#define NM_ENSURE_NOT_NULL(ptr) \ + ({ \ + typeof(ptr) _ptr = (ptr); \ + \ + nm_assert(_ptr != NULL); \ + _ptr; \ + }) #if _NM_CC_SUPPORT_GENERIC -/* returns @value, if the type of @value matches @type. + /* returns @value, if the type of @value matches @type. * This requires support for C11 _Generic(). If no support is * present, this returns @value directly. * * It's useful to check the let the compiler ensure that @value is * of a certain type. */ -#define _NM_ENSURE_TYPE(type, value) (_Generic ((value), type: (value))) -#define _NM_ENSURE_TYPE_CONST(type, value) (_Generic ((value), \ - const type : ((const type) (value)), \ - const type const: ((const type) (value)), \ - type : ((const type) (value)), \ - type const: ((const type) (value)))) + #define _NM_ENSURE_TYPE(type, value) (_Generic((value), type : (value))) + #define _NM_ENSURE_TYPE_CONST(type, value) \ + (_Generic((value), const type \ + : ((const type)(value)), const type const \ + : ((const type)(value)), type \ + : ((const type)(value)), type const \ + : ((const type)(value)))) #else -#define _NM_ENSURE_TYPE(type, value) (value) -#define _NM_ENSURE_TYPE_CONST(type, value) ((const type) (value)) + #define _NM_ENSURE_TYPE(type, value) (value) + #define _NM_ENSURE_TYPE_CONST(type, value) ((const type)(value)) #endif -#if _NM_CC_SUPPORT_GENERIC && ( !defined (__clang__) || __clang_major__ > 3 ) -#define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) (_Generic ( (&(((container *) NULL)->field))[0] , \ - type: G_STRUCT_OFFSET (container, field))) +#if _NM_CC_SUPPORT_GENERIC && (!defined(__clang__) || __clang_major__ > 3) + #define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) \ + (_Generic((&(((container *) NULL)->field))[0], type : G_STRUCT_OFFSET(container, field))) #else -#define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) G_STRUCT_OFFSET (container, field) + #define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) G_STRUCT_OFFSET(container, field) #endif #if _NM_CC_SUPPORT_GENERIC -/* these macros cast (value) to + /* these macros cast (value) to * - "const char **" (for "MC", mutable-const) * - "const char *const*" (for "CC", const-const) * The point is to do this cast, but only accepting pointers @@ -680,197 +697,40 @@ NM_G_ERROR_MSG (GError *error) * These macros do the cast, but they only accept a compatible input * type, otherwise they will fail compilation. */ -#define NM_CAST_STRV_MC(value) \ - (_Generic ((value), \ - const char * *: (const char * *) (value), \ - char * *: (const char * *) (value), \ - void *: (const char * *) (value))) -#define NM_CAST_STRV_CC(value) \ - (_Generic ((value), \ - const char *const*: (const char *const*) (value), \ - const char * *: (const char *const*) (value), \ - char *const*: (const char *const*) (value), \ - char * *: (const char *const*) (value), \ - const void *: (const char *const*) (value), \ - void *: (const char *const*) (value))) + #define NM_CAST_STRV_MC(value) \ + (_Generic ((value), \ + const char * *: (const char * *) (value), \ + char * *: (const char * *) (value), \ + void *: (const char * *) (value))) + #define NM_CAST_STRV_CC(value) \ + (_Generic ((value), \ + const char *const*: (const char *const*) (value), \ + const char * *: (const char *const*) (value), \ + char *const*: (const char *const*) (value), \ + char * *: (const char *const*) (value), \ + const void *: (const char *const*) (value), \ + void *: (const char *const*) (value))) #else -#define NM_CAST_STRV_MC(value) ((const char * *) (value)) -#define NM_CAST_STRV_CC(value) ((const char *const*) (value)) + #define NM_CAST_STRV_MC(value) ((const char **) (value)) + #define NM_CAST_STRV_CC(value) ((const char *const *) (value)) #endif #if _NM_CC_SUPPORT_GENERIC -#define NM_PROPAGATE_CONST(test_expr, ptr) \ - (_Generic ((test_expr), \ - const typeof (*(test_expr)) *: ((const typeof (*(ptr)) *) (ptr)), \ - default: (_Generic ((test_expr), \ - typeof (*(test_expr)) *: (ptr))))) + #define NM_PROPAGATE_CONST(test_expr, ptr) \ + (_Generic ((test_expr), \ + const typeof (*(test_expr)) *: ((const typeof (*(ptr)) *) (ptr)), \ + default: (_Generic ((test_expr), \ + typeof (*(test_expr)) *: (ptr))))) #else -#define NM_PROPAGATE_CONST(test_expr, ptr) (ptr) + #define NM_PROPAGATE_CONST(test_expr, ptr) (ptr) #endif /* with the way it is implemented, the caller may or may not pass a trailing * ',' and it will work. However, this makes the macro unsuitable for initializing * an array. */ -#define NM_MAKE_STRV(...) \ - ((const char *const[(sizeof (((const char *const[]) { __VA_ARGS__ })) / sizeof (const char *)) + 1]) { __VA_ARGS__ }) - -/*****************************************************************************/ - -#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_17(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_16 (op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_18(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_17 (op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_19(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_18 (op, _x, __VA_ARGS__) -#define _NM_IN_SET_EVAL_20(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_19 (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_17(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_16 (op, _x, __VA_ARGS__) -#define _NM_IN_STRSET_EVAL_18(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_17 (op, _x, __VA_ARGS__) -#define _NM_IN_STRSET_EVAL_19(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_18 (op, _x, __VA_ARGS__) -#define _NM_IN_STRSET_EVAL_20(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_19 (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; \ - }) +#define NM_MAKE_STRV(...) \ + ((const char *const[(sizeof(((const char *const[]){__VA_ARGS__})) / sizeof(const char *)) \ + + 1]){__VA_ARGS__}) /*****************************************************************************/ @@ -879,14 +739,14 @@ _NM_IN_STRSET_streq (const char *x, const char *s) * * @string must be a string literal. */ -#define NM_CACHED_QUARK(string) \ - ({ \ - static GQuark _nm_cached_quark = 0; \ - \ - (G_LIKELY (_nm_cached_quark != 0) \ - ? _nm_cached_quark \ - : (_nm_cached_quark = g_quark_from_static_string (""string""))); \ - }) +#define NM_CACHED_QUARK(string) \ + ({ \ + static GQuark _nm_cached_quark = 0; \ + \ + (G_LIKELY(_nm_cached_quark != 0) \ + ? _nm_cached_quark \ + : (_nm_cached_quark = g_quark_from_static_string("" string ""))); \ + }) /* NM_CACHED_QUARK_FCN() is essentially the same as G_DEFINE_QUARK * with two differences: @@ -900,177 +760,87 @@ _NM_IN_STRSET_streq (const char *x, const char *s) * NM_CACHED_QUARK_FCN() defines it). */ #define NM_CACHED_QUARK_FCN(string, fcn) \ -GQuark \ -fcn (void) \ -{ \ - return NM_CACHED_QUARK (string); \ -} - -/*****************************************************************************/ - -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'; \ - }) + GQuark fcn(void) \ + { \ + return NM_CACHED_QUARK(string); \ + } \ + struct _dummy_struct_for_trailing_semicolon /*****************************************************************************/ static inline GString * -nm_gstring_prepare (GString **l) +nm_gstring_prepare(GString **l) { - if (*l) - g_string_set_size (*l, 0); - else - *l = g_string_sized_new (30); - return *l; + if (*l) + g_string_set_size(*l, 0); + else + *l = g_string_sized_new(30); + return *l; } static inline GString * -nm_gstring_add_space_delimiter (GString *str) +nm_gstring_add_space_delimiter(GString *str) { - if (str->len > 0) - g_string_append_c (str, ' '); - return str; + if (str->len > 0) + g_string_append_c(str, ' '); + return str; } static inline gboolean -nm_str_is_empty (const char *str) +nm_str_is_empty(const char *str) { - /* %NULL is also accepted, and also "empty". */ - return !str || !str[0]; + /* %NULL is also accepted, and also "empty". */ + return !str || !str[0]; } static inline const char * -nm_str_not_empty (const char *str) +nm_str_not_empty(const char *str) { - return !nm_str_is_empty (str) ? str : NULL; + return !nm_str_is_empty(str) ? str : NULL; } static inline char * -nm_strdup_not_empty (const char *str) +nm_strdup_not_empty(const char *str) { - return !nm_str_is_empty (str) ? g_strdup (str) : NULL; + return !nm_str_is_empty(str) ? g_strdup(str) : NULL; } static inline char * -nm_str_realloc (char *str) +nm_str_realloc(char *str) { - gs_free char *s = str; - - /* Returns a new clone of @str and frees @str. The point is that @str - * possibly points to a larger chunck of memory. We want to freshly allocate - * a buffer. - * - * We could use realloc(), but that might not do anything or leave - * @str in its memory pool for chunks of a different size (bad for - * fragmentation). - * - * This is only useful when we want to keep the buffer around for a long - * time and want to re-allocate a more optimal buffer. */ - - return g_strdup (s); + gs_free char *s = str; + + /* Returns a new clone of @str and frees @str. The point is that @str + * possibly points to a larger chunck of memory. We want to freshly allocate + * a buffer. + * + * We could use realloc(), but that might not do anything or leave + * @str in its memory pool for chunks of a different size (bad for + * fragmentation). + * + * This is only useful when we want to keep the buffer around for a long + * time and want to re-allocate a more optimal buffer. */ + + return g_strdup(s); } /*****************************************************************************/ +#define NM_PRINT_FMT_QUOTED2(cond, prefix, str, str_else) \ + (cond) ? (prefix) : "", (cond) ? (str) : (str_else) #define NM_PRINT_FMT_QUOTED(cond, prefix, str, suffix, str_else) \ - (cond) ? (prefix) : "", \ - (cond) ? (str) : (str_else), \ - (cond) ? (suffix) : "" + (cond) ? (prefix) : "", (cond) ? (str) : (str_else), (cond) ? (suffix) : "" #define NM_PRINT_FMT_QUOTE_STRING(arg) NM_PRINT_FMT_QUOTED((arg), "\"", (arg), "\"", "(null)") -#define NM_PRINT_FMT_QUOTE_REF_STRING(arg) NM_PRINT_FMT_QUOTED((arg), "\"", (arg)->str, "\"", "(null)") +#define NM_PRINT_FMT_QUOTE_REF_STRING(arg) \ + NM_PRINT_FMT_QUOTED((arg), "\"", (arg)->str, "\"", "(null)") /*****************************************************************************/ -/* 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: * @@ -1079,111 +849,132 @@ nm_str_realloc (char *str) * This will only run the check once, and only if NM_MORE_ASSERT is >= than * more_assert_level. */ -#define NM_MORE_ASSERT_ONCE(more_assert_level) \ - ( (NM_MORE_ASSERTS >= (more_assert_level)) \ - && ({ \ - static volatile int _assert_once = 0; \ - \ - G_STATIC_ASSERT_EXPR ((more_assert_level) > 0); \ - \ - G_UNLIKELY ( _assert_once == 0 \ - && g_atomic_int_compare_and_exchange (&_assert_once, 0, 1)); \ - })) +#define NM_MORE_ASSERT_ONCE(more_assert_level) \ + ((NM_MORE_ASSERTS >= (more_assert_level)) && ({ \ + static volatile int _assert_once = 0; \ + \ + G_STATIC_ASSERT_EXPR((more_assert_level) > 0); \ + \ + G_UNLIKELY(_assert_once == 0 && g_atomic_int_compare_and_exchange(&_assert_once, 0, 1)); \ + })) /*****************************************************************************/ -#define NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(suffix, ...) \ -typedef enum { \ - PROP_0##suffix, \ - __VA_ARGS__ \ - _PROPERTY_ENUMS_LAST##suffix, \ -} _PropertyEnums##suffix; \ -static GParamSpec *obj_properties##suffix[_PROPERTY_ENUMS_LAST##suffix] = { NULL, } - -#define NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY(suffix, obj_type) \ -static inline void \ -_nm_gobject_notify_together_impl##suffix (obj_type *obj, guint n, const _PropertyEnums##suffix *props) \ -{ \ - const gboolean freeze_thaw = (n > 1); \ - \ - nm_assert (G_IS_OBJECT (obj)); \ - nm_assert (n > 0); \ - \ - if (freeze_thaw) \ - g_object_freeze_notify ((GObject *) obj); \ - while (n-- > 0) { \ - const _PropertyEnums##suffix prop = *props++; \ - \ - if (prop != PROP_0##suffix) { \ - nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties##suffix)); \ - nm_assert (obj_properties##suffix[prop]); \ - g_object_notify_by_pspec ((GObject *) obj, obj_properties##suffix[prop]); \ - } \ - } \ - if (freeze_thaw) \ - g_object_thaw_notify ((GObject *) obj); \ -} \ -\ -_nm_unused static inline void \ -_notify##suffix (obj_type *obj, _PropertyEnums##suffix prop) \ -{ \ - _nm_gobject_notify_together_impl##suffix (obj, 1, &prop); \ -} \ +#define NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(suffix, ...) \ + typedef enum { \ + PROP_0##suffix, \ + __VA_ARGS__ _PROPERTY_ENUMS_LAST##suffix, \ + } _PropertyEnums##suffix; \ + static GParamSpec *obj_properties##suffix[_PROPERTY_ENUMS_LAST##suffix] = { \ + NULL, \ + } + +#define NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY(suffix, obj_type) \ + static inline void _nm_gobject_notify_together_impl##suffix( \ + obj_type * obj, \ + guint n, \ + const _PropertyEnums##suffix *props) \ + { \ + GObject *const gobj = (GObject *) obj; \ + GParamSpec * pspec_first = NULL; \ + gboolean frozen = FALSE; \ + \ + nm_assert(G_IS_OBJECT(obj)); \ + nm_assert(n > 0); \ + \ + while (n-- > 0) { \ + const _PropertyEnums##suffix prop = *props++; \ + GParamSpec * pspec; \ + \ + if (prop == PROP_0##suffix) \ + continue; \ + \ + nm_assert((gsize) prop < G_N_ELEMENTS(obj_properties##suffix)); \ + pspec = obj_properties##suffix[prop]; \ + nm_assert(pspec); \ + \ + if (!frozen) { \ + if (!pspec_first) { \ + pspec_first = pspec; \ + continue; \ + } \ + frozen = TRUE; \ + g_object_freeze_notify(gobj); \ + g_object_notify_by_pspec(gobj, pspec_first); \ + } \ + g_object_notify_by_pspec(gobj, pspec); \ + } \ + \ + if (frozen) \ + g_object_thaw_notify(gobj); \ + else if (pspec_first) \ + g_object_notify_by_pspec(gobj, pspec_first); \ + } \ + \ + _nm_unused static inline void _notify##suffix(obj_type *obj, _PropertyEnums##suffix prop) \ + { \ + _nm_gobject_notify_together_impl##suffix(obj, 1, &prop); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON #define NM_GOBJECT_PROPERTIES_DEFINE_BASE(...) \ - NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL (, __VA_ARGS__); \ + NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(, __VA_ARGS__); #define NM_GOBJECT_PROPERTIES_DEFINE_FULL(suffix, obj_type, ...) \ - NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL (suffix, __VA_ARGS__); \ - NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY (suffix, obj_type) + NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(suffix, __VA_ARGS__); \ + NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY(suffix, obj_type) #define NM_GOBJECT_PROPERTIES_DEFINE(obj_type, ...) \ - NM_GOBJECT_PROPERTIES_DEFINE_FULL (, obj_type, __VA_ARGS__) + NM_GOBJECT_PROPERTIES_DEFINE_FULL(, obj_type, __VA_ARGS__) /* invokes _notify() for all arguments (of type _PropertyEnums). Note, that if * there are more than one prop arguments, this will involve a freeze/thaw * of GObject property notifications. */ -#define nm_gobject_notify_together_full(suffix, obj, ...) \ - _nm_gobject_notify_together_impl##suffix (obj, NM_NARG (__VA_ARGS__), (const _PropertyEnums##suffix[]) { __VA_ARGS__ }) +#define nm_gobject_notify_together_full(suffix, obj, ...) \ + _nm_gobject_notify_together_impl##suffix(obj, \ + NM_NARG(__VA_ARGS__), \ + (const _PropertyEnums##suffix[]){__VA_ARGS__}) -#define nm_gobject_notify_together(obj, ...) \ - nm_gobject_notify_together_full (, obj, __VA_ARGS__) +#define nm_gobject_notify_together(obj, ...) nm_gobject_notify_together_full(, obj, __VA_ARGS__) /*****************************************************************************/ -#define _NM_GET_PRIVATE(self, type, is_check, ...) (&(NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv)) +#define _NM_GET_PRIVATE(self, type, is_check, ...) \ + (&(NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv)) #if _NM_CC_SUPPORT_AUTO_TYPE -#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \ - ({ \ - _nm_auto_type _self_get_private = NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__); \ - \ - NM_PROPAGATE_CONST (_self_get_private, _self_get_private->_priv); \ - }) + #define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \ + ({ \ + _nm_auto_type _self_get_private = \ + NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__); \ + \ + NM_PROPAGATE_CONST(_self_get_private, _self_get_private->_priv); \ + }) #else -#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) (NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv) + #define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \ + (NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv) #endif /*****************************************************************************/ static inline gpointer -nm_g_object_ref (gpointer obj) +nm_g_object_ref(gpointer obj) { - /* g_object_ref() doesn't accept NULL. */ - if (obj) - g_object_ref (obj); - return obj; + /* g_object_ref() doesn't accept NULL. */ + if (obj) + g_object_ref(obj); + return obj; } -#define nm_g_object_ref(obj) ((typeof (obj)) nm_g_object_ref (obj)) +#define nm_g_object_ref(obj) ((typeof(obj)) nm_g_object_ref(obj)) static inline void -nm_g_object_unref (gpointer obj) +nm_g_object_unref(gpointer obj) { - /* g_object_unref() doesn't accept NULL. Usully, 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 - * NULL values). */ - if (obj) - g_object_unref (obj); + /* 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 destroy function for a hash table that can contain + * NULL values). */ + if (obj) + g_object_unref(obj); } /* Assigns GObject @obj to destination @pp, and takes an additional ref. @@ -1192,51 +983,43 @@ nm_g_object_unref (gpointer obj) * It makes sure to first increase the ref-count of @obj, and handles %NULL * @obj correctly. * */ -#define nm_g_object_ref_set(pp, obj) \ - ({ \ - typeof (*(pp)) *const _pp = (pp); \ - typeof (*_pp) const _obj = (obj); \ - typeof (*_pp) _p; \ - gboolean _changed = FALSE; \ - \ - nm_assert (!_pp || !*_pp || G_IS_OBJECT (*_pp)); \ - nm_assert (!_obj || G_IS_OBJECT (_obj)); \ - \ - if ( _pp \ - && ((_p = *_pp) != _obj)) { \ - nm_g_object_ref (_obj); \ - *_pp = _obj; \ - nm_g_object_unref (_p); \ - _changed = TRUE; \ - } \ - _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; \ - }) +#define nm_g_object_ref_set(pp, obj) \ + ({ \ + typeof(*(pp)) *const _pp = (pp); \ + typeof(*_pp) const _obj = (obj); \ + typeof(*_pp) _p; \ + gboolean _changed = FALSE; \ + \ + nm_assert(!_pp || !*_pp || G_IS_OBJECT(*_pp)); \ + nm_assert(!_obj || G_IS_OBJECT(_obj)); \ + \ + if (_pp && ((_p = *_pp) != _obj)) { \ + nm_g_object_ref(_obj); \ + *_pp = _obj; \ + nm_g_object_unref(_p); \ + _changed = TRUE; \ + } \ + _changed; \ + }) + +#define nm_g_object_ref_set_take(pp, obj) \ + ({ \ + typeof(*(pp)) *const _pp = (pp); \ + typeof(*_pp) const _obj = (obj); \ + typeof(*_pp) _p; \ + gboolean _changed = FALSE; \ + \ + nm_assert(!_pp || !*_pp || G_IS_OBJECT(*_pp)); \ + nm_assert(!_obj || G_IS_OBJECT(_obj)); \ + \ + if (_pp && ((_p = *_pp) != _obj)) { \ + *_pp = _obj; \ + nm_g_object_unref(_p); \ + _changed = TRUE; \ + } else \ + nm_g_object_unref(_obj); \ + _changed; \ + }) /* basically, replaces * g_clear_pointer (&location, g_free) @@ -1247,11 +1030,9 @@ nm_g_object_unref (gpointer obj) * typesafe and gives you for example a compiler warning when pp is a const * pointer or points to a const-pointer. */ -#define nm_clear_g_free(pp) \ - nm_clear_pointer (pp, g_free) +#define nm_clear_g_free(pp) nm_clear_pointer(pp, g_free) -#define nm_clear_g_object(pp) \ - nm_clear_pointer (pp, g_object_unref) +#define nm_clear_g_object(pp) nm_clear_pointer(pp, g_object_unref) /** * nm_clear_error: @@ -1261,12 +1042,12 @@ nm_g_object_unref (gpointer obj) * that this is an inline function. */ static inline void -nm_clear_error (GError **err) +nm_clear_error(GError **err) { - if (err && *err) { - g_error_free (*err); - *err = NULL; - } + if (err && *err) { + g_error_free(*err); + *err = NULL; + } } /* Patch g_clear_error() to use nm_clear_error(), which is inlineable @@ -1278,60 +1059,56 @@ nm_clear_error (GError **err) #define g_clear_error(ptr) nm_clear_error(ptr) static inline gboolean -nm_clear_g_source (guint *id) +nm_clear_g_source(guint *id) { - guint v; - - if ( id - && (v = *id)) { - *id = 0; - g_source_remove (v); - return TRUE; - } - return FALSE; + guint v; + + if (id && (v = *id)) { + *id = 0; + g_source_remove(v); + return TRUE; + } + return FALSE; } static inline gboolean -nm_clear_g_signal_handler (gpointer self, gulong *id) +nm_clear_g_signal_handler(gpointer self, gulong *id) { - gulong v; - - if ( id - && (v = *id)) { - *id = 0; - g_signal_handler_disconnect (self, v); - return TRUE; - } - return FALSE; + gulong v; + + if (id && (v = *id)) { + *id = 0; + g_signal_handler_disconnect(self, v); + return TRUE; + } + return FALSE; } static inline gboolean -nm_clear_g_variant (GVariant **variant) +nm_clear_g_variant(GVariant **variant) { - GVariant *v; - - if ( variant - && (v = *variant)) { - *variant = NULL; - g_variant_unref (v); - return TRUE; - } - return FALSE; + GVariant *v; + + if (variant && (v = *variant)) { + *variant = NULL; + g_variant_unref(v); + return TRUE; + } + return FALSE; } static inline gboolean -nm_clear_g_cancellable (GCancellable **cancellable) +nm_clear_g_cancellable(GCancellable **cancellable) { - GCancellable *v; - - if ( cancellable - && (v = *cancellable)) { - *cancellable = NULL; - g_cancellable_cancel (v); - g_object_unref (v); - return TRUE; - } - return FALSE; + GCancellable *v; + + if (cancellable && (v = *cancellable)) { + *cancellable = NULL; + g_cancellable_cancel(v); + g_object_unref(v); + return TRUE; + } + return FALSE; } /* If @cancellable_id is not 0, clear it and call g_cancellable_disconnect(). @@ -1343,28 +1120,25 @@ nm_clear_g_cancellable (GCancellable **cancellable) * Note the warning in glib documentation about dead-lock and what g_cancellable_disconnect() * actually does. */ static inline gboolean -nm_clear_g_cancellable_disconnect (GCancellable *cancellable, gulong *cancellable_id) +nm_clear_g_cancellable_disconnect(GCancellable *cancellable, gulong *cancellable_id) { - gulong id; - - if ( cancellable_id - && (id = *cancellable_id) != 0) { - *cancellable_id = 0; - g_cancellable_disconnect (cancellable, id); - return TRUE; - } - return FALSE; + gulong id; + + if (cancellable_id && (id = *cancellable_id) != 0) { + *cancellable_id = 0; + g_cancellable_disconnect(cancellable, id); + return TRUE; + } + return FALSE; } /*****************************************************************************/ static inline const char * -nm_dbus_path_not_empty (const char *str) +nm_dbus_path_not_empty(const char *str) { - nm_assert (!str || str[0] == '/'); - return !str || (str[0] == '/' && str[1] == '\0') - ? NULL - : str; + nm_assert(!str || str[0] == '/'); + return !str || (str[0] == '/' && str[1] == '\0') ? NULL : str; } /*****************************************************************************/ @@ -1375,249 +1149,260 @@ nm_dbus_path_not_empty (const char *str) * * Here you loose the assertion check that G_VARIANT_TYPE() to ensure the * string is valid. */ -#define NM_G_VARIANT_TYPE(fmt) ((const GVariantType *) (""fmt"")) +#define NM_G_VARIANT_TYPE(fmt) ((const GVariantType *) ("" fmt "")) static inline GVariant * -nm_g_variant_ref (GVariant *v) +nm_g_variant_ref(GVariant *v) { - if (v) - g_variant_ref (v); - return v; + if (v) + g_variant_ref(v); + return v; } static inline GVariant * -nm_g_variant_ref_sink (GVariant *v) +nm_g_variant_ref_sink(GVariant *v) { - if (v) - g_variant_ref_sink (v); - return v; + if (v) + g_variant_ref_sink(v); + return v; } static inline void -nm_g_variant_unref (GVariant *v) +nm_g_variant_unref(GVariant *v) { - if (v) - g_variant_unref (v); + if (v) + g_variant_unref(v); } static inline GVariant * -nm_g_variant_take_ref (GVariant *v) +nm_g_variant_take_ref(GVariant *v) { - if (v) - g_variant_take_ref (v); - return v; + if (v) + g_variant_take_ref(v); + return v; } /*****************************************************************************/ -/* Determine whether @x is a power of two (@x being an integer type). - * Basically, this returns TRUE, if @x has exactly one bit set. - * For negative values and zero, this always returns FALSE. */ -#define nm_utils_is_power_of_two(x) ({ \ - typeof(x) __x = (x); \ - \ - ( (__x > ((typeof(__x)) 0)) \ - && ((__x & (__x - (((typeof(__x)) 1)))) == ((typeof(__x)) 0))); \ - }) - -#define NM_DIV_ROUND_UP(x, y) \ - ({ \ - const typeof(x) _x = (x); \ - const typeof(y) _y = (y); \ - \ - (_x / _y + !!(_x % _y)); \ - }) +#define NM_DIV_ROUND_UP(x, y) \ + ({ \ + const typeof(x) _x = (x); \ + const typeof(y) _y = (y); \ + \ + (_x / _y + !!(_x % _y)); \ + }) /*****************************************************************************/ -#define NM_UTILS_LOOKUP_DEFAULT(v) return (v) -#define NM_UTILS_LOOKUP_DEFAULT_WARN(v) g_return_val_if_reached (v) -#define NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(v) { nm_assert_not_reached (); return (v); } -#define NM_UTILS_LOOKUP_ITEM(v, n) (void) 0; case v: return (n); (void) 0 -#define NM_UTILS_LOOKUP_STR_ITEM(v, n) NM_UTILS_LOOKUP_ITEM(v, ""n"") -#define NM_UTILS_LOOKUP_ITEM_IGNORE(v) (void) 0; case v: break; (void) 0 -#define NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER() (void) 0; default: break; (void) 0 +#define NM_UTILS_LOOKUP_DEFAULT(v) return (v) +#define NM_UTILS_LOOKUP_DEFAULT_WARN(v) g_return_val_if_reached(v) +#define NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(v) \ + { \ + nm_assert_not_reached(); \ + return (v); \ + } +#define NM_UTILS_LOOKUP_ITEM(v, n) \ + (void) 0; \ +case v: \ + return (n); \ + (void) 0 +#define NM_UTILS_LOOKUP_STR_ITEM(v, n) NM_UTILS_LOOKUP_ITEM(v, "" n "") +#define NM_UTILS_LOOKUP_ITEM_IGNORE(v) \ + (void) 0; \ +case v: \ + break; \ + (void) 0 +#define NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER() \ + (void) 0; \ +default: \ + break; \ + (void) 0 #define NM_UTILS_LOOKUP_DEFINE(fcn_name, lookup_type, result_type, unknown_val, ...) \ -result_type \ -fcn_name (lookup_type val) \ -{ \ - switch (val) { \ - (void) 0, \ - __VA_ARGS__ \ - (void) 0; \ - }; \ - { unknown_val; } \ -} + result_type fcn_name(lookup_type val) \ + { \ + switch (val) { \ + (void) 0, __VA_ARGS__(void) 0; \ + }; \ + { \ + unknown_val; \ + } \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON #define NM_UTILS_LOOKUP_STR_DEFINE(fcn_name, lookup_type, unknown_val, ...) \ - NM_UTILS_LOOKUP_DEFINE (fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__) + NM_UTILS_LOOKUP_DEFINE(fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__) /* Call the string-lookup-table function @fcn_name. If the function returns * %NULL, the numeric index is converted to string using a alloca() buffer. * Beware: this macro uses alloca(). */ -#define NM_UTILS_LOOKUP_STR_A(fcn_name, idx) \ - ({ \ - typeof (idx) _idx = (idx); \ - const char *_s; \ - \ - _s = fcn_name (_idx); \ - if (!_s) { \ - _s = g_alloca (30); \ - \ - g_snprintf ((char *) _s, 30, "(%lld)", (long long) _idx); \ - } \ - _s; \ - }) +#define NM_UTILS_LOOKUP_STR_A(fcn_name, idx) \ + ({ \ + typeof(idx) _idx = (idx); \ + const char *_s; \ + \ + _s = fcn_name(_idx); \ + if (!_s) { \ + _s = g_alloca(30); \ + \ + g_snprintf((char *) _s, 30, "(%lld)", (long long) _idx); \ + } \ + _s; \ + }) /*****************************************************************************/ /* check if @flags has exactly one flag (@check) set. You should call this * only with @check being a compile time constant and a power of two. */ -#define NM_FLAGS_HAS(flags, check) \ - ( G_STATIC_ASSERT_EXPR ((check) > 0 && ((check) & ((check) - 1)) == 0), NM_FLAGS_ANY ((flags), (check)) ) - -#define NM_FLAGS_ANY(flags, check) ( ( ((flags) & (check)) != 0 ) ? TRUE : FALSE ) -#define NM_FLAGS_ALL(flags, check) ( ( ((flags) & (check)) == (check) ) ? TRUE : FALSE ) - -#define NM_FLAGS_SET(flags, val) ({ \ - const typeof(flags) _flags = (flags); \ - const typeof(flags) _val = (val); \ - \ - _flags | _val; \ - }) - -#define NM_FLAGS_UNSET(flags, val) ({ \ - const typeof(flags) _flags = (flags); \ - const typeof(flags) _val = (val); \ - \ - _flags & (~_val); \ - }) - -#define NM_FLAGS_ASSIGN(flags, val, assign) ({ \ - const typeof(flags) _flags = (flags); \ - const typeof(flags) _val = (val); \ - \ - (assign) \ - ? _flags | (_val) \ - : _flags & (~_val); \ - }) - -#define NM_FLAGS_ASSIGN_MASK(flags, mask, val) ({ \ - const typeof(flags) _flags = (flags); \ - const typeof(flags) _mask = (mask); \ - const typeof(flags) _val = (val); \ - \ - ((_flags & ~_mask) | (_mask & _val)); \ - }) +#define NM_FLAGS_HAS(flags, check) \ + (G_STATIC_ASSERT_EXPR((check) > 0 && ((check) & ((check) -1)) == 0), \ + NM_FLAGS_ANY((flags), (check))) + +#define NM_FLAGS_ANY(flags, check) ((((flags) & (check)) != 0) ? TRUE : FALSE) +#define NM_FLAGS_ALL(flags, check) ((((flags) & (check)) == (check)) ? TRUE : FALSE) + +#define NM_FLAGS_SET(flags, val) \ + ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + _flags | _val; \ + }) + +#define NM_FLAGS_UNSET(flags, val) \ + ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + _flags &(~_val); \ + }) + +#define NM_FLAGS_ASSIGN(flags, val, assign) \ + ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + (assign) ? _flags | (_val) : _flags &(~_val); \ + }) + +#define NM_FLAGS_ASSIGN_MASK(flags, mask, val) \ + ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _mask = (mask); \ + const typeof(flags) _val = (val); \ + \ + ((_flags & ~_mask) | (_mask & _val)); \ + }) /*****************************************************************************/ -#define _NM_BACKPORT_SYMBOL_IMPL(version, return_type, orig_func, versioned_func, args_typed, args) \ -return_type versioned_func args_typed; \ -_nm_externally_visible return_type versioned_func args_typed \ -{ \ - return orig_func args; \ -} \ -return_type orig_func args_typed; \ -__asm__(".symver "G_STRINGIFY(versioned_func)", "G_STRINGIFY(orig_func)"@"G_STRINGIFY(version)) +#define _NM_BACKPORT_SYMBOL_IMPL(version, \ + return_type, \ + orig_func, \ + versioned_func, \ + args_typed, \ + args) \ + return_type versioned_func args_typed; \ + _nm_externally_visible return_type versioned_func args_typed \ + { \ + return orig_func args; \ + } \ + return_type orig_func args_typed; \ + __asm__(".symver " G_STRINGIFY(versioned_func) ", " G_STRINGIFY(orig_func) "@" G_STRINGIFY( \ + version)) #define NM_BACKPORT_SYMBOL(version, return_type, func, args_typed, args) \ -_NM_BACKPORT_SYMBOL_IMPL(version, return_type, func, _##func##_##version, args_typed, args) + _NM_BACKPORT_SYMBOL_IMPL(version, return_type, func, _##func##_##version, args_typed, args) /*****************************************************************************/ /* mirrors g_ascii_isspace() and what we consider spaces in general. */ -#define NM_ASCII_SPACES " \n\t\r\f" +#define NM_ASCII_SPACES " \n\t\r\f" /* Like NM_ASCII_SPACES, but without "\f" (0x0c, Formfeed Page Break). * This is what for example systemd calls WHITESPACE and what it uses to tokenize * the kernel command line. */ #define NM_ASCII_WHITESPACES " \n\t\r" -#define nm_str_skip_leading_spaces(str) \ - ({ \ - typeof (*(str)) *_str_sls = (str); \ - _nm_unused const char *const _str_type_check = _str_sls; \ - \ - if (_str_sls) { \ - while (g_ascii_isspace (_str_sls[0])) \ - _str_sls++; \ - } \ - _str_sls; \ - }) +#define nm_str_skip_leading_spaces(str) \ + ({ \ + typeof(*(str)) * _str_sls = (str); \ + _nm_unused const char *const _str_type_check = _str_sls; \ + \ + if (_str_sls) { \ + while (g_ascii_isspace(_str_sls[0])) \ + _str_sls++; \ + } \ + _str_sls; \ + }) static inline char * -nm_strstrip (char *str) +nm_strstrip(char *str) { - /* g_strstrip doesn't like NULL. */ - return str ? g_strstrip (str) : NULL; + /* g_strstrip doesn't like NULL. */ + return str ? g_strstrip(str) : NULL; } static inline const char * -nm_strstrip_avoid_copy (const char *str, char **str_free) +nm_strstrip_avoid_copy(const char *str, char **str_free) { - gsize l; - char *s; - - nm_assert (str_free && !*str_free); - - if (!str) - return NULL; - - str = nm_str_skip_leading_spaces (str); - l = strlen (str); - if ( l == 0 - || !g_ascii_isspace (str[l - 1])) - return str; - while ( l > 0 - && g_ascii_isspace (str[l - 1])) - l--; - - s = g_new (char, l + 1); - memcpy (s, str, l); - s[l] = '\0'; - *str_free = s; - return s; + gsize l; + char *s; + + nm_assert(str_free && !*str_free); + + if (!str) + return NULL; + + str = nm_str_skip_leading_spaces(str); + l = strlen(str); + if (l == 0 || !g_ascii_isspace(str[l - 1])) + return str; + while (l > 0 && g_ascii_isspace(str[l - 1])) + l--; + + s = g_new(char, l + 1); + memcpy(s, str, l); + s[l] = '\0'; + *str_free = s; + return s; } -#define nm_strstrip_avoid_copy_a(alloca_maxlen, str, out_str_free) \ - ({ \ - const char *_str_ssac = (str); \ - char **_out_str_free_ssac = (out_str_free); \ - \ - G_STATIC_ASSERT_EXPR ((alloca_maxlen) > 0); \ - \ - nm_assert ( _out_str_free_ssac || ((alloca_maxlen) > (str ? strlen (str) : 0u))); \ - nm_assert (!_out_str_free_ssac || !*_out_str_free_ssac); \ - \ - if (_str_ssac) { \ - _str_ssac = nm_str_skip_leading_spaces (_str_ssac); \ - if (_str_ssac[0] != '\0') { \ - gsize _l = strlen (_str_ssac); \ - \ - if (g_ascii_isspace (_str_ssac[--_l])) { \ - while ( _l > 0 \ - && g_ascii_isspace (_str_ssac[_l - 1])) { \ - _l--; \ - } \ - _str_ssac = nm_strndup_a ((alloca_maxlen), _str_ssac, _l, _out_str_free_ssac); \ - } \ - } \ - } \ - \ - _str_ssac; \ - }) +#define nm_strstrip_avoid_copy_a(alloca_maxlen, str, out_str_free) \ + ({ \ + const char *_str_ssac = (str); \ + char ** _out_str_free_ssac = (out_str_free); \ + \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0); \ + \ + nm_assert(_out_str_free_ssac || ((alloca_maxlen) > (str ? strlen(str) : 0u))); \ + nm_assert(!_out_str_free_ssac || !*_out_str_free_ssac); \ + \ + if (_str_ssac) { \ + _str_ssac = nm_str_skip_leading_spaces(_str_ssac); \ + if (_str_ssac[0] != '\0') { \ + gsize _l = strlen(_str_ssac); \ + \ + if (g_ascii_isspace(_str_ssac[--_l])) { \ + while (_l > 0 && g_ascii_isspace(_str_ssac[_l - 1])) { \ + _l--; \ + } \ + _str_ssac = nm_strndup_a((alloca_maxlen), _str_ssac, _l, _out_str_free_ssac); \ + } \ + } \ + } \ + \ + _str_ssac; \ + }) static inline gboolean -nm_str_is_stripped (const char *str) +nm_str_is_stripped(const char *str) { - if (str && str[0]) { - if ( g_ascii_isspace (str[0]) - || g_ascii_isspace (str[strlen (str) - 1])) - return FALSE; - } - return TRUE; + if (str && str[0]) { + if (g_ascii_isspace(str[0]) || g_ascii_isspace(str[strlen(str) - 1])) + return FALSE; + } + return TRUE; } /* g_ptr_array_sort()'s compare function takes pointers to the @@ -1626,80 +1411,54 @@ nm_str_is_stripped (const char *str) * * Like strcmp(), this function is not forgiving to accept %NULL. */ static inline int -nm_strcmp_p (gconstpointer a, gconstpointer b) +nm_strcmp_p(gconstpointer a, gconstpointer b) { - const char *s1 = *((const char **) a); - const char *s2 = *((const char **) b); + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); - return strcmp (s1, s2); + return strcmp(s1, s2); } /*****************************************************************************/ -/* 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__ +static inline int +_NM_IN_STRSET_ASCII_CASE_op_streq(const char *x, const char *s) +{ + return s && g_ascii_strcasecmp(x, s) == 0; +} -/*****************************************************************************/ +#define NM_IN_STRSET_ASCII_CASE(x, ...) \ + _NM_IN_STRSET_EVAL_N(||, \ + _NM_IN_STRSET_ASCII_CASE_op_streq, \ + x, \ + NM_NARG(__VA_ARGS__), \ + __VA_ARGS__) + +#define NM_STR_HAS_SUFFIX_ASCII_CASE(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)) \ + && (g_ascii_strcasecmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "") == 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_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(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)) \ + && (g_ascii_strcasecmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "") == 0)); \ + }) /*****************************************************************************/ -#define nm_g_slice_free(ptr) \ - g_slice_free (typeof (*(ptr)), ptr) +#define nm_g_slice_free(ptr) g_slice_free(typeof(*(ptr)), ptr) /*****************************************************************************/ @@ -1721,83 +1480,88 @@ nm_strcmp_p (gconstpointer a, gconstpointer b) * passing a %NULL @data pointer. */ static inline gpointer -nm_memdup (gconstpointer data, gsize size) +nm_memdup(gconstpointer data, gsize size) { - gpointer p; + gpointer p; - if (size == 0) - return NULL; - p = g_malloc (size); - memcpy (p, data, size); - return p; + if (size == 0) + return NULL; + p = g_malloc(size); + memcpy(p, data, size); + return p; } -#define nm_malloc_maybe_a(alloca_maxlen, bytes, to_free) \ - ({ \ - const gsize _bytes = (bytes); \ - typeof (to_free) _to_free = (to_free); \ - typeof (*_to_free) _ptr; \ - \ - G_STATIC_ASSERT_EXPR ((alloca_maxlen) <= 500); \ - nm_assert (_to_free && !*_to_free); \ - \ - if (_bytes <= (alloca_maxlen)) { \ - _ptr = g_alloca (_bytes); \ - } else { \ - _ptr = g_malloc (_bytes); \ - *_to_free = _ptr; \ - }; \ - \ - _ptr; \ - }) +#define nm_malloc_maybe_a(alloca_maxlen, bytes, to_free) \ + ({ \ + const gsize _bytes = (bytes); \ + typeof(to_free) _to_free = (to_free); \ + typeof(*_to_free) _ptr; \ + \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 500u); \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0u); \ + nm_assert(_to_free && !*_to_free); \ + \ + if (G_LIKELY(_bytes <= (alloca_maxlen))) { \ + _ptr = _bytes > 0u ? g_alloca(_bytes) : NULL; \ + } else { \ + _ptr = g_malloc(_bytes); \ + *_to_free = _ptr; \ + }; \ + \ + _ptr; \ + }) #define nm_malloc0_maybe_a(alloca_maxlen, bytes, to_free) \ - ({ \ - const gsize _bytes = (bytes); \ - typeof (to_free) _to_free = (to_free); \ - typeof (*_to_free) _ptr; \ - \ - G_STATIC_ASSERT_EXPR ((alloca_maxlen) <= 500); \ - nm_assert (_to_free && !*_to_free); \ - \ - if (_bytes <= (alloca_maxlen)) { \ - _ptr = g_alloca (_bytes); \ - memset (_ptr, 0, _bytes); \ - } else { \ - _ptr = g_malloc0 (_bytes); \ - *_to_free = _ptr; \ - }; \ - \ - _ptr; \ - }) - -#define nm_memdup_maybe_a(alloca_maxlen, data, size, to_free) \ - ({ \ - const gsize _size = (size); \ - typeof (to_free) _to_free_md = (to_free); \ - typeof (*_to_free_md) _ptr_md = NULL; \ - \ - nm_assert (_to_free_md && !*_to_free_md); \ - \ - if (_size > 0u) { \ - _ptr_md = nm_malloc_maybe_a ((alloca_maxlen), _size, _to_free_md); \ - memcpy (_ptr_md, (data), _size); \ - } \ - \ - _ptr_md; \ - }) + ({ \ + const gsize _bytes = (bytes); \ + typeof(to_free) _to_free = (to_free); \ + typeof(*_to_free) _ptr; \ + \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 500u); \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0u); \ + nm_assert(_to_free && !*_to_free); \ + \ + if (G_LIKELY(_bytes <= (alloca_maxlen))) { \ + if (_bytes > 0u) { \ + _ptr = g_alloca(_bytes); \ + memset(_ptr, 0, _bytes); \ + } else \ + _ptr = NULL; \ + } else { \ + _ptr = g_malloc0(_bytes); \ + *_to_free = _ptr; \ + }; \ + \ + _ptr; \ + }) + +#define nm_memdup_maybe_a(alloca_maxlen, data, size, to_free) \ + ({ \ + const gsize _size = (size); \ + typeof(to_free) _to_free_md = (to_free); \ + typeof(*_to_free_md) _ptr_md = NULL; \ + \ + nm_assert(_to_free_md && !*_to_free_md); \ + \ + if (_size > 0u) { \ + _ptr_md = nm_malloc_maybe_a((alloca_maxlen), _size, _to_free_md); \ + memcpy(_ptr_md, (data), _size); \ + } \ + \ + _ptr_md; \ + }) static inline char * -_nm_strndup_a_step (char *s, const char *str, gsize len) +_nm_strndup_a_step(char *s, const char *str, gsize len) { - NM_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation"); - NM_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow"); - if (len > 0) - strncpy (s, str, len); - s[len] = '\0'; - return s; - NM_PRAGMA_WARNING_REENABLE; - NM_PRAGMA_WARNING_REENABLE; + NM_PRAGMA_WARNING_DISABLE("-Wstringop-truncation"); + NM_PRAGMA_WARNING_DISABLE("-Wstringop-overflow"); + if (len > 0) + strncpy(s, str, len); + s[len] = '\0'; + return s; + NM_PRAGMA_WARNING_REENABLE; + NM_PRAGMA_WARNING_REENABLE; } /* Similar to g_strndup(), however, if the string (including the terminating @@ -1814,26 +1578,25 @@ _nm_strndup_a_step (char *s, const char *str, gsize len) * bytes, even if strlen(@str) is shorter than that (NUL terminated early). We fill * the buffer with strncpy(), which means, that @str is copied up to the first * NUL character and then filled with NUL characters. */ -#define nm_strndup_a(alloca_maxlen, str, len, out_str_free) \ - ({ \ - const gsize _alloca_maxlen_snd = (alloca_maxlen); \ - const char *const _str_snd = (str); \ - const gsize _len_snd = (len); \ - char **const _out_str_free_snd = (out_str_free); \ - char *_s_snd; \ - \ - G_STATIC_ASSERT_EXPR ((alloca_maxlen) <= 300); \ - \ - if ( _out_str_free_snd \ - && _len_snd >= _alloca_maxlen_snd) { \ - _s_snd = g_malloc (_len_snd + 1); \ - *_out_str_free_snd = _s_snd; \ - } else { \ - g_assert (_len_snd < _alloca_maxlen_snd); \ - _s_snd = g_alloca (_len_snd + 1); \ - } \ - _nm_strndup_a_step (_s_snd, _str_snd, _len_snd); \ - }) +#define nm_strndup_a(alloca_maxlen, str, len, out_str_free) \ + ({ \ + const gsize _alloca_maxlen_snd = (alloca_maxlen); \ + const char *const _str_snd = (str); \ + const gsize _len_snd = (len); \ + char **const _out_str_free_snd = (out_str_free); \ + char * _s_snd; \ + \ + G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 300); \ + \ + if (_out_str_free_snd && _len_snd >= _alloca_maxlen_snd) { \ + _s_snd = g_malloc(_len_snd + 1); \ + *_out_str_free_snd = _s_snd; \ + } else { \ + g_assert(_len_snd < _alloca_maxlen_snd); \ + _s_snd = g_alloca(_len_snd + 1); \ + } \ + _nm_strndup_a_step(_s_snd, _str_snd, _len_snd); \ + }) /*****************************************************************************/ @@ -1846,45 +1609,45 @@ _nm_strndup_a_step (char *s, const char *str, gsize len) * * Instead, this generic macro is supposed to handle all integers correctly. */ #if _NM_CC_SUPPORT_GENERIC -#define nm_strdup_int(val) \ - _Generic ((val), \ - char: g_strdup_printf ("%d", (int) (val)), \ - \ - signed char: g_strdup_printf ("%d", (signed) (val)), \ - signed short: g_strdup_printf ("%d", (signed) (val)), \ - signed: g_strdup_printf ("%d", (signed) (val)), \ - signed long: g_strdup_printf ("%ld", (signed long) (val)), \ - signed long long: g_strdup_printf ("%lld", (signed long long) (val)), \ - \ - unsigned char: g_strdup_printf ("%u", (unsigned) (val)), \ - unsigned short: g_strdup_printf ("%u", (unsigned) (val)), \ - unsigned: g_strdup_printf ("%u", (unsigned) (val)), \ - unsigned long: g_strdup_printf ("%lu", (unsigned long) (val)), \ - unsigned long long: g_strdup_printf ("%llu", (unsigned long long) (val)) \ - ) + #define nm_strdup_int(val) \ + _Generic((val), char \ + : g_strdup_printf("%d", (int) (val)), \ + \ + signed char \ + : g_strdup_printf("%d", (signed) (val)), signed short \ + : g_strdup_printf("%d", (signed) (val)), signed \ + : g_strdup_printf("%d", (signed) (val)), signed long \ + : g_strdup_printf("%ld", (signed long) (val)), signed long long \ + : g_strdup_printf("%lld", (signed long long) (val)), \ + \ + unsigned char \ + : g_strdup_printf("%u", (unsigned) (val)), unsigned short \ + : g_strdup_printf("%u", (unsigned) (val)), unsigned \ + : g_strdup_printf("%u", (unsigned) (val)), unsigned long \ + : g_strdup_printf("%lu", (unsigned long) (val)), unsigned long long \ + : g_strdup_printf("%llu", (unsigned long long) (val))) #else -#define nm_strdup_int(val) \ - ( ( sizeof (val) == sizeof (guint64) \ - && ((typeof (val)) -1) > 0) \ - ? g_strdup_printf ("%"G_GUINT64_FORMAT, (guint64) (val)) \ - : g_strdup_printf ("%"G_GINT64_FORMAT, (gint64) (val))) + #define nm_strdup_int(val) \ + ((sizeof(val) == sizeof(guint64) && ((typeof(val)) - 1) > 0) \ + ? g_strdup_printf("%" G_GUINT64_FORMAT, (guint64)(val)) \ + : g_strdup_printf("%" G_GINT64_FORMAT, (gint64)(val))) #endif /*****************************************************************************/ static inline guint -nm_encode_version (guint major, guint minor, guint micro) +nm_encode_version(guint major, guint minor, guint micro) { - /* analog to the preprocessor macro NM_ENCODE_VERSION(). */ - return (major << 16) | (minor << 8) | micro; + /* analog to the preprocessor macro NM_ENCODE_VERSION(). */ + return (major << 16) | (minor << 8) | micro; } static inline void -nm_decode_version (guint version, guint *major, guint *minor, guint *micro) +nm_decode_version(guint version, guint *major, guint *minor, guint *micro) { - *major = (version & 0xFFFF0000u) >> 16; - *minor = (version & 0x0000FF00u) >> 8; - *micro = (version & 0x000000FFu); + *major = (version & 0xFFFF0000u) >> 16; + *minor = (version & 0x0000FF00u) >> 8; + *micro = (version & 0x000000FFu); } /*****************************************************************************/ @@ -1896,10 +1659,12 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) * negative '-' prefix (hence works correctly on signed * types). Includes space for the trailing NUL. */ #define NM_DECIMAL_STR_MAX(type) \ - (2+(sizeof(type) <= 1 ? 3 : \ - sizeof(type) <= 2 ? 5 : \ - sizeof(type) <= 4 ? 10 : \ - sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) + (2 \ + + (sizeof(type) <= 1 ? 3 \ + : sizeof(type) <= 2 ? 5 \ + : sizeof(type) <= 4 ? 10 \ + : sizeof(type) <= 8 ? 20 \ + : sizeof(int[-2 * (sizeof(type) > 8)]))) /*****************************************************************************/ @@ -1910,138 +1675,89 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) * * Thus, the maximum stack allocated buffer will be @trunc_at+3. The maximum * buffer size must be a constant and not larger than 300. */ -#define nm_strquote_a(trunc_at, str) \ - ({ \ - const char *const _str = (str); \ - \ - (_str \ - ? ({ \ - const gsize _trunc_at = (trunc_at); \ - const gsize _strlen_trunc = NM_MIN (strlen (_str), _trunc_at); \ - char *_buf; \ - \ - G_STATIC_ASSERT_EXPR ((trunc_at) <= 300); \ - \ - _buf = g_alloca (_strlen_trunc + 3); \ - _buf[0] = '"'; \ - memcpy (&_buf[1], _str, _strlen_trunc); \ - _buf[_strlen_trunc + 1] = _str[_strlen_trunc] ? '^' : '"'; \ - _buf[_strlen_trunc + 2] = '\0'; \ - _buf; \ - }) \ - : "(null)"); \ - }) - -#define nm_sprintf_buf(buf, format, ...) \ - ({ \ - char * _buf = (buf); \ - int _buf_len; \ - \ - /* some static assert trying to ensure that the buffer is statically allocated. - * It disallows a buffer size of sizeof(gpointer) to catch that. */ \ - G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *)); \ - _buf_len = g_snprintf (_buf, sizeof (buf), \ - ""format"", ##__VA_ARGS__); \ - nm_assert (_buf_len < sizeof (buf)); \ - _buf; \ - }) +#define nm_strquote_a(trunc_at, str) \ + ({ \ + const char *const _str = (str); \ + \ + (_str ? ({ \ + const gsize _trunc_at = (trunc_at); \ + const gsize _strlen_trunc = NM_MIN(strlen(_str), _trunc_at); \ + char * _buf; \ + \ + G_STATIC_ASSERT_EXPR((trunc_at) <= 300); \ + \ + _buf = g_alloca(_strlen_trunc + 3); \ + _buf[0] = '"'; \ + memcpy(&_buf[1], _str, _strlen_trunc); \ + _buf[_strlen_trunc + 1] = _str[_strlen_trunc] ? '^' : '"'; \ + _buf[_strlen_trunc + 2] = '\0'; \ + _buf; \ + }) \ + : "(null)"); \ + }) + +#define nm_sprintf_buf(buf, format, ...) \ + ({ \ + char *_buf = (buf); \ + int _buf_len; \ + \ + /* some static assert trying to ensure that the buffer is statically allocated. + * It disallows a buffer size of sizeof(gpointer) to catch that. */ \ + G_STATIC_ASSERT(G_N_ELEMENTS(buf) == sizeof(buf) && sizeof(buf) != sizeof(char *)); \ + _buf_len = g_snprintf(_buf, sizeof(buf), "" format "", ##__VA_ARGS__); \ + nm_assert(_buf_len < sizeof(buf)); \ + _buf; \ + }) /* it is "unsafe" because @bufsize must not be a constant expression and * there is no check at compiletime. Regardless of that, the buffer size * must not be larger than 300 bytes, as this gets stack allocated. */ -#define nm_sprintf_buf_unsafe_a(bufsize, format, ...) \ - ({ \ - char *_buf; \ - int _buf_len; \ - typeof (bufsize) _bufsize = (bufsize); \ - \ - nm_assert (_bufsize <= 300); \ - \ - _buf = g_alloca (_bufsize); \ - _buf_len = g_snprintf (_buf, _bufsize, \ - ""format"", ##__VA_ARGS__); \ - nm_assert (_buf_len >= 0 && _buf_len < _bufsize); \ - _buf; \ - }) - -#define nm_sprintf_bufa(bufsize, format, ...) \ - ({ \ - G_STATIC_ASSERT_EXPR ((bufsize) <= 300); \ - nm_sprintf_buf_unsafe_a ((bufsize), format, ##__VA_ARGS__); \ - }) +#define nm_sprintf_buf_unsafe_a(bufsize, format, ...) \ + ({ \ + char *_buf; \ + int _buf_len; \ + typeof(bufsize) _bufsize = (bufsize); \ + \ + nm_assert(_bufsize <= 300); \ + \ + _buf = g_alloca(_bufsize); \ + _buf_len = g_snprintf(_buf, _bufsize, "" format "", ##__VA_ARGS__); \ + nm_assert(_buf_len >= 0 && _buf_len < _bufsize); \ + _buf; \ + }) + +#define nm_sprintf_bufa(bufsize, format, ...) \ + ({ \ + G_STATIC_ASSERT_EXPR((bufsize) <= 300); \ + nm_sprintf_buf_unsafe_a((bufsize), format, ##__VA_ARGS__); \ + }) /* aims to alloca() a buffer and fill it with printf(format, name). * Note that format must not contain any format specifier except * "%s". * If the resulting string would be too large for stack allocation, * it allocates a buffer with g_malloc() and assigns it to *p_val_to_free. */ -#define nm_construct_name_a(format, name, p_val_to_free) \ - ({ \ - const char *const _name = (name); \ - char **const _p_val_to_free = (p_val_to_free); \ - const gsize _name_len = strlen (_name); \ - char *_buf2; \ - \ - nm_assert (_p_val_to_free && !*_p_val_to_free); \ - if ( NM_STRLEN (format) <= 290 \ - && _name_len < (gsize) (290 - NM_STRLEN (format))) \ - _buf2 = nm_sprintf_buf_unsafe_a (NM_STRLEN (format) + _name_len, format, _name); \ - else { \ - _buf2 = g_strdup_printf (format, _name); \ - *_p_val_to_free = _buf2; \ - } \ - (const char *) _buf2; \ - }) +#define nm_construct_name_a(format, name, p_val_to_free) \ + ({ \ + const char *const _name = (name); \ + char **const _p_val_to_free = (p_val_to_free); \ + const gsize _name_len = strlen(_name); \ + char * _buf2; \ + \ + nm_assert(_p_val_to_free && !*_p_val_to_free); \ + if (NM_STRLEN(format) <= 290 && _name_len < (gsize)(290 - NM_STRLEN(format))) \ + _buf2 = nm_sprintf_buf_unsafe_a(NM_STRLEN(format) + _name_len, format, _name); \ + else { \ + _buf2 = g_strdup_printf(format, _name); \ + *_p_val_to_free = _buf2; \ + } \ + (const char *) _buf2; \ + }) /*****************************************************************************/ -/** - * 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(). + /* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR(). * As glib's implementation uses a local variable _g_boolean_var_, * we cannot do * g_assert (some_macro ()); @@ -2051,84 +1767,24 @@ 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) + #undef _G_BOOLEAN_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) /*****************************************************************************/ -NM_AUTO_DEFINE_FCN_VOID0 (GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock) +NM_AUTO_DEFINE_FCN_VOID0(GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock); -#define nm_auto_unlock_g_mutex nm_auto (_nm_auto_unlock_g_mutex) +#define nm_auto_unlock_g_mutex nm_auto(_nm_auto_unlock_g_mutex) #define _NM_G_MUTEX_LOCKED(lock, uniq) \ - nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = (lock) + nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = (lock) -#define NM_G_MUTEX_LOCKED(lock) \ - _NM_G_MUTEX_LOCKED (lock, NM_UNIQ) +#define NM_G_MUTEX_LOCKED(lock) _NM_G_MUTEX_LOCKED(lock, NM_UNIQ) /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-obj.h b/shared/nm-glib-aux/nm-obj.h index cbfdba63..9bbe05a4 100644 --- a/shared/nm-glib-aux/nm-obj.h +++ b/shared/nm-glib-aux/nm-obj.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -14,51 +14,51 @@ typedef struct _NMObjBaseInst NMObjBaseInst; typedef struct _NMObjBaseClass NMObjBaseClass; struct _NMObjBaseInst { - /* The first field of NMObjBaseInst is compatible with GObject. - * Basically, NMObjBaseInst is an abstract base type of GTypeInstance. - * - * If you do it right, you may derive a type of NMObjBaseInst as a proper GTypeInstance. - * That involves allocating a GType for it, which can be inconvenient because - * a GType is dynamically created (and the class can no longer be immutable - * memory). - * - * Even if your implementation of NMObjBaseInst is not a full fledged GType(Instance), - * you still can use GTypeInstances in the same context as you can decide based on the - * NMObjBaseClass with what kind of object you are dealing with. - * - * Basically, the only thing NMObjBaseInst gives you is access to an - * NMObjBaseClass instance. - */ - union { - const NMObjBaseClass *klass; - GTypeInstance g_type_instance; - }; + /* The first field of NMObjBaseInst is compatible with GObject. + * Basically, NMObjBaseInst is an abstract base type of GTypeInstance. + * + * If you do it right, you may derive a type of NMObjBaseInst as a proper GTypeInstance. + * That involves allocating a GType for it, which can be inconvenient because + * a GType is dynamically created (and the class can no longer be immutable + * memory). + * + * Even if your implementation of NMObjBaseInst is not a full fledged GType(Instance), + * you still can use GTypeInstances in the same context as you can decide based on the + * NMObjBaseClass with what kind of object you are dealing with. + * + * Basically, the only thing NMObjBaseInst gives you is access to an + * NMObjBaseClass instance. + */ + union { + const NMObjBaseClass *klass; + GTypeInstance g_type_instance; + }; }; struct _NMObjBaseClass { - /* NMObjBaseClass is the base class of all NMObjBaseInst implementations. - * Note that it is also an abstract super class of GTypeInstance, that means - * you may implement a NMObjBaseClass as a subtype of GTypeClass. - * - * For that to work, you must properly set the GTypeClass instance (and its - * GType). - * - * Note that to implement a NMObjBaseClass that is *not* a GTypeClass, you wouldn't - * set the GType. Hence, this field is only useful for type implementations that actually - * extend GTypeClass. - * - * In a way it is wrong that NMObjBaseClass has the GType member, because it is - * a base class of GTypeClass and doesn't necessarily use the GType. However, - * it is here so that G_TYPE_CHECK_INSTANCE_TYPE() and friends work correctly - * on any NMObjectClass. That means, while not necessary, it is convenient that - * a NMObjBaseClass has all members of GTypeClass. - * Also note that usually you have only one instance of a certain type, so this - * wastes just a few bytes for the unneeded GType. - */ - union { - GType g_type; - GTypeClass g_type_class; - }; + /* NMObjBaseClass is the base class of all NMObjBaseInst implementations. + * Note that it is also an abstract super class of GTypeInstance, that means + * you may implement a NMObjBaseClass as a subtype of GTypeClass. + * + * For that to work, you must properly set the GTypeClass instance (and its + * GType). + * + * Note that to implement a NMObjBaseClass that is *not* a GTypeClass, you wouldn't + * set the GType. Hence, this field is only useful for type implementations that actually + * extend GTypeClass. + * + * In a way it is wrong that NMObjBaseClass has the GType member, because it is + * a base class of GTypeClass and doesn't necessarily use the GType. However, + * it is here so that G_TYPE_CHECK_INSTANCE_TYPE() and friends work correctly + * on any NMObjectClass. That means, while not necessary, it is convenient that + * a NMObjBaseClass has all members of GTypeClass. + * Also note that usually you have only one instance of a certain type, so this + * wastes just a few bytes for the unneeded GType. + */ + union { + GType g_type; + GTypeClass g_type_class; + }; }; /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-random-utils.c b/shared/nm-glib-aux/nm-random-utils.c index 95063c94..0c8b2758 100644 --- a/shared/nm-glib-aux/nm-random-utils.c +++ b/shared/nm-glib-aux/nm-random-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -10,9 +10,9 @@ #include <fcntl.h> #if USE_SYS_RANDOM_H -#include <sys/random.h> + #include <sys/random.h> #else -#include <linux/random.h> + #include <linux/random.h> #endif #include "nm-shared-utils.h" @@ -41,109 +41,108 @@ * a warning. */ gboolean -nm_utils_random_bytes (void *p, size_t n) +nm_utils_random_bytes(void *p, size_t n) { - int fd; - int r; - gboolean has_high_quality = TRUE; - gboolean urandom_success; - guint8 *buf = p; - gboolean avoid_urandom = FALSE; + int fd; + int r; + gboolean has_high_quality = TRUE; + gboolean urandom_success; + guint8 * buf = p; + gboolean avoid_urandom = FALSE; - g_return_val_if_fail (p, FALSE); - g_return_val_if_fail (n > 0, FALSE); + g_return_val_if_fail(p, FALSE); + g_return_val_if_fail(n > 0, FALSE); #if HAVE_GETRANDOM - { - static gboolean have_syscall = TRUE; - - if (have_syscall) { - r = getrandom (buf, n, GRND_NONBLOCK); - if (r > 0) { - if ((size_t) r == n) - return TRUE; - - /* no or partial read. There is not enough entropy. - * Fill the rest reading from urandom, and remember that - * some bits are not high quality. */ - nm_assert (r < n); - buf += r; - n -= r; - has_high_quality = FALSE; - - /* At this point, we don't want to read /dev/urandom, because - * the entropy pool is low (early boot?), and asking for more - * entropy causes kernel messages to be logged. - * - * We use our fallback via GRand. Note that g_rand_new() also - * tries to seed itself with data from /dev/urandom, but since - * we reuse the instance, it shouldn't matter. */ - avoid_urandom = TRUE; - } else { - if (errno == ENOSYS) { - /* no support for getrandom(). We don't know whether - * we urandom will give us good quality. Assume yes. */ - have_syscall = FALSE; - } else { - /* unknown error. We'll read urandom below, but we don't have - * high-quality randomness. */ - has_high_quality = FALSE; - } - } - } - } + { + static gboolean have_syscall = TRUE; + + if (have_syscall) { + r = getrandom(buf, n, GRND_NONBLOCK); + if (r > 0) { + if ((size_t) r == n) + return TRUE; + + /* no or partial read. There is not enough entropy. + * Fill the rest reading from urandom, and remember that + * some bits are not high quality. */ + nm_assert(r < n); + buf += r; + n -= r; + has_high_quality = FALSE; + + /* At this point, we don't want to read /dev/urandom, because + * the entropy pool is low (early boot?), and asking for more + * entropy causes kernel messages to be logged. + * + * We use our fallback via GRand. Note that g_rand_new() also + * tries to seed itself with data from /dev/urandom, but since + * we reuse the instance, it shouldn't matter. */ + avoid_urandom = TRUE; + } else { + if (errno == ENOSYS) { + /* no support for getrandom(). We don't know whether + * we urandom will give us good quality. Assume yes. */ + have_syscall = FALSE; + } else { + /* unknown error. We'll read urandom below, but we don't have + * high-quality randomness. */ + has_high_quality = FALSE; + } + } + } + } #endif - urandom_success = FALSE; - if (!avoid_urandom) { + urandom_success = FALSE; + if (!avoid_urandom) { fd_open: - fd = open ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); - if (fd < 0) { - r = errno; - if (r == EINTR) - goto fd_open; - } else { - r = nm_utils_fd_read_loop_exact (fd, buf, n, TRUE); - nm_close (fd); - if (r >= 0) - urandom_success = TRUE; - } - } - - if (!urandom_success) { - static _nm_thread_local GRand *rand = NULL; - gsize i; - int j; - - /* we failed to fill the bytes reading from urandom. - * Fill the bits using GRand pseudo random numbers. - * - * We don't have good quality. - */ - has_high_quality = FALSE; - - if (G_UNLIKELY (!rand)) - rand = g_rand_new (); - - nm_assert (n > 0); - i = 0; - for (;;) { - const union { - guint32 v32; - guint8 v8[4]; - } v = { - .v32 = g_rand_int (rand), - }; - - for (j = 0; j < 4; ) { - buf[i++] = v.v8[j++]; - if (i >= n) - goto done; - } - } -done: - ; - } - - return has_high_quality; + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); + if (fd < 0) { + r = errno; + if (r == EINTR) + goto fd_open; + } else { + r = nm_utils_fd_read_loop_exact(fd, buf, n, TRUE); + nm_close(fd); + if (r >= 0) + urandom_success = TRUE; + } + } + + if (!urandom_success) { + static _nm_thread_local GRand *rand = NULL; + gsize i; + int j; + + /* we failed to fill the bytes reading from urandom. + * Fill the bits using GRand pseudo random numbers. + * + * We don't have good quality. + */ + has_high_quality = FALSE; + + if (G_UNLIKELY(!rand)) + rand = g_rand_new(); + + nm_assert(n > 0); + i = 0; + for (;;) { + const union { + guint32 v32; + guint8 v8[4]; + } v = { + .v32 = g_rand_int(rand), + }; + + for (j = 0; j < 4;) { + buf[i++] = v.v8[j++]; + if (i >= n) + goto done; + } + } +done:; + } + + return has_high_quality; } diff --git a/shared/nm-glib-aux/nm-random-utils.h b/shared/nm-glib-aux/nm-random-utils.h index 056af38a..5c34d8ab 100644 --- a/shared/nm-glib-aux/nm-random-utils.h +++ b/shared/nm-glib-aux/nm-random-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -6,6 +6,6 @@ #ifndef __NM_RANDOM_UTILS_H__ #define __NM_RANDOM_UTILS_H__ -gboolean nm_utils_random_bytes (void *p, size_t n); +gboolean nm_utils_random_bytes(void *p, size_t n); #endif /* __NM_RANDOM_UTILS_H__ */ diff --git a/shared/nm-glib-aux/nm-ref-string.c b/shared/nm-glib-aux/nm-ref-string.c index 0a0b0d3a..526185f3 100644 --- a/shared/nm-glib-aux/nm-ref-string.c +++ b/shared/nm-glib-aux/nm-ref-string.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #include "nm-default.h" @@ -7,62 +7,61 @@ /*****************************************************************************/ typedef struct { - NMRefString r; - volatile int ref_count; - char str_data[]; + NMRefString r; + volatile int ref_count; + char str_data[]; } RefString; -G_LOCK_DEFINE_STATIC (gl_lock); +G_LOCK_DEFINE_STATIC(gl_lock); static GHashTable *gl_hash; /* the first field of NMRefString is a pointer to the NUL terminated string. * This also allows to compare strings with nm_pstr_equal(), although, pointer * equality might be better. */ -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMRefString, str) == 0); -G_STATIC_ASSERT (G_STRUCT_OFFSET (RefString, r) == 0); -G_STATIC_ASSERT (G_STRUCT_OFFSET (RefString, r.str) == 0); +G_STATIC_ASSERT(G_STRUCT_OFFSET(NMRefString, str) == 0); +G_STATIC_ASSERT(G_STRUCT_OFFSET(RefString, r) == 0); +G_STATIC_ASSERT(G_STRUCT_OFFSET(RefString, r.str) == 0); /*****************************************************************************/ static guint -_ref_string_hash (gconstpointer ptr) +_ref_string_hash(gconstpointer ptr) { - const RefString *a = ptr; - NMHashState h; + const RefString *a = ptr; + NMHashState h; - nm_hash_init (&h, 1463435489u); - nm_hash_update (&h, a->r.str, a->r.len); - return nm_hash_complete (&h); + nm_hash_init(&h, 1463435489u); + nm_hash_update(&h, a->r.str, a->r.len); + return nm_hash_complete(&h); } static gboolean -_ref_string_equal (gconstpointer pa, gconstpointer pb) +_ref_string_equal(gconstpointer pa, gconstpointer pb) { - const RefString *a = pa; - const RefString *b = pb; + const RefString *a = pa; + const RefString *b = pb; - return a->r.len == b->r.len - && memcmp (a->r.str, b->r.str, a->r.len) == 0; + return a->r.len == b->r.len && memcmp(a->r.str, b->r.str, a->r.len) == 0; } /*****************************************************************************/ static void -_ASSERT (const RefString *rstr0) +_ASSERT(const RefString *rstr0) { #if NM_MORE_ASSERTS - int r; + int r; - nm_assert (rstr0); + nm_assert(rstr0); - G_LOCK (gl_lock); - r = g_atomic_int_get (&rstr0->ref_count); + G_LOCK(gl_lock); + r = g_atomic_int_get(&rstr0->ref_count); - nm_assert (r > 0); - nm_assert (r < G_MAXINT); + nm_assert(r > 0); + nm_assert(r < G_MAXINT); - nm_assert (rstr0 == g_hash_table_lookup (gl_hash, rstr0)); - G_UNLOCK (gl_lock); + nm_assert(rstr0 == g_hash_table_lookup(gl_hash, rstr0)); + G_UNLOCK(gl_lock); #endif } @@ -70,7 +69,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 +82,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 @@ -108,88 +107,88 @@ _ASSERT (const RefString *rstr0) * The result must be unrefed with nm_ref_string_unref(). */ NMRefString * -nm_ref_string_new_len (const char *cstr, gsize len) +nm_ref_string_new_len(const char *cstr, gsize len) { - RefString *rstr0; - - G_LOCK (gl_lock); - - if (G_UNLIKELY (!gl_hash)) { - gl_hash = g_hash_table_new_full (_ref_string_hash, _ref_string_equal, g_free, NULL); - rstr0 = NULL; - } else { - NMRefString rr_lookup = { - .len = len, - .str = cstr, - }; - - rstr0 = g_hash_table_lookup (gl_hash, &rr_lookup); - } - - if (rstr0) { - nm_assert (({ - int r = g_atomic_int_get (&rstr0->ref_count); - - (r >= 0 && r < G_MAXINT); - })); - g_atomic_int_inc (&rstr0->ref_count); - } else { - rstr0 = g_malloc (sizeof (RefString) + 1 + len); - rstr0->ref_count = 1; - *((gsize *) &rstr0->r.len) = len; - *((const char **) &rstr0->r.str) = rstr0->str_data; - if (len > 0) - memcpy (rstr0->str_data, cstr, len); - rstr0->str_data[len] = '\0'; - - if (!g_hash_table_add (gl_hash, rstr0)) - nm_assert_not_reached (); - } - - G_UNLOCK (gl_lock); - - return &rstr0->r; + RefString *rstr0; + + G_LOCK(gl_lock); + + if (G_UNLIKELY(!gl_hash)) { + gl_hash = g_hash_table_new_full(_ref_string_hash, _ref_string_equal, g_free, NULL); + rstr0 = NULL; + } else { + NMRefString rr_lookup = { + .len = len, + .str = cstr, + }; + + rstr0 = g_hash_table_lookup(gl_hash, &rr_lookup); + } + + if (rstr0) { + nm_assert(({ + int r = g_atomic_int_get(&rstr0->ref_count); + + (r >= 0 && r < G_MAXINT); + })); + g_atomic_int_inc(&rstr0->ref_count); + } else { + rstr0 = g_malloc(sizeof(RefString) + 1 + len); + rstr0->ref_count = 1; + *((gsize *) &rstr0->r.len) = len; + *((const char **) &rstr0->r.str) = rstr0->str_data; + if (len > 0) + memcpy(rstr0->str_data, cstr, len); + rstr0->str_data[len] = '\0'; + + if (!g_hash_table_add(gl_hash, rstr0)) + nm_assert_not_reached(); + } + + G_UNLOCK(gl_lock); + + return &rstr0->r; } NMRefString * -nm_ref_string_ref (NMRefString *rstr) +nm_ref_string_ref(NMRefString *rstr) { - RefString *const rstr0 = (RefString *) rstr; + RefString *const rstr0 = (RefString *) rstr; - if (!rstr) - return NULL; + if (!rstr) + return NULL; - _ASSERT (rstr0); + _ASSERT(rstr0); - g_atomic_int_inc (&rstr0->ref_count); - return &rstr0->r; + g_atomic_int_inc(&rstr0->ref_count); + return &rstr0->r; } void -_nm_ref_string_unref_non_null (NMRefString *rstr) +_nm_ref_string_unref_non_null(NMRefString *rstr) { - RefString *const rstr0 = (RefString *) rstr; + RefString *const rstr0 = (RefString *) rstr; - _ASSERT (rstr0); + _ASSERT(rstr0); - if (G_LIKELY (!g_atomic_int_dec_and_test (&rstr0->ref_count))) - return; + if (G_LIKELY(!g_atomic_int_dec_and_test(&rstr0->ref_count))) + return; - G_LOCK (gl_lock); + G_LOCK(gl_lock); - /* in the fast-path above, we already decremented the ref-count to zero. - * We need recheck that the ref-count is still zero. */ + /* in the fast-path above, we already decremented the ref-count to zero. + * We need recheck that the ref-count is still zero. */ - if (g_atomic_int_get (&rstr0->ref_count) == 0) { - if (!g_hash_table_remove (gl_hash, rstr0)) - nm_assert_not_reached (); - } else { + if (g_atomic_int_get(&rstr0->ref_count) == 0) { + if (!g_hash_table_remove(gl_hash, rstr0)) + nm_assert_not_reached(); + } else { #if NM_MORE_ASSERTS > 5 - nm_assert (g_hash_table_lookup (gl_hash, rstr0) == rstr0); + nm_assert(g_hash_table_lookup(gl_hash, rstr0) == rstr0); #endif - } + } - G_UNLOCK (gl_lock); + G_UNLOCK(gl_lock); } /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-ref-string.h b/shared/nm-glib-aux/nm-ref-string.h index 60052c45..fe65d6a3 100644 --- a/shared/nm-glib-aux/nm-ref-string.h +++ b/shared/nm-glib-aux/nm-ref-string.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NM_REF_STRING_H__ #define __NM_REF_STRING_H__ @@ -6,78 +6,74 @@ /*****************************************************************************/ typedef struct _NMRefString { - const char *const str; - const gsize len; + const char *const str; + const gsize len; } NMRefString; /*****************************************************************************/ -NMRefString *nm_ref_string_new_len (const char *cstr, gsize len); +NMRefString *nm_ref_string_new_len(const char *cstr, gsize len); static inline NMRefString * -nm_ref_string_new (const char *cstr) +nm_ref_string_new(const char *cstr) { - return cstr - ? nm_ref_string_new_len (cstr, strlen (cstr)) - : NULL; + return cstr ? nm_ref_string_new_len(cstr, strlen(cstr)) : NULL; } -NMRefString *nm_ref_string_ref (NMRefString *rstr); -void _nm_ref_string_unref_non_null (NMRefString *rstr); +NMRefString *nm_ref_string_ref(NMRefString *rstr); +void _nm_ref_string_unref_non_null(NMRefString *rstr); static inline void -nm_ref_string_unref (NMRefString *rstr) +nm_ref_string_unref(NMRefString *rstr) { - if (rstr) - _nm_ref_string_unref_non_null (rstr); + if (rstr) + _nm_ref_string_unref_non_null(rstr); } -NM_AUTO_DEFINE_FCN_VOID0 (NMRefString *, _nm_auto_ref_string, _nm_ref_string_unref_non_null) +NM_AUTO_DEFINE_FCN_VOID0(NMRefString *, _nm_auto_ref_string, _nm_ref_string_unref_non_null); #define nm_auto_ref_string nm_auto(_nm_auto_ref_string) /*****************************************************************************/ static inline const char * -nm_ref_string_get_str (NMRefString *rstr) +nm_ref_string_get_str(NMRefString *rstr) { - return rstr ? rstr->str : NULL; + return rstr ? rstr->str : NULL; } static inline gsize -nm_ref_string_get_len (NMRefString *rstr) +nm_ref_string_get_len(NMRefString *rstr) { - return rstr ? rstr->len : 0u; + return rstr ? rstr->len : 0u; } static inline gboolean -nm_ref_string_equals_str (NMRefString *rstr, const char *s) +nm_ref_string_equals_str(NMRefString *rstr, const char *s) { - /* Note that rstr->len might be greater than strlen(rstr->str). This function does - * not cover that and would ignore everything after the first NUL byte. If you need - * that distinction, this function is not for you. */ + /* Note that rstr->len might be greater than strlen(rstr->str). This function does + * not cover that and would ignore everything after the first NUL byte. If you need + * that distinction, this function is not for you. */ - return rstr - ? (s && nm_streq (rstr->str, s)) - : (s == NULL); + return rstr ? (s && nm_streq(rstr->str, s)) : (s == NULL); } static inline gboolean -NM_IS_REF_STRING (const NMRefString *rstr) +NM_IS_REF_STRING(const NMRefString *rstr) { #if NM_MORE_ASSERTS > 10 - if (rstr) { - nm_auto_ref_string NMRefString *r2 = NULL; + if (rstr) { + nm_auto_ref_string NMRefString *r2 = NULL; - r2 = nm_ref_string_new_len (rstr->str, rstr->len); - nm_assert (rstr == r2); - } + r2 = nm_ref_string_new_len(rstr->str, rstr->len); + nm_assert(rstr == r2); + } #endif - /* Technically, %NULL is also a valid NMRefString (according to nm_ref_string_new(), - * nm_ref_string_get_str() and nm_ref_string_unref()). However, NM_IS_REF_STRING() - * does not think so. If callers want to allow %NULL, they need to check - * separately. */ - return !!rstr; + /* Technically, %NULL is also a valid NMRefString (according to nm_ref_string_new(), + * nm_ref_string_get_str() and nm_ref_string_unref()). However, NM_IS_REF_STRING() + * does not think so. If callers want to allow %NULL, they need to check + * separately. */ + return !!rstr; } #endif /* __NM_REF_STRING_H__ */ diff --git a/shared/nm-glib-aux/nm-secret-utils.c b/shared/nm-glib-aux/nm-secret-utils.c index 78369b5e..3a488673 100644 --- a/shared/nm-glib-aux/nm-secret-utils.c +++ b/shared/nm-glib-aux/nm-secret-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. * Copyright (C) 2015 - 2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. @@ -13,142 +13,142 @@ /*****************************************************************************/ void -nm_explicit_bzero (void *s, gsize n) +nm_explicit_bzero(void *s, gsize n) { - /* gracefully handle n == 0. This is important, callers rely on it. */ - if (G_UNLIKELY (n == 0)) - return; + /* gracefully handle n == 0. This is important, callers rely on it. */ + if (G_UNLIKELY(n == 0)) + return; - nm_assert (s); + nm_assert(s); -#if defined (HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO - explicit_bzero (s, n); +#if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO + explicit_bzero(s, n); #else - { - volatile guint8 *p = s; + { + volatile guint8 *p = s; - memset (s, '\0', n); - while (n-- > 0) - *(p++) = '\0'; - } + memset(s, '\0', n); + while (n-- > 0) + *(p++) = '\0'; + } #endif } void -nm_free_secret (char *secret) +nm_free_secret(char *secret) { - gsize len; - - if (!secret) - return; - -#if GLIB_CHECK_VERSION(2,44,0) - /* Here we mix malloc() and g_malloc() API. Usually we avoid this, - * however since glib 2.44.0 we are in fact guaranteed that g_malloc()/g_free() - * just wraps malloc()/free(), so this is actually fine. - * - * See https://gitlab.gnome.org/GNOME/glib/commit/3be6ed60aa58095691bd697344765e715a327fc1 - */ - len = malloc_usable_size (secret); + gsize len; + + if (!secret) + return; + +#if GLIB_CHECK_VERSION(2, 44, 0) + /* Here we mix malloc() and g_malloc() API. Usually we avoid this, + * however since glib 2.44.0 we are in fact guaranteed that g_malloc()/g_free() + * just wraps malloc()/free(), so this is actually fine. + * + * See https://gitlab.gnome.org/GNOME/glib/commit/3be6ed60aa58095691bd697344765e715a327fc1 + */ + len = malloc_usable_size(secret); #else - len = strlen (secret); + len = strlen(secret); #endif - nm_explicit_bzero (secret, len); - g_free (secret); + nm_explicit_bzero(secret, len); + g_free(secret); } /*****************************************************************************/ char * -nm_secret_strchomp (char *secret) +nm_secret_strchomp(char *secret) { - gsize len; + gsize len; - g_return_val_if_fail (secret, NULL); + g_return_val_if_fail(secret, NULL); - /* it's actually identical to g_strchomp(). However, - * the glib function does not document, that it clears the - * memory. For @secret, we don't only want to truncate trailing - * spaces, we want to overwrite them with NUL. */ + /* it's actually identical to g_strchomp(). However, + * the glib function does not document, that it clears the + * memory. For @secret, we don't only want to truncate trailing + * spaces, we want to overwrite them with NUL. */ - len = strlen (secret); - while (len--) { - if (g_ascii_isspace ((guchar) secret[len])) - secret[len] = '\0'; - else - break; - } + len = strlen(secret); + while (len--) { + if (g_ascii_isspace((guchar) secret[len])) + secret[len] = '\0'; + else + break; + } - return secret; + return secret; } /*****************************************************************************/ GBytes * -nm_secret_copy_to_gbytes (gconstpointer mem, gsize mem_len) +nm_secret_copy_to_gbytes(gconstpointer mem, gsize mem_len) { - NMSecretBuf *b; - - if (mem_len == 0) - return g_bytes_new_static ("", 0); - - nm_assert (mem); - - /* NUL terminate the buffer. - * - * The entire buffer is already malloc'ed and likely has some room for padding. - * Thus, in many situations, this additional byte will cause no overhead in - * practice. - * - * Even if it causes an overhead, do it just for safety. Yes, the returned - * bytes is not a NUL terminated string and no user must rely on this. Do - * not treat binary data as NUL terminated strings, unless you know what - * you are doing. Anyway, defensive FTW. - */ - - b = nm_secret_buf_new (mem_len + 1); - memcpy (b->bin, mem, mem_len); - b->bin[mem_len] = 0; - return nm_secret_buf_to_gbytes_take (b, mem_len); + NMSecretBuf *b; + + if (mem_len == 0) + return g_bytes_new_static("", 0); + + nm_assert(mem); + + /* NUL terminate the buffer. + * + * The entire buffer is already malloc'ed and likely has some room for padding. + * Thus, in many situations, this additional byte will cause no overhead in + * practice. + * + * Even if it causes an overhead, do it just for safety. Yes, the returned + * bytes is not a NUL terminated string and no user must rely on this. Do + * not treat binary data as NUL terminated strings, unless you know what + * you are doing. Anyway, defensive FTW. + */ + + b = nm_secret_buf_new(mem_len + 1); + memcpy(b->bin, mem, mem_len); + b->bin[mem_len] = 0; + return nm_secret_buf_to_gbytes_take(b, mem_len); } /*****************************************************************************/ NMSecretBuf * -nm_secret_buf_new (gsize len) +nm_secret_buf_new(gsize len) { - NMSecretBuf *secret; + NMSecretBuf *secret; - nm_assert (len > 0); + nm_assert(len > 0); - secret = g_malloc (sizeof (NMSecretBuf) + len); - *((gsize *) &(secret->len)) = len; - return secret; + secret = g_malloc(sizeof(NMSecretBuf) + len); + *((gsize *) &(secret->len)) = len; + return secret; } static void -_secret_buf_free (gpointer user_data) +_secret_buf_free(gpointer user_data) { - NMSecretBuf *secret = user_data; + NMSecretBuf *secret = user_data; - nm_assert (secret); - nm_assert (secret->len > 0); + nm_assert(secret); + nm_assert(secret->len > 0); - nm_explicit_bzero (secret->bin, secret->len); - g_free (user_data); + nm_explicit_bzero(secret->bin, secret->len); + g_free(user_data); } GBytes * -nm_secret_buf_to_gbytes_take (NMSecretBuf *secret, gssize actual_len) +nm_secret_buf_to_gbytes_take(NMSecretBuf *secret, gssize actual_len) { - nm_assert (secret); - nm_assert (secret->len > 0); - nm_assert (actual_len == -1 || (actual_len >= 0 && actual_len <= secret->len)); - return g_bytes_new_with_free_func (secret->bin, - actual_len >= 0 ? (gsize) actual_len : secret->len, - _secret_buf_free, - secret); + nm_assert(secret); + nm_assert(secret->len > 0); + nm_assert(actual_len == -1 || (actual_len >= 0 && actual_len <= secret->len)); + return g_bytes_new_with_free_func(secret->bin, + actual_len >= 0 ? (gsize) actual_len : secret->len, + _secret_buf_free, + secret); } /*****************************************************************************/ @@ -164,15 +164,15 @@ nm_secret_buf_to_gbytes_take (NMSecretBuf *secret, gssize actual_len) * Returns: whether all bytes are zero. */ gboolean -nm_utils_memeqzero_secret (gconstpointer data, gsize length) +nm_utils_memeqzero_secret(gconstpointer data, gsize length) { - const guint8 *const key = data; - volatile guint8 acc = 0; - gsize i; - - for (i = 0; i < length; i++) { - acc |= key[i]; - asm volatile("" : "=r"(acc) : "0"(acc)); - } - return 1 & ((acc - 1) >> 8); + const guint8 *const key = data; + volatile guint8 acc = 0; + gsize i; + + for (i = 0; i < length; i++) { + acc |= key[i]; + asm volatile("" : "=r"(acc) : "0"(acc)); + } + return 1 & ((acc - 1) >> 8); } diff --git a/shared/nm-glib-aux/nm-secret-utils.h b/shared/nm-glib-aux/nm-secret-utils.h index 501e7520..2d342e59 100644 --- a/shared/nm-glib-aux/nm-secret-utils.h +++ b/shared/nm-glib-aux/nm-secret-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -10,17 +10,17 @@ /*****************************************************************************/ -void nm_explicit_bzero (void *s, gsize n); +void nm_explicit_bzero(void *s, gsize n); /*****************************************************************************/ -char *nm_secret_strchomp (char *secret); +char *nm_secret_strchomp(char *secret); /*****************************************************************************/ -void nm_free_secret (char *secret); +void nm_free_secret(char *secret); -NM_AUTO_DEFINE_FCN0 (char *, _nm_auto_free_secret, nm_free_secret) +NM_AUTO_DEFINE_FCN0(char *, _nm_auto_free_secret, nm_free_secret); /** * nm_auto_free_secret: * @@ -32,7 +32,7 @@ NM_AUTO_DEFINE_FCN0 (char *, _nm_auto_free_secret, nm_free_secret) /*****************************************************************************/ -GBytes *nm_secret_copy_to_gbytes (gconstpointer mem, gsize mem_len); +GBytes *nm_secret_copy_to_gbytes(gconstpointer mem, gsize mem_len); /*****************************************************************************/ @@ -41,116 +41,116 @@ GBytes *nm_secret_copy_to_gbytes (gconstpointer mem, gsize mem_len); * which ensures that the data pointer (with all len bytes) is cleared upon * cleanup. */ typedef struct { - gsize len; - - /* the data pointer. This pointer must be allocated with malloc (at least - * when used with nm_secret_ptr_clear()). */ - union { - char *str; - void *ptr; - guint8 *bin; - }; + gsize len; + + /* the data pointer. This pointer must be allocated with malloc (at least + * when used with nm_secret_ptr_clear()). */ + union { + char * str; + void * ptr; + guint8 *bin; + }; } NMSecretPtr; static inline void -nm_secret_ptr_bzero (NMSecretPtr *secret) +nm_secret_ptr_bzero(NMSecretPtr *secret) { - if (secret) { - if (secret->len > 0) { - if (secret->ptr) - nm_explicit_bzero (secret->ptr, secret->len); - } - } + if (secret) { + if (secret->len > 0) { + if (secret->ptr) + nm_explicit_bzero(secret->ptr, secret->len); + } + } } #define nm_auto_bzero_secret_ptr nm_auto(nm_secret_ptr_bzero) static inline void -nm_secret_ptr_clear (NMSecretPtr *secret) +nm_secret_ptr_clear(NMSecretPtr *secret) { - if (secret) { - if (secret->len > 0) { - if (secret->ptr) - nm_explicit_bzero (secret->ptr, secret->len); - secret->len = 0; - } - nm_clear_g_free (&secret->ptr); - } + if (secret) { + if (secret->len > 0) { + if (secret->ptr) + nm_explicit_bzero(secret->ptr, secret->len); + secret->len = 0; + } + nm_clear_g_free(&secret->ptr); + } } #define nm_auto_clear_secret_ptr nm_auto(nm_secret_ptr_clear) #define NM_SECRET_PTR_INIT() \ - ((const NMSecretPtr) { \ - .len = 0, \ - .ptr = NULL, \ - }) + ((const NMSecretPtr){ \ + .len = 0, \ + .ptr = NULL, \ + }) #define NM_SECRET_PTR_STATIC(_len) \ - ((const NMSecretPtr) { \ - .len = _len, \ - .ptr = ((guint8 [_len]) { }), \ - }) + ((const NMSecretPtr){ \ + .len = _len, \ + .ptr = ((guint8[_len]){}), \ + }) -#define NM_SECRET_PTR_ARRAY(_arr) \ - ((const NMSecretPtr) { \ - .len = G_N_ELEMENTS (_arr) * sizeof ((_arr)[0]), \ - .ptr = &((_arr)[0]), \ - }) +#define NM_SECRET_PTR_ARRAY(_arr) \ + ((const NMSecretPtr){ \ + .len = G_N_ELEMENTS(_arr) * sizeof((_arr)[0]), \ + .ptr = &((_arr)[0]), \ + }) static inline void -nm_secret_ptr_clear_static (const NMSecretPtr *secret) +nm_secret_ptr_clear_static(const NMSecretPtr *secret) { - if (secret) { - if (secret->len > 0) { - nm_assert (secret->ptr); - nm_explicit_bzero (secret->ptr, secret->len); - } - } + if (secret) { + if (secret->len > 0) { + nm_assert(secret->ptr); + nm_explicit_bzero(secret->ptr, secret->len); + } + } } #define nm_auto_clear_static_secret_ptr nm_auto(nm_secret_ptr_clear_static) static inline void -nm_secret_ptr_move (NMSecretPtr *dst, NMSecretPtr *src) +nm_secret_ptr_move(NMSecretPtr *dst, NMSecretPtr *src) { - if (dst && dst != src) { - *dst = *src; - src->len = 0; - src->ptr = NULL; - } + if (dst && dst != src) { + *dst = *src; + src->len = 0; + src->ptr = NULL; + } } /*****************************************************************************/ typedef struct { - const gsize len; - union { - char str[0]; - guint8 bin[0]; - }; + const gsize len; + union { + char str[0]; + guint8 bin[0]; + }; } NMSecretBuf; static inline void -_nm_auto_free_secret_buf (NMSecretBuf **ptr) +_nm_auto_free_secret_buf(NMSecretBuf **ptr) { - NMSecretBuf *b = *ptr; + NMSecretBuf *b = *ptr; - if (b) { - nm_assert (b->len > 0); - nm_explicit_bzero (b->bin, b->len); - g_free (b); - } + if (b) { + nm_assert(b->len > 0); + nm_explicit_bzero(b->bin, b->len); + g_free(b); + } } #define nm_auto_free_secret_buf nm_auto(_nm_auto_free_secret_buf) -NMSecretBuf *nm_secret_buf_new (gsize len); +NMSecretBuf *nm_secret_buf_new(gsize len); -GBytes *nm_secret_buf_to_gbytes_take (NMSecretBuf *secret, gssize actual_len); +GBytes *nm_secret_buf_to_gbytes_take(NMSecretBuf *secret, gssize actual_len); /*****************************************************************************/ -gboolean nm_utils_memeqzero_secret (gconstpointer data, gsize length); +gboolean nm_utils_memeqzero_secret(gconstpointer data, gsize length); /*****************************************************************************/ @@ -165,28 +165,27 @@ 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(). */ static inline gpointer -nm_secret_mem_realloc (gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) +nm_secret_mem_realloc(gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) { - gpointer m_new; + gpointer m_new; - nm_assert (m_old || cur_len == 0); + nm_assert(m_old || cur_len == 0); - if ( do_bzero_mem - && G_LIKELY (cur_len > 0)) { - m_new = g_malloc (new_len); - if (G_LIKELY (new_len > 0)) - memcpy (m_new, m_old, NM_MIN (cur_len, new_len)); - nm_explicit_bzero (m_old, cur_len); - g_free (m_old); - } else - m_new = g_realloc (m_old, new_len); + if (do_bzero_mem && G_LIKELY(cur_len > 0)) { + m_new = g_malloc(new_len); + if (G_LIKELY(new_len > 0)) + memcpy(m_new, m_old, NM_MIN(cur_len, new_len)); + nm_explicit_bzero(m_old, cur_len); + g_free(m_old); + } else + m_new = g_realloc(m_old, new_len); - return m_new; + return m_new; } /** @@ -200,33 +199,32 @@ 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(). */ static inline gpointer -nm_secret_mem_try_realloc (gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) +nm_secret_mem_try_realloc(gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) { - gpointer m_new; - - nm_assert (m_old || cur_len == 0); - - if ( do_bzero_mem - && G_LIKELY (cur_len > 0)) { - if (G_UNLIKELY (new_len == 0)) - m_new = NULL; - else { - m_new = g_try_malloc (new_len); - if (!m_new) - return NULL; - memcpy (m_new, m_old, NM_MIN (cur_len, new_len)); - } - nm_explicit_bzero (m_old, cur_len); - g_free (m_old); - return m_new; - } - - return g_try_realloc (m_old, new_len); + gpointer m_new; + + nm_assert(m_old || cur_len == 0); + + if (do_bzero_mem && G_LIKELY(cur_len > 0)) { + if (G_UNLIKELY(new_len == 0)) + m_new = NULL; + else { + m_new = g_try_malloc(new_len); + if (!m_new) + return NULL; + memcpy(m_new, m_old, NM_MIN(cur_len, new_len)); + } + nm_explicit_bzero(m_old, cur_len); + g_free(m_old); + return m_new; + } + + return g_try_realloc(m_old, new_len); } /** @@ -245,30 +243,29 @@ nm_secret_mem_try_realloc (gpointer m_old, gboolean do_bzero_mem, gsize cur_len, * but it will always free @m_old. */ static inline gpointer -nm_secret_mem_try_realloc_take (gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) +nm_secret_mem_try_realloc_take(gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len) { - gpointer m_new; - - nm_assert (m_old || cur_len == 0); - - if ( do_bzero_mem - && G_LIKELY (cur_len > 0)) { - if (G_UNLIKELY (new_len == 0)) - m_new = NULL; - else { - m_new = g_try_malloc (new_len); - if (G_LIKELY (m_new)) - memcpy (m_new, m_old, NM_MIN (cur_len, new_len)); - } - nm_explicit_bzero (m_old, cur_len); - g_free (m_old); - return m_new; - } - - m_new = g_try_realloc (m_old, new_len); - if (G_UNLIKELY (!m_new && new_len > 0)) - g_free (m_old); - return m_new; + gpointer m_new; + + nm_assert(m_old || cur_len == 0); + + if (do_bzero_mem && G_LIKELY(cur_len > 0)) { + if (G_UNLIKELY(new_len == 0)) + m_new = NULL; + else { + m_new = g_try_malloc(new_len); + if (G_LIKELY(m_new)) + memcpy(m_new, m_old, NM_MIN(cur_len, new_len)); + } + nm_explicit_bzero(m_old, cur_len); + g_free(m_old); + return m_new; + } + + m_new = g_try_realloc(m_old, new_len); + if (G_UNLIKELY(!m_new && new_len > 0)) + g_free(m_old); + return m_new; } /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 3d1b0098..b0e02381 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2016 Red Hat, Inc. */ @@ -7,6 +7,7 @@ #include "nm-shared-utils.h" +#include <pwd.h> #include <arpa/inet.h> #include <poll.h> #include <fcntl.h> @@ -18,16 +19,19 @@ #include "nm-errno.h" #include "nm-str-buf.h" -G_STATIC_ASSERT (sizeof (NMUtilsNamedEntry) == sizeof (const char *)); -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, value_ptr) == sizeof (const char *)); +G_STATIC_ASSERT(sizeof(NMUtilsNamedEntry) == sizeof(const char *)); +G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, value_ptr) == sizeof(const char *)); /*****************************************************************************/ -const void *const _NM_PTRARRAY_EMPTY[1] = { NULL }; +const char _nm_hexchar_table_lower[16] = "0123456789abcdef"; +const char _nm_hexchar_table_upper[16] = "0123456789ABCDEF"; + +const void *const _NM_PTRARRAY_EMPTY[1] = {NULL}; /*****************************************************************************/ -const NMIPAddr nm_ip_addr_zero = { }; +const NMIPAddr nm_ip_addr_zero = {}; /* this initializes a struct in_addr/in6_addr and allows for untrusted * arguments (like unsuitable @addr_family or @src_len). It's almost safe @@ -42,131 +46,66 @@ const NMIPAddr nm_ip_addr_zero = { }; * Meaning, if @dst is an NMIPAddr union, only the first bytes will be set. * If that matter to you, clear @dst before. */ gboolean -nm_ip_addr_set_from_untrusted (int addr_family, - gpointer dst, - gconstpointer src, - gsize src_len, - int *out_addr_family) -{ - nm_assert (dst); - - switch (addr_family) { - case AF_UNSPEC: - if (!out_addr_family) { - /* when the callers allow undefined @addr_family, they must provide - * an @out_addr_family argument. */ - nm_assert_not_reached (); - return FALSE; - } - switch (src_len) { - case sizeof (struct in_addr): addr_family = AF_INET; break; - case sizeof (struct in6_addr): addr_family = AF_INET6; break; - default: - return FALSE; - } - break; - case AF_INET: - if (src_len != sizeof (struct in_addr)) - return FALSE; - break; - case AF_INET6: - if (src_len != sizeof (struct in6_addr)) - return FALSE; - break; - default: - /* when the callers allow undefined @addr_family, they must provide - * an @out_addr_family argument. */ - nm_assert (out_addr_family); - return FALSE; - } - - nm_assert (src); - - memcpy (dst, src, src_len); - NM_SET_OUT (out_addr_family, addr_family); - return TRUE; +nm_ip_addr_set_from_untrusted(int addr_family, + gpointer dst, + gconstpointer src, + gsize src_len, + int * out_addr_family) +{ + nm_assert(dst); + + switch (addr_family) { + case AF_UNSPEC: + if (!out_addr_family) { + /* when the callers allow undefined @addr_family, they must provide + * an @out_addr_family argument. */ + nm_assert_not_reached(); + return FALSE; + } + switch (src_len) { + case sizeof(struct in_addr): + addr_family = AF_INET; + break; + case sizeof(struct in6_addr): + addr_family = AF_INET6; + break; + default: + return FALSE; + } + break; + case AF_INET: + if (src_len != sizeof(struct in_addr)) + return FALSE; + break; + case AF_INET6: + if (src_len != sizeof(struct in6_addr)) + return FALSE; + break; + default: + /* when the callers allow undefined @addr_family, they must provide + * an @out_addr_family argument. */ + nm_assert(out_addr_family); + return FALSE; + } + + nm_assert(src); + + memcpy(dst, src, src_len); + NM_SET_OUT(out_addr_family, addr_family); + return TRUE; } /*****************************************************************************/ -G_STATIC_ASSERT (ETH_ALEN == sizeof (struct ether_addr)); -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; -} +G_STATIC_ASSERT(ETH_ALEN == sizeof(struct ether_addr)); +G_STATIC_ASSERT(ETH_ALEN == 6); /*****************************************************************************/ pid_t -nm_utils_gettid (void) +nm_utils_gettid(void) { - return (pid_t) syscall (SYS_gettid); + return (pid_t) syscall(SYS_gettid); } /* Used for asserting that this function is called on the main-thread. @@ -175,155 +114,154 @@ nm_utils_gettid (void) * * When forking, the thread-id is again reset upon first call. */ gboolean -_nm_assert_on_main_thread (void) +_nm_assert_on_main_thread(void) { - G_LOCK_DEFINE_STATIC (lock); - static pid_t seen_tid; - static pid_t seen_pid; - pid_t tid; - pid_t pid; - gboolean success = FALSE; + G_LOCK_DEFINE_STATIC(lock); + static pid_t seen_tid; + static pid_t seen_pid; + pid_t tid; + pid_t pid; + gboolean success = FALSE; - tid = nm_utils_gettid (); - nm_assert (tid != 0); + tid = nm_utils_gettid(); + nm_assert(tid != 0); - G_LOCK (lock); + G_LOCK(lock); - if (G_LIKELY (tid == seen_tid)) { - /* we don't care about false positives (when the process forked, and the thread-id - * is accidentally re-used) . It's for assertions only. */ - success = TRUE; - } else { - pid = getpid (); - nm_assert (pid != 0); + if (G_LIKELY(tid == seen_tid)) { + /* we don't care about false positives (when the process forked, and the thread-id + * is accidentally re-used) . It's for assertions only. */ + success = TRUE; + } else { + pid = getpid(); + nm_assert(pid != 0); - if ( seen_tid == 0 - || seen_pid != pid) { - /* either this is the first time we call the function, or the process - * forked. In both cases, remember the thread-id. */ - seen_tid = tid; - seen_pid = pid; - success = TRUE; - } - } + if (seen_tid == 0 || seen_pid != pid) { + /* either this is the first time we call the function, or the process + * forked. In both cases, remember the thread-id. */ + seen_tid = tid; + seen_pid = pid; + success = TRUE; + } + } - G_UNLOCK (lock); + G_UNLOCK(lock); - return success; + return success; } /*****************************************************************************/ void -nm_utils_strbuf_append_c (char **buf, gsize *len, char c) -{ - switch (*len) { - case 0: - return; - case 1: - (*buf)[0] = '\0'; - *len = 0; - (*buf)++; - return; - default: - (*buf)[0] = c; - (*buf)[1] = '\0'; - (*len)--; - (*buf)++; - return; - } +nm_utils_strbuf_append_c(char **buf, gsize *len, char c) +{ + switch (*len) { + case 0: + return; + case 1: + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + (*buf)[0] = c; + (*buf)[1] = '\0'; + (*len)--; + (*buf)++; + return; + } } void -nm_utils_strbuf_append_bin (char **buf, gsize *len, gconstpointer str, gsize str_len) -{ - switch (*len) { - case 0: - return; - case 1: - if (str_len == 0) { - (*buf)[0] = '\0'; - return; - } - (*buf)[0] = '\0'; - *len = 0; - (*buf)++; - return; - default: - if (str_len == 0) { - (*buf)[0] = '\0'; - return; - } - if (str_len >= *len) { - memcpy (*buf, str, *len - 1); - (*buf)[*len - 1] = '\0'; - *buf = &(*buf)[*len]; - *len = 0; - } else { - memcpy (*buf, str, str_len); - *buf = &(*buf)[str_len]; - (*buf)[0] = '\0'; - *len -= str_len; - } - return; - } +nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len) +{ + switch (*len) { + case 0: + return; + case 1: + if (str_len == 0) { + (*buf)[0] = '\0'; + return; + } + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + if (str_len == 0) { + (*buf)[0] = '\0'; + return; + } + if (str_len >= *len) { + memcpy(*buf, str, *len - 1); + (*buf)[*len - 1] = '\0'; + *buf = &(*buf)[*len]; + *len = 0; + } else { + memcpy(*buf, str, str_len); + *buf = &(*buf)[str_len]; + (*buf)[0] = '\0'; + *len -= str_len; + } + return; + } } void -nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str) -{ - gsize src_len; - - switch (*len) { - case 0: - return; - case 1: - if (!str || !*str) { - (*buf)[0] = '\0'; - return; - } - (*buf)[0] = '\0'; - *len = 0; - (*buf)++; - return; - default: - if (!str || !*str) { - (*buf)[0] = '\0'; - return; - } - src_len = g_strlcpy (*buf, str, *len); - if (src_len >= *len) { - *buf = &(*buf)[*len]; - *len = 0; - } else { - *buf = &(*buf)[src_len]; - *len -= src_len; - } - return; - } +nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str) +{ + gsize src_len; + + switch (*len) { + case 0: + return; + case 1: + if (!str || !*str) { + (*buf)[0] = '\0'; + return; + } + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + if (!str || !*str) { + (*buf)[0] = '\0'; + return; + } + src_len = g_strlcpy(*buf, str, *len); + if (src_len >= *len) { + *buf = &(*buf)[*len]; + *len = 0; + } else { + *buf = &(*buf)[src_len]; + *len -= src_len; + } + return; + } } void -nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) +nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...) { - char *p = *buf; - va_list args; - int retval; + char * p = *buf; + va_list args; + int retval; - if (*len == 0) - return; + if (*len == 0) + return; - va_start (args, format); - retval = g_vsnprintf (p, *len, format, args); - va_end (args); + va_start(args, format); + retval = g_vsnprintf(p, *len, format, args); + va_end(args); - if ((gsize) retval >= *len) { - *buf = &p[*len]; - *len = 0; - } else { - *buf = &p[retval]; - *len -= retval; - } + if ((gsize) retval >= *len) { + *buf = &p[*len]; + *len = 0; + } else { + *buf = &p[retval]; + *len -= retval; + } } /** @@ -369,59 +307,58 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) * nm_utils_strbuf_seek_end() would then NUL terminate it. */ void -nm_utils_strbuf_seek_end (char **buf, gsize *len) +nm_utils_strbuf_seek_end(char **buf, gsize *len) { - gsize l; - char *end; + gsize l; + char *end; - nm_assert (len); - nm_assert (buf && *buf); + nm_assert(len); + nm_assert(buf && *buf); - if (*len <= 1) { - if ( *len == 1 - && (*buf)[0]) - goto truncate; - return; - } + if (*len <= 1) { + if (*len == 1 && (*buf)[0]) + goto truncate; + return; + } - end = memchr (*buf, 0, *len); - if (end) { - l = end - *buf; - nm_assert (l < *len); + end = memchr(*buf, 0, *len); + if (end) { + l = end - *buf; + nm_assert(l < *len); - *buf = end; - *len -= l; - return; - } + *buf = end; + *len -= l; + return; + } truncate: - /* hm, no NUL character within len bytes. - * Just NUL terminate the array and consume them - * all. */ - *buf += *len; - (*buf)[-1] = '\0'; - *len = 0; - return; + /* hm, no NUL character within len bytes. + * Just NUL terminate the array and consume them + * all. */ + *buf += *len; + (*buf)[-1] = '\0'; + *len = 0; + return; } /*****************************************************************************/ GBytes * -nm_gbytes_get_empty (void) +nm_gbytes_get_empty(void) { - static GBytes *bytes = NULL; - GBytes *b; + static GBytes *bytes = NULL; + GBytes * b; again: - b = g_atomic_pointer_get (&bytes); - if (G_UNLIKELY (!b)) { - b = g_bytes_new_static ("", 0); - if (!g_atomic_pointer_compare_and_exchange (&bytes, NULL, b)) { - g_bytes_unref (b); - goto again; - } - } - return b; + b = g_atomic_pointer_get(&bytes); + if (G_UNLIKELY(!b)) { + b = g_bytes_new_static("", 0); + if (!g_atomic_pointer_compare_and_exchange(&bytes, NULL, b)) { + g_bytes_unref(b); + goto again; + } + } + return b; } /** @@ -435,38 +372,64 @@ again: * special case, a %NULL @bytes is treated like an empty array. */ gboolean -nm_utils_gbytes_equal_mem (GBytes *bytes, - gconstpointer mem_data, - gsize mem_len) +nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len) { - gconstpointer p; - gsize l; + gconstpointer p; + gsize l; - if (!bytes) { - /* as a special case, let %NULL GBytes compare idential - * to an empty array. */ - return (mem_len == 0); - } + if (!bytes) { + /* as a special case, let %NULL GBytes compare identical + * to an empty array. */ + return (mem_len == 0); + } - p = g_bytes_get_data (bytes, &l); - return l == mem_len - && ( mem_len == 0 /* allow @mem_data to be %NULL */ - || memcmp (p, mem_data, mem_len) == 0); + p = g_bytes_get_data(bytes, &l); + return l == mem_len + && (mem_len == 0 /* allow @mem_data to be %NULL */ + || memcmp(p, mem_data, mem_len) == 0); } GVariant * -nm_utils_gbytes_to_variant_ay (GBytes *bytes) +nm_utils_gbytes_to_variant_ay(GBytes *bytes) { - const guint8 *p; - gsize l; + const guint8 *p; + gsize l; + + if (!bytes) { + /* for convenience, accept NULL to return an empty variant */ + return g_variant_new_array(G_VARIANT_TYPE_BYTE, NULL, 0); + } - if (!bytes) { - /* for convenience, accept NULL to return an empty variant */ - return g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0); - } + p = g_bytes_get_data(bytes, &l); + return g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, p, l, 1); +} + +/*****************************************************************************/ - p = g_bytes_get_data (bytes, &l); - return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, p, l, 1); +#define _variant_singleton_get(create_variant) \ + ({ \ + static GVariant *_singleton = NULL; \ + GVariant * _v; \ + \ +again: \ + _v = g_atomic_pointer_get(&_singleton); \ + if (G_UNLIKELY(!_v)) { \ + _v = (create_variant); \ + nm_assert(_v); \ + nm_assert(g_variant_is_floating(_v)); \ + g_variant_ref_sink(_v); \ + if (!g_atomic_pointer_compare_and_exchange(&_singleton, NULL, _v)) { \ + g_variant_unref(_v); \ + goto again; \ + } \ + } \ + _v; \ + }) + +GVariant * +nm_g_variant_singleton_u_0(void) +{ + return _variant_singleton_get(g_variant_new_uint32(0)); } /*****************************************************************************/ @@ -476,53 +439,46 @@ nm_utils_gbytes_to_variant_ay (GBytes *bytes) * Returns a floating reference. */ GVariant * -nm_utils_strdict_to_variant_ass (GHashTable *strdict) -{ - GHashTableIter iter; - const char *key, *value; - 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; - - g_hash_table_iter_init (&iter, strdict); - if (!g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) - nm_assert_not_reached (); - - if (len == 1) - g_variant_builder_add (&builder, "{ss}", key, value); - else { - gs_free NMUtilsNamedValue *idx_free = NULL; - NMUtilsNamedValue *idx; - - 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); - - nm_utils_named_value_list_sort (idx, len, NULL, NULL); - - for (i = 0; i < len; i++) - g_variant_builder_add (&builder, "{ss}", idx[i].name, idx[i].value_str); - } +nm_utils_strdict_to_variant_ass(GHashTable *strdict) +{ + gs_free NMUtilsNamedValue *values_free = NULL; + NMUtilsNamedValue values_prepared[20]; + const NMUtilsNamedValue * values; + GVariantBuilder builder; + guint i; + guint n; -out: - return g_variant_builder_end (&builder); + values = nm_utils_named_values_from_strdict(strdict, &n, values_prepared, &values_free); + + 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); +} + +/*****************************************************************************/ + +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; + + values = nm_utils_named_values_from_strdict(strdict, &n, values_prepared, &values_free); + + 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)); + } + return g_variant_builder_end(&builder); } /*****************************************************************************/ @@ -548,54 +504,54 @@ out: * Returns: the input buffer with the quoted string. */ const char * -nm_strquote (char *buf, gsize buf_len, const char *str) -{ - const char *const buf0 = buf; - - if (!str) { - nm_utils_strbuf_append_str (&buf, &buf_len, "(null)"); - goto out; - } - - if (G_UNLIKELY (buf_len <= 2)) { - switch (buf_len) { - case 2: - *(buf++) = '^'; - /* fall-through */ - case 1: - *(buf++) = '\0'; - break; - } - goto out; - } - - *(buf++) = '"'; - buf_len--; - - nm_utils_strbuf_append_str (&buf, &buf_len, str); - - /* if the string was too long we indicate truncation with a - * '^' instead of a closing quote. */ - if (G_UNLIKELY (buf_len <= 1)) { - switch (buf_len) { - case 1: - buf[-1] = '^'; - break; - case 0: - buf[-2] = '^'; - break; - default: - nm_assert_not_reached (); - break; - } - } else { - nm_assert (buf_len >= 2); - *(buf++) = '"'; - *(buf++) = '\0'; - } +nm_strquote(char *buf, gsize buf_len, const char *str) +{ + const char *const buf0 = buf; + + if (!str) { + nm_utils_strbuf_append_str(&buf, &buf_len, "(null)"); + goto out; + } + + if (G_UNLIKELY(buf_len <= 2)) { + switch (buf_len) { + case 2: + *(buf++) = '^'; + /* fall-through */ + case 1: + *(buf++) = '\0'; + break; + } + goto out; + } + + *(buf++) = '"'; + buf_len--; + + nm_utils_strbuf_append_str(&buf, &buf_len, str); + + /* if the string was too long we indicate truncation with a + * '^' instead of a closing quote. */ + if (G_UNLIKELY(buf_len <= 1)) { + switch (buf_len) { + case 1: + buf[-1] = '^'; + break; + case 0: + buf[-2] = '^'; + break; + default: + nm_assert_not_reached(); + break; + } + } else { + nm_assert(buf_len >= 2); + *(buf++) = '"'; + *(buf++) = '\0'; + } out: - return buf0; + return buf0; } /*****************************************************************************/ @@ -603,82 +559,81 @@ out: char _nm_utils_to_string_buffer[]; void -nm_utils_to_string_buffer_init (char **buf, gsize *len) +nm_utils_to_string_buffer_init(char **buf, gsize *len) { - if (!*buf) { - *buf = _nm_utils_to_string_buffer; - *len = sizeof (_nm_utils_to_string_buffer); - } + if (!*buf) { + *buf = _nm_utils_to_string_buffer; + *len = sizeof(_nm_utils_to_string_buffer); + } } gboolean -nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len) +nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len) { - nm_utils_to_string_buffer_init (buf, len); - if (!obj) { - g_strlcpy (*buf, "(null)", *len); - return FALSE; - } - return TRUE; + nm_utils_to_string_buffer_init(buf, len); + if (!obj) { + g_strlcpy(*buf, "(null)", *len); + return FALSE; + } + return TRUE; } /*****************************************************************************/ const char * -nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, - gsize n_descs, - unsigned flags, - char *buf, - gsize len) +nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs, + gsize n_descs, + unsigned flags, + char * buf, + gsize len) { - gsize i; - char *p; + gsize i; + char *p; #if NM_MORE_ASSERTS > 10 - nm_assert (descs); - nm_assert (n_descs > 0); - for (i = 0; i < n_descs; i++) { - gsize j; - - nm_assert (descs[i].name && descs[i].name[0]); - for (j = 0; j < i; j++) - nm_assert (descs[j].flag != descs[i].flag); - } + nm_assert(descs); + nm_assert(n_descs > 0); + for (i = 0; i < n_descs; i++) { + gsize j; + + nm_assert(descs[i].name && descs[i].name[0]); + for (j = 0; j < i; j++) + nm_assert(descs[j].flag != descs[i].flag); + } #endif - nm_utils_to_string_buffer_init (&buf, &len); - - if (!len) - return buf; - - buf[0] = '\0'; - p = buf; - if (!flags) { - for (i = 0; i < n_descs; i++) { - if (!descs[i].flag) { - nm_utils_strbuf_append_str (&p, &len, descs[i].name); - break; - } - } - return buf; - } - - for (i = 0; flags && i < n_descs; i++) { - if ( descs[i].flag - && NM_FLAGS_ALL (flags, descs[i].flag)) { - flags &= ~descs[i].flag; - - if (buf[0] != '\0') - nm_utils_strbuf_append_c (&p, &len, ','); - nm_utils_strbuf_append_str (&p, &len, descs[i].name); - } - } - if (flags) { - if (buf[0] != '\0') - nm_utils_strbuf_append_c (&p, &len, ','); - nm_utils_strbuf_append (&p, &len, "0x%x", flags); - } - return buf; + nm_utils_to_string_buffer_init(&buf, &len); + + if (!len) + return buf; + + buf[0] = '\0'; + p = buf; + if (!flags) { + for (i = 0; i < n_descs; i++) { + if (!descs[i].flag) { + nm_utils_strbuf_append_str(&p, &len, descs[i].name); + break; + } + } + return buf; + } + + for (i = 0; flags && i < n_descs; i++) { + if (descs[i].flag && NM_FLAGS_ALL(flags, descs[i].flag)) { + flags &= ~descs[i].flag; + + if (buf[0] != '\0') + nm_utils_strbuf_append_c(&p, &len, ','); + nm_utils_strbuf_append_str(&p, &len, descs[i].name); + } + } + if (flags) { + if (buf[0] != '\0') + nm_utils_strbuf_append_c(&p, &len, ','); + nm_utils_strbuf_append(&p, &len, "0x%x", flags); + } + return buf; }; /*****************************************************************************/ @@ -690,34 +645,34 @@ nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, * Returns: the netmask represented by the prefix, in network byte order **/ guint32 -_nm_utils_ip4_prefix_to_netmask (guint32 prefix) +_nm_utils_ip4_prefix_to_netmask(guint32 prefix) { - return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF; + return prefix < 32 ? ~htonl(0xFFFFFFFFu >> prefix) : 0xFFFFFFFFu; } gconstpointer -nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen) +nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen) { - g_return_val_if_fail (dst, NULL); + g_return_val_if_fail(dst, NULL); - switch (family) { - case AF_INET: - g_return_val_if_fail (plen <= 32, NULL); + switch (family) { + case AF_INET: + g_return_val_if_fail(plen <= 32, NULL); - if (!src) { - /* allow "self-assignment", by specifying %NULL as source. */ - src = dst; - } + if (!src) { + /* allow "self-assignment", by specifying %NULL as source. */ + src = dst; + } - *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address (*((guint32 *) src), plen); - break; - case AF_INET6: - nm_utils_ip6_address_clear_host_address (dst, src, plen); - break; - default: - g_return_val_if_reached (NULL); - } - return dst; + *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address(*((guint32 *) src), plen); + break; + case AF_INET6: + nm_utils_ip6_address_clear_host_address(dst, src, plen); + break; + default: + g_return_val_if_reached(NULL); + } + return dst; } /* nm_utils_ip4_address_clear_host_address: @@ -727,9 +682,9 @@ nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer * returns: the input address, with the host address set to 0. */ in_addr_t -nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) +nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint8 plen) { - return addr & _nm_utils_ip4_prefix_to_netmask (plen); + return addr & _nm_utils_ip4_prefix_to_netmask(plen); } /* nm_utils_ip6_address_clear_host_address: @@ -741,54 +696,58 @@ nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) * @dst and @src to the same destination or set @src NULL. */ const struct in6_addr * -nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen) +nm_utils_ip6_address_clear_host_address(struct in6_addr * dst, + const struct in6_addr *src, + guint8 plen) { - g_return_val_if_fail (plen <= 128, NULL); - g_return_val_if_fail (dst, NULL); + g_return_val_if_fail(plen <= 128, NULL); + g_return_val_if_fail(dst, NULL); - if (!src) - src = dst; + if (!src) + src = dst; - if (plen < 128) { - guint nbytes = plen / 8; - guint nbits = plen % 8; + if (plen < 128) { + guint nbytes = plen / 8; + guint nbits = plen % 8; - if (nbytes && dst != src) - memcpy (dst, src, nbytes); - if (nbits) { - dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); - nbytes++; - } - if (nbytes <= 15) - memset (&dst->s6_addr[nbytes], 0, 16 - nbytes); - } else if (src != dst) - *dst = *src; + if (nbytes && dst != src) + memcpy(dst, src, nbytes); + if (nbits) { + dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits))); + nbytes++; + } + if (nbytes <= 15) + memset(&dst->s6_addr[nbytes], 0, 16 - nbytes); + } else if (src != dst) + *dst = *src; - return dst; + return dst; } int -nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen) -{ - int nbytes; - guint8 va, vb, m; - - if (plen >= 128) - NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, sizeof (struct in6_addr)); - else { - nbytes = plen / 8; - if (nbytes) - NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, nbytes); - - plen = plen % 8; - if (plen != 0) { - m = ~((1 << (8 - plen)) - 1); - va = ((((const guint8 *) addr_a))[nbytes]) & m; - vb = ((((const guint8 *) addr_b))[nbytes]) & m; - NM_CMP_DIRECT (va, vb); - } - } - return 0; +nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a, + const struct in6_addr *addr_b, + guint8 plen) +{ + int nbytes; + guint8 va, vb, m; + + if (plen >= 128) + NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, sizeof(struct in6_addr)); + else { + nbytes = plen / 8; + if (nbytes) + NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, nbytes); + + plen = plen % 8; + if (plen != 0) { + m = ~((1 << (8 - plen)) - 1); + va = ((((const guint8 *) addr_a))[nbytes]) & m; + vb = ((((const guint8 *) addr_b))[nbytes]) & m; + NM_CMP_DIRECT(va, vb); + } + } + return 0; } /** @@ -804,347 +763,349 @@ nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struc **/ /* The function is originally from ipcalc.c of Red Hat's initscripts. */ guint32 -_nm_utils_ip4_get_default_prefix (guint32 ip) +_nm_utils_ip4_get_default_prefix(guint32 ip) { - if (((ntohl (ip) & 0xFF000000) >> 24) <= 127) - return 8; /* Class A - 255.0.0.0 */ - else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191) - return 16; /* Class B - 255.255.0.0 */ + if (((ntohl(ip) & 0xFF000000) >> 24) <= 127) + return 8; /* Class A - 255.0.0.0 */ + else if (((ntohl(ip) & 0xFF000000) >> 24) <= 191) + return 16; /* Class B - 255.255.0.0 */ - return 24; /* Class C - 255.255.255.0 */ + return 24; /* Class C - 255.255.255.0 */ } gboolean -nm_utils_ip_is_site_local (int addr_family, - const void *address) -{ - in_addr_t addr4; - - switch (addr_family) { - case AF_INET: - /* RFC1918 private addresses - * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */ - addr4 = ntohl (*((const in_addr_t *) address)); - return (addr4 & 0xff000000) == 0x0a000000 - || (addr4 & 0xfff00000) == 0xac100000 - || (addr4 & 0xffff0000) == 0xc0a80000; - case AF_INET6: - return IN6_IS_ADDR_SITELOCAL (address); - default: - g_return_val_if_reached (FALSE); - } +nm_utils_ip_is_site_local(int addr_family, const void *address) +{ + in_addr_t addr4; + + switch (addr_family) { + case AF_INET: + /* RFC1918 private addresses + * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */ + addr4 = ntohl(*((const in_addr_t *) address)); + return (addr4 & 0xff000000) == 0x0a000000 || (addr4 & 0xfff00000) == 0xac100000 + || (addr4 & 0xffff0000) == 0xc0a80000; + case AF_INET6: + return IN6_IS_ADDR_SITELOCAL(address); + default: + g_return_val_if_reached(FALSE); + } } /*****************************************************************************/ static gboolean -_parse_legacy_addr4 (const char *text, in_addr_t *out_addr, GError **error) -{ - gs_free char *s_free = NULL; - struct in_addr a1; - guint8 bin[sizeof (a1)]; - char *s; - int i; - - if (inet_aton (text, &a1) != 1) { - g_set_error_literal (error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "address invalid according to inet_aton()"); - return FALSE; - } - - /* OK, inet_aton() accepted the format. That's good, because we want - * to accept IPv4 addresses in octal format, like 255.255.000.000. - * That's what "legacy" means here. inet_pton() doesn't accept those. - * - * But inet_aton() also ignores trailing garbage and formats with fewer than - * 4 digits. That is just too crazy and we don't do that. Perform additional checks - * and reject some forms that inet_aton() accepted. - * - * Note that we still should (of course) accept everything that inet_pton() - * accepts. However this code never gets called if inet_pton() succeeds - * (see below, aside the assertion code). */ - - if (NM_STRCHAR_ANY (text, ch, ( !(ch >= '0' && ch <= '9') - && !NM_IN_SET (ch, '.', 'x')))) { - /* We only accepts '.', digits, and 'x' for "0x". */ - g_set_error_literal (error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "contains an invalid character"); - return FALSE; - } - - s = nm_memdup_maybe_a (300, text, strlen (text) + 1, &s_free); - - for (i = 0; i < G_N_ELEMENTS (bin); i++) { - char *current_token = s; - gint32 v; - - s = strchr (s, '.'); - if (s) { - s[0] = '\0'; - s++; - } - - if ((i == G_N_ELEMENTS (bin) - 1) != (s == NULL)) { - /* Exactly for the last digit, we expect to have no more following token. - * But this isn't the case. Abort. */ - g_set_error (error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "wrong number of tokens (index %d, token '%s')", - i, s); - return FALSE; - } - - v = _nm_utils_ascii_str_to_int64 (current_token, 0, 0, 0xFF, -1); - if (v == -1) { - int errsv = errno; - - /* we do accept octal and hex (even with leading "0x"). But something - * about this token is wrong. */ - g_set_error (error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "invalid token '%s': %s (%d)", - current_token, - nm_strerror_native (errsv), - errsv); - return FALSE; - } - - bin[i] = v; - } - - if (memcmp (bin, &a1, sizeof (bin)) != 0) { - /* our parsing did not agree with what inet_aton() gave. Something - * is wrong. Abort. */ - g_set_error (error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_INVALID_ARGUMENT, - "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx", - a1.s_addr, - bin[0], bin[1], bin[2], bin[3]); - return FALSE; - } - - *out_addr = a1.s_addr; - return TRUE; +_parse_legacy_addr4(const char *text, in_addr_t *out_addr, GError **error) +{ + gs_free char * s_free = NULL; + struct in_addr a1; + guint8 bin[sizeof(a1)]; + char * s; + int i; + + if (inet_aton(text, &a1) != 1) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "address invalid according to inet_aton()"); + return FALSE; + } + + /* OK, inet_aton() accepted the format. That's good, because we want + * to accept IPv4 addresses in octal format, like 255.255.000.000. + * That's what "legacy" means here. inet_pton() doesn't accept those. + * + * But inet_aton() also ignores trailing garbage and formats with fewer than + * 4 digits. That is just too crazy and we don't do that. Perform additional checks + * and reject some forms that inet_aton() accepted. + * + * Note that we still should (of course) accept everything that inet_pton() + * accepts. However this code never gets called if inet_pton() succeeds + * (see below, aside the assertion code). */ + + if (NM_STRCHAR_ANY(text, ch, (!(ch >= '0' && ch <= '9') && !NM_IN_SET(ch, '.', 'x')))) { + /* We only accepts '.', digits, and 'x' for "0x". */ + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "contains an invalid character"); + return FALSE; + } + + s = nm_memdup_maybe_a(300, text, strlen(text) + 1, &s_free); + + for (i = 0; i < G_N_ELEMENTS(bin); i++) { + char * current_token = s; + gint32 v; + + s = strchr(s, '.'); + if (s) { + s[0] = '\0'; + s++; + } + + if ((i == G_N_ELEMENTS(bin) - 1) != (s == NULL)) { + /* Exactly for the last digit, we expect to have no more following token. + * But this isn't the case. Abort. */ + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "wrong number of tokens (index %d, token '%s')", + i, + s); + return FALSE; + } + + v = _nm_utils_ascii_str_to_int64(current_token, 0, 0, 0xFF, -1); + if (v == -1) { + int errsv = errno; + + /* we do accept octal and hex (even with leading "0x"). But something + * about this token is wrong. */ + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "invalid token '%s': %s (%d)", + current_token, + nm_strerror_native(errsv), + errsv); + return FALSE; + } + + bin[i] = v; + } + + if (memcmp(bin, &a1, sizeof(bin)) != 0) { + /* our parsing did not agree with what inet_aton() gave. Something + * is wrong. Abort. */ + g_set_error( + error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx", + a1.s_addr, + bin[0], + bin[1], + bin[2], + bin[3]); + return FALSE; + } + + *out_addr = a1.s_addr; + return TRUE; } gboolean -nm_utils_parse_inaddr_bin_full (int addr_family, - gboolean accept_legacy, - const char *text, - int *out_addr_family, - gpointer out_addr) -{ - NMIPAddr addrbin; - - g_return_val_if_fail (text, FALSE); - - if (addr_family == AF_UNSPEC) { - g_return_val_if_fail (!out_addr || out_addr_family, FALSE); - addr_family = strchr (text, ':') ? AF_INET6 : AF_INET; - } else - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); - - if (inet_pton (addr_family, text, &addrbin) != 1) { - if ( accept_legacy - && addr_family == AF_INET - && _parse_legacy_addr4 (text, &addrbin.addr4, NULL)) { - /* The address is in some legacy format which inet_aton() accepts, but not inet_pton(). - * Most likely octal digits (leading zeros). We accept the address. */ - } else - return FALSE; - } +nm_utils_parse_inaddr_bin_full(int addr_family, + gboolean accept_legacy, + const char *text, + int * out_addr_family, + gpointer out_addr) +{ + NMIPAddr addrbin; + + g_return_val_if_fail(text, FALSE); + + if (addr_family == AF_UNSPEC) { + g_return_val_if_fail(!out_addr || out_addr_family, FALSE); + addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; + } else + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); + + if (inet_pton(addr_family, text, &addrbin) != 1) { + if (accept_legacy && addr_family == AF_INET + && _parse_legacy_addr4(text, &addrbin.addr4, NULL)) { + /* The address is in some legacy format which inet_aton() accepts, but not inet_pton(). + * Most likely octal digits (leading zeros). We accept the address. */ + } else + return FALSE; + } #if NM_MORE_ASSERTS > 10 - if (addr_family == AF_INET) { - gs_free_error GError *error = NULL; - in_addr_t a; - - /* The legacy parser should accept everything that inet_pton() accepts too. Meaning, - * it should strictly parse *more* formats. And of course, parse it the same way. */ - if (!_parse_legacy_addr4 (text, &a, &error)) { - char buf[INET_ADDRSTRLEN]; - - g_error ("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by legacy parser: %s", - text, _nm_utils_inet4_ntop (addrbin.addr4, buf), error->message); - } - nm_assert (addrbin.addr4 == a); - } + if (addr_family == AF_INET) { + gs_free_error GError *error = NULL; + in_addr_t a; + + /* The legacy parser should accept everything that inet_pton() accepts too. Meaning, + * it should strictly parse *more* formats. And of course, parse it the same way. */ + if (!_parse_legacy_addr4(text, &a, &error)) { + char buf[INET_ADDRSTRLEN]; + + g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by " + "legacy parser: %s", + text, + _nm_utils_inet4_ntop(addrbin.addr4, buf), + error->message); + } + nm_assert(addrbin.addr4 == a); + } #endif - NM_SET_OUT (out_addr_family, addr_family); - if (out_addr) - nm_ip_addr_set (addr_family, out_addr, &addrbin); - return TRUE; + NM_SET_OUT(out_addr_family, addr_family); + if (out_addr) + nm_ip_addr_set(addr_family, out_addr, &addrbin); + return TRUE; } gboolean -nm_utils_parse_inaddr (int addr_family, - const char *text, - char **out_addr) +nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr) { - NMIPAddr addrbin; - char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + NMIPAddr addrbin; + char addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; - g_return_val_if_fail (text, FALSE); + g_return_val_if_fail(text, FALSE); - if (addr_family == AF_UNSPEC) - addr_family = strchr (text, ':') ? AF_INET6 : AF_INET; - else - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); + if (addr_family == AF_UNSPEC) + addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; + else + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); - if (inet_pton (addr_family, text, &addrbin) != 1) - return FALSE; + if (inet_pton(addr_family, text, &addrbin) != 1) + return FALSE; - NM_SET_OUT (out_addr, g_strdup (inet_ntop (addr_family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); - return TRUE; + NM_SET_OUT(out_addr, + g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf)))); + return TRUE; } gboolean -nm_utils_parse_inaddr_prefix_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr, - int *out_prefix) -{ - gs_free char *addrstr_free = NULL; - int prefix = -1; - const char *slash; - const char *addrstr; - NMIPAddr addrbin; - - g_return_val_if_fail (text, FALSE); - - if (addr_family == AF_UNSPEC) { - g_return_val_if_fail (!out_addr || out_addr_family, FALSE); - addr_family = strchr (text, ':') ? AF_INET6 : AF_INET; - } else - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); - - slash = strchr (text, '/'); - if (slash) - addrstr = addrstr_free = g_strndup (text, slash - text); - else - addrstr = text; - - if (inet_pton (addr_family, addrstr, &addrbin) != 1) - return FALSE; - - if (slash) { - /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't - * do that. */ - prefix = _nm_utils_ascii_str_to_int64 (slash + 1, 10, - 0, - addr_family == AF_INET ? 32 : 128, - -1); - if (prefix == -1) - return FALSE; - } - - NM_SET_OUT (out_addr_family, addr_family); - if (out_addr) - nm_ip_addr_set (addr_family, out_addr, &addrbin); - NM_SET_OUT (out_prefix, prefix); - return TRUE; +nm_utils_parse_inaddr_prefix_bin(int addr_family, + const char *text, + int * out_addr_family, + gpointer out_addr, + int * out_prefix) +{ + gs_free char *addrstr_free = NULL; + int prefix = -1; + const char * slash; + const char * addrstr; + NMIPAddr addrbin; + + g_return_val_if_fail(text, FALSE); + + if (addr_family == AF_UNSPEC) { + g_return_val_if_fail(!out_addr || out_addr_family, FALSE); + addr_family = strchr(text, ':') ? AF_INET6 : AF_INET; + } else + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); + + slash = strchr(text, '/'); + if (slash) + addrstr = nm_strndup_a(300, text, slash - text, &addrstr_free); + else + addrstr = text; + + if (inet_pton(addr_family, addrstr, &addrbin) != 1) + return FALSE; + + if (slash) { + /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't + * do that. */ + prefix = + _nm_utils_ascii_str_to_int64(&slash[1], 10, 0, addr_family == AF_INET ? 32 : 128, -1); + if (prefix == -1) + return FALSE; + } + + NM_SET_OUT(out_addr_family, addr_family); + if (out_addr) + nm_ip_addr_set(addr_family, out_addr, &addrbin); + NM_SET_OUT(out_prefix, prefix); + return TRUE; } gboolean -nm_utils_parse_inaddr_prefix (int addr_family, - const char *text, - char **out_addr, - int *out_prefix) +nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix) { - NMIPAddr addrbin; - char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + NMIPAddr addrbin; + char addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; - if (!nm_utils_parse_inaddr_prefix_bin (addr_family, text, &addr_family, &addrbin, out_prefix)) - return FALSE; - NM_SET_OUT (out_addr, g_strdup (inet_ntop (addr_family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); - return TRUE; + if (!nm_utils_parse_inaddr_prefix_bin(addr_family, text, &addr_family, &addrbin, out_prefix)) + return FALSE; + NM_SET_OUT(out_addr, + g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf)))); + return TRUE; } gboolean -nm_utils_parse_next_line (const char **inout_ptr, - gsize *inout_len, - const char **out_line, - gsize *out_line_len) -{ - const char *line_start; - const char *line_end; - - g_return_val_if_fail (inout_ptr, FALSE); - g_return_val_if_fail (inout_len, FALSE); - g_return_val_if_fail (out_line, FALSE); - - if (*inout_len <= 0) - goto error; - - 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)); - - if (*inout_len > 0) - NM_SET_OUT (inout_ptr, line_end + 1); - else - NM_SET_OUT (inout_ptr, NULL); - return TRUE; - -error: - NM_SET_OUT (out_line, NULL); - NM_SET_OUT (out_line_len, 0); - return FALSE; +nm_utils_parse_next_line(const char **inout_ptr, + gsize * inout_len, + const char **out_line, + gsize * out_line_len) +{ + gboolean eol_is_carriage_return; + const char *line_start; + gsize line_len; + + 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 (G_UNLIKELY(*inout_len == 0)) + return FALSE; + + line_start = *inout_ptr; + + 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; + } + } + +done: + *out_line = line_start; + *out_line_len = line_len; + return TRUE; } /*****************************************************************************/ gboolean -nm_utils_ipaddr_is_valid (int addr_family, - const char *str_addr) +nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr) { - nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6)); + nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - return str_addr - && nm_utils_parse_inaddr_bin (addr_family, - str_addr, - NULL, - NULL); + return str_addr && nm_utils_parse_inaddr_bin(addr_family, str_addr, NULL, NULL); } gboolean -nm_utils_ipaddr_is_normalized (int addr_family, - const char *str_addr) +nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr) { - NMIPAddr addr; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + NMIPAddr addr; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6)); + nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - if (!str_addr) - return FALSE; + if (!str_addr) + return FALSE; - if (!nm_utils_parse_inaddr_bin (addr_family, - str_addr, - &addr_family, - &addr)) - return FALSE; + if (!nm_utils_parse_inaddr_bin(addr_family, str_addr, &addr_family, &addr)) + return FALSE; - nm_utils_inet_ntop (addr_family, &addr, sbuf); - return nm_streq (sbuf, str_addr); + nm_utils_inet_ntop(addr_family, &addr, sbuf); + return nm_streq(sbuf, str_addr); } /*****************************************************************************/ @@ -1168,137 +1129,124 @@ nm_utils_ipaddr_is_normalized (int addr_family, * This wrapper tries to workaround that condition. */ gint64 -nm_g_ascii_strtoll (const char *nptr, - char **endptr, - guint base) +nm_g_ascii_strtoll(const char *nptr, char **endptr, guint base) { - int try_count = 2; - gint64 v; - const int errsv_orig = errno; - int errsv; + int try_count = 2; + gint64 v; + const int errsv_orig = errno; + int errsv; - nm_assert (nptr); - nm_assert (base == 0u || (base >= 2u && base <= 36u)); + nm_assert(nptr); + nm_assert(base == 0u || (base >= 2u && base <= 36u)); again: - errno = 0; - v = g_ascii_strtoll (nptr, endptr, base); - errsv = errno; + errno = 0; + v = g_ascii_strtoll(nptr, endptr, base); + errsv = errno; - if (errsv == 0) { - if (errsv_orig != 0) - errno = errsv_orig; - return v; - } + if (errsv == 0) { + if (errsv_orig != 0) + errno = errsv_orig; + return v; + } - if ( errsv == ERANGE - && NM_IN_SET (v, G_MININT64, G_MAXINT64)) - return v; + if (errsv == ERANGE && NM_IN_SET(v, G_MININT64, G_MAXINT64)) + return v; - if ( errsv == EINVAL - && v == 0 - && nptr - && nptr[0] == '\0') - return v; + if (errsv == EINVAL && v == 0 && nptr && nptr[0] == '\0') + return v; - if (try_count-- > 0) - goto again; + if (try_count-- > 0) + goto again; #if NM_MORE_ASSERTS - g_critical ("g_ascii_strtoll() for \"%s\" failed with errno=%d (%s) and v=%"G_GINT64_FORMAT, - nptr, - errsv, - nm_strerror_native (errsv), - v); + g_critical("g_ascii_strtoll() for \"%s\" failed with errno=%d (%s) and v=%" G_GINT64_FORMAT, + nptr, + errsv, + nm_strerror_native(errsv), + v); #endif - return v; + return v; } /* See nm_g_ascii_strtoll() */ guint64 -nm_g_ascii_strtoull (const char *nptr, - char **endptr, - guint base) +nm_g_ascii_strtoull(const char *nptr, char **endptr, guint base) { - int try_count = 2; - guint64 v; - const int errsv_orig = errno; - int errsv; + int try_count = 2; + guint64 v; + const int errsv_orig = errno; + int errsv; - nm_assert (nptr); - nm_assert (base == 0u || (base >= 2u && base <= 36u)); + nm_assert(nptr); + nm_assert(base == 0u || (base >= 2u && base <= 36u)); again: - errno = 0; - v = g_ascii_strtoull (nptr, endptr, base); - errsv = errno; + errno = 0; + v = g_ascii_strtoull(nptr, endptr, base); + errsv = errno; - if (errsv == 0) { - if (errsv_orig != 0) - errno = errsv_orig; - return v; - } + if (errsv == 0) { + if (errsv_orig != 0) + errno = errsv_orig; + return v; + } - if ( errsv == ERANGE - && NM_IN_SET (v, G_MAXUINT64)) - return v; + if (errsv == ERANGE && NM_IN_SET(v, G_MAXUINT64)) + return v; - if ( errsv == EINVAL - && v == 0 - && nptr - && nptr[0] == '\0') - return v; + if (errsv == EINVAL && v == 0 && nptr && nptr[0] == '\0') + return v; - if (try_count-- > 0) - goto again; + if (try_count-- > 0) + goto again; #if NM_MORE_ASSERTS - g_critical ("g_ascii_strtoull() for \"%s\" failed with errno=%d (%s) and v=%"G_GUINT64_FORMAT, - nptr, - errsv, - nm_strerror_native (errsv), - v); + g_critical("g_ascii_strtoull() for \"%s\" failed with errno=%d (%s) and v=%" G_GUINT64_FORMAT, + nptr, + errsv, + nm_strerror_native(errsv), + v); #endif - return v; + return v; } /* see nm_g_ascii_strtoll(). */ double -nm_g_ascii_strtod (const char *nptr, - char **endptr) +nm_g_ascii_strtod(const char *nptr, char **endptr) { - int try_count = 2; - double v; - int errsv; + int try_count = 2; + double v; + int errsv; - nm_assert (nptr); + nm_assert(nptr); again: - v = g_ascii_strtod (nptr, endptr); - errsv = errno; + v = g_ascii_strtod(nptr, endptr); + errsv = errno; - if (errsv == 0) - return v; + if (errsv == 0) + return v; - if (errsv == ERANGE) - return v; + if (errsv == ERANGE) + return v; - if (try_count-- > 0) - goto again; + if (try_count-- > 0) + goto again; #if NM_MORE_ASSERTS - g_critical ("g_ascii_strtod() for \"%s\" failed with errno=%d (%s) and v=%f", - nptr, - errsv, - nm_strerror_native (errsv), - v); + g_critical("g_ascii_strtod() for \"%s\" failed with errno=%d (%s) and v=%f", + nptr, + errsv, + nm_strerror_native(errsv), + v); #endif - /* Not really much else to do. Return the parsed value and leave errno set - * to the unexpected value. */ - return v; + /* Not really much else to do. Return the parsed value and leave errno set + * to the unexpected value. */ + return v; } /* _nm_utils_ascii_str_to_int64: @@ -1316,91 +1264,94 @@ again: * white space. **/ gint64 -_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) +_nm_utils_ascii_str_to_int64(const char *str, guint base, gint64 min, gint64 max, gint64 fallback) { - gint64 v; - const char *s = NULL; + gint64 v; + const char *s = NULL; - str = nm_str_skip_leading_spaces (str); - if (!str || !str[0]) { - errno = EINVAL; - return fallback; - } + str = nm_str_skip_leading_spaces(str); + if (!str || !str[0]) { + errno = EINVAL; + return fallback; + } - errno = 0; - v = nm_g_ascii_strtoll (str, (char **) &s, base); + errno = 0; + v = nm_g_ascii_strtoll(str, (char **) &s, base); - if (errno != 0) - return fallback; + if (errno != 0) + return fallback; - if (s[0] != '\0') { - s = nm_str_skip_leading_spaces (s); - if (s[0] != '\0') { - errno = EINVAL; - return fallback; - } - } - if (v > max || v < min) { - errno = ERANGE; - return fallback; - } + if (s[0] != '\0') { + s = nm_str_skip_leading_spaces(s); + if (s[0] != '\0') { + errno = EINVAL; + return fallback; + } + } + if (v > max || v < min) { + errno = ERANGE; + return fallback; + } - return v; + return v; } guint64 -_nm_utils_ascii_str_to_uint64 (const char *str, guint base, guint64 min, guint64 max, guint64 fallback) -{ - guint64 v; - const char *s = NULL; - - if (str) { - while (g_ascii_isspace (str[0])) - str++; - } - if (!str || !str[0]) { - errno = EINVAL; - return fallback; - } - - errno = 0; - v = nm_g_ascii_strtoull (str, (char **) &s, base); - - if (errno != 0) - return fallback; - if (s[0] != '\0') { - while (g_ascii_isspace (s[0])) - s++; - if (s[0] != '\0') { - errno = EINVAL; - return fallback; - } - } - if (v > max || v < min) { - errno = ERANGE; - return fallback; - } - - if ( v != 0 - && str[0] == '-') { - /* As documented, g_ascii_strtoull() accepts negative values, and returns their - * absolute value. We don't. */ - errno = ERANGE; - return fallback; - } - - return v; +_nm_utils_ascii_str_to_uint64(const char *str, + guint base, + guint64 min, + guint64 max, + guint64 fallback) +{ + guint64 v; + const char *s = NULL; + + if (str) { + while (g_ascii_isspace(str[0])) + str++; + } + if (!str || !str[0]) { + errno = EINVAL; + return fallback; + } + + errno = 0; + v = nm_g_ascii_strtoull(str, (char **) &s, base); + + if (errno != 0) + return fallback; + if (s[0] != '\0') { + while (g_ascii_isspace(s[0])) + s++; + if (s[0] != '\0') { + errno = EINVAL; + return fallback; + } + } + if (v > max || v < min) { + errno = ERANGE; + return fallback; + } + + if (v != 0 && str[0] == '-') { + /* As documented, g_ascii_strtoull() accepts negative values, and returns their + * absolute value. We don't. */ + errno = ERANGE; + return fallback; + } + + return v; } /*****************************************************************************/ int -nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data) +nm_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data) { - const char *s1 = a; - const char *s2 = b; + const char *s1 = a; + const char *s2 = b; - return strcmp (s1, s2); + return strcmp(s1, s2); } /* like nm_strcmp_p(), suitable for g_ptr_array_sort_with_data(). @@ -1411,202 +1362,220 @@ nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data) * For NetworkManager, we'd rather avoid such stunts. **/ int -nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data) +nm_strcmp_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); + + return strcmp(s1, s2); +} + +int +nm_strcmp0_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data) { - const char *s1 = *((const char **) a); - const char *s2 = *((const char **) b); + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); - return strcmp (s1, s2); + return nm_strcmp0(s1, s2); } int -nm_strcmp0_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data) +nm_strcmp_ascii_case_with_data(gconstpointer a, gconstpointer b, gpointer user_data) { - const char *s1 = *((const char **) a); - const char *s2 = *((const char **) b); + const char *s1 = a; + const char *s2 = b; - return nm_strcmp0 (s1, s2); + return g_ascii_strcasecmp(s1, s2); } int -nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +nm_cmp_uint32_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data) { - const guint32 a = *((const guint32 *) p_a); - const guint32 b = *((const guint32 *) p_b); + const guint32 a = *((const guint32 *) p_a); + const guint32 b = *((const guint32 *) p_b); - if (a < b) - return -1; - if (a > b) - return 1; - return 0; + if (a < b) + return -1; + if (a > b) + return 1; + return 0; } int -nm_cmp_int2ptr_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +nm_cmp_int2ptr_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data) { - /* p_a and p_b are two pointers to a pointer, where the pointer is - * interpreted as a integer using GPOINTER_TO_INT(). - * - * That is the case of a hash-table that uses GINT_TO_POINTER() to - * convert integers as pointers, and the resulting keys-as-array - * array. */ - const int a = GPOINTER_TO_INT (*((gconstpointer *) p_a)); - const int b = GPOINTER_TO_INT (*((gconstpointer *) p_b)); + /* p_a and p_b are two pointers to a pointer, where the pointer is + * interpreted as a integer using GPOINTER_TO_INT(). + * + * That is the case of a hash-table that uses GINT_TO_POINTER() to + * convert integers as pointers, and the resulting keys-as-array + * array. */ + const int a = GPOINTER_TO_INT(*((gconstpointer *) p_a)); + const int b = GPOINTER_TO_INT(*((gconstpointer *) p_b)); - if (a < b) - return -1; - if (a > b) - return 1; - return 0; + if (a < b) + return -1; + if (a > b) + return 1; + return 0; } /*****************************************************************************/ const char * -nm_utils_dbus_path_get_last_component (const char *dbus_path) +nm_utils_dbus_path_get_last_component(const char *dbus_path) { - if (dbus_path) { - dbus_path = strrchr (dbus_path, '/'); - if (dbus_path) - return dbus_path + 1; - } - return NULL; + if (dbus_path) { + dbus_path = strrchr(dbus_path, '/'); + if (dbus_path) + return dbus_path + 1; + } + return NULL; } static gint64 -_dbus_path_component_as_num (const char *p) -{ - gint64 n; - - /* no odd stuff. No leading zeros, only a non-negative, decimal integer. - * - * Otherwise, there would be multiple ways to encode the same number "10" - * and "010". That is just confusing. A number has no leading zeros, - * if it has, it's not a number (as far as we are concerned here). */ - if (p[0] == '0') { - if (p[1] != '\0') - return -1; - else - return 0; - } - if (!(p[0] >= '1' && p[0] <= '9')) - return -1; - if (!NM_STRCHAR_ALL (&p[1], ch, (ch >= '0' && ch <= '9'))) - return -1; - n = _nm_utils_ascii_str_to_int64 (p, 10, 0, G_MAXINT64, -1); - nm_assert (n == -1 || nm_streq0 (p, nm_sprintf_bufa (100, "%"G_GINT64_FORMAT, n))); - return n; +_dbus_path_component_as_num(const char *p) +{ + gint64 n; + + /* no odd stuff. No leading zeros, only a non-negative, decimal integer. + * + * Otherwise, there would be multiple ways to encode the same number "10" + * and "010". That is just confusing. A number has no leading zeros, + * if it has, it's not a number (as far as we are concerned here). */ + if (p[0] == '0') { + if (p[1] != '\0') + return -1; + else + return 0; + } + if (!(p[0] >= '1' && p[0] <= '9')) + return -1; + if (!NM_STRCHAR_ALL(&p[1], ch, (ch >= '0' && ch <= '9'))) + return -1; + n = _nm_utils_ascii_str_to_int64(p, 10, 0, G_MAXINT64, -1); + nm_assert(n == -1 || nm_streq0(p, nm_sprintf_bufa(100, "%" G_GINT64_FORMAT, n))); + return n; } int -nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b) -{ - const char *l_a, *l_b; - gsize plen; - gint64 n_a, n_b; - - /* compare function for two D-Bus paths. It behaves like - * strcmp(), except, if both paths have the same prefix, - * and both end in a (positive) number, then the paths - * will be sorted by number. */ - - NM_CMP_SELF (dbus_path_a, dbus_path_b); - - /* if one or both paths have no slash (and no last component) - * compare the full paths directly. */ - if ( !(l_a = nm_utils_dbus_path_get_last_component (dbus_path_a)) - || !(l_b = nm_utils_dbus_path_get_last_component (dbus_path_b))) - goto comp_full; - - /* check if both paths have the same prefix (up to the last-component). */ - plen = l_a - dbus_path_a; - if (plen != (l_b - dbus_path_b)) - goto comp_full; - NM_CMP_RETURN (strncmp (dbus_path_a, dbus_path_b, plen)); - - n_a = _dbus_path_component_as_num (l_a); - n_b = _dbus_path_component_as_num (l_b); - if (n_a == -1 && n_b == -1) - goto comp_l; - - /* both components must be convertiable 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. - * - * An example of a not total ordering would be: - * "8" < "010" (numeric) - * "0x" < "8" (lexical) - * "0x" > "010" (lexical) - * We avoid this, by forcing that a non-numeric entry "0x" always sorts - * before numeric entries. - * - * Additionally, _dbus_path_component_as_num() would also reject "010" as - * not a valid number. - */ - if (n_a == -1) - return -1; - if (n_b == -1) - return 1; - - NM_CMP_DIRECT (n_a, n_b); - nm_assert (nm_streq (dbus_path_a, dbus_path_b)); - return 0; +nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b) +{ + const char *l_a, *l_b; + gsize plen; + gint64 n_a, n_b; + + /* compare function for two D-Bus paths. It behaves like + * strcmp(), except, if both paths have the same prefix, + * and both end in a (positive) number, then the paths + * will be sorted by number. */ + + NM_CMP_SELF(dbus_path_a, dbus_path_b); + + /* if one or both paths have no slash (and no last component) + * compare the full paths directly. */ + if (!(l_a = nm_utils_dbus_path_get_last_component(dbus_path_a)) + || !(l_b = nm_utils_dbus_path_get_last_component(dbus_path_b))) + goto comp_full; + + /* check if both paths have the same prefix (up to the last-component). */ + plen = l_a - dbus_path_a; + if (plen != (l_b - dbus_path_b)) + goto comp_full; + NM_CMP_RETURN(strncmp(dbus_path_a, dbus_path_b, plen)); + + n_a = _dbus_path_component_as_num(l_a); + n_b = _dbus_path_component_as_num(l_b); + if (n_a == -1 && n_b == -1) + goto comp_l; + + /* 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. + * + * An example of a not total ordering would be: + * "8" < "010" (numeric) + * "0x" < "8" (lexical) + * "0x" > "010" (lexical) + * We avoid this, by forcing that a non-numeric entry "0x" always sorts + * before numeric entries. + * + * Additionally, _dbus_path_component_as_num() would also reject "010" as + * not a valid number. + */ + if (n_a == -1) + return -1; + if (n_b == -1) + return 1; + + NM_CMP_DIRECT(n_a, n_b); + nm_assert(nm_streq(dbus_path_a, dbus_path_b)); + return 0; comp_full: - NM_CMP_DIRECT_STRCMP0 (dbus_path_a, dbus_path_b); - return 0; + NM_CMP_DIRECT_STRCMP0(dbus_path_a, dbus_path_b); + return 0; comp_l: - NM_CMP_DIRECT_STRCMP0 (l_a, l_b); - nm_assert (nm_streq (dbus_path_a, dbus_path_b)); - return 0; + NM_CMP_DIRECT_STRCMP0(l_a, l_b); + nm_assert(nm_streq(dbus_path_a, dbus_path_b)); + return 0; } /*****************************************************************************/ +typedef struct { + union { + guint8 table[256]; + guint64 _dummy_for_alignment; + }; +} CharLookupTable; + static void -_char_lookup_table_set_one (guint8 lookup[static 256], - char ch) +_char_lookup_table_set_one(CharLookupTable *lookup, char ch) { - lookup[(guint8) ch] = 1; + lookup->table[(guint8) ch] = 1; } static void -_char_lookup_table_set_all (guint8 lookup[static 256], - const char *candidates) +_char_lookup_table_set_all(CharLookupTable *lookup, const char *candidates) { - while (candidates[0] != '\0') - _char_lookup_table_set_one (lookup, (candidates++)[0]); + while (candidates[0] != '\0') + _char_lookup_table_set_one(lookup, (candidates++)[0]); } static void -_char_lookup_table_init (guint8 lookup[static 256], - const char *candidates) +_char_lookup_table_init(CharLookupTable *lookup, const char *candidates) { - memset (lookup, 0, 256); - if (candidates) - _char_lookup_table_set_all (lookup, candidates); + *lookup = (CharLookupTable){ + .table = {0}, + }; + if (candidates) + _char_lookup_table_set_all(lookup, candidates); } static gboolean -_char_lookup_has (const guint8 lookup[static 256], - char ch) +_char_lookup_has(const CharLookupTable *lookup, char ch) { - nm_assert (lookup[(guint8) '\0'] == 0); - return lookup[(guint8) ch] != 0; + /* with some optimization levels, the compiler thinks this code + * might access uninitialized @lookup. It is not -- when you look at the + * callers of this function. */ + NM_PRAGMA_WARNING_DISABLE("-Wmaybe-uninitialized") + nm_assert(lookup->table[(guint8) '\0'] == 0); + return lookup->table[(guint8) ch] != 0; + NM_PRAGMA_WARNING_REENABLE } static gboolean -_char_lookup_has_all (const guint8 lookup[static 256], - const char *candidates) +_char_lookup_has_all(const CharLookupTable *lookup, const char *candidates) { - if (candidates) { - while (candidates[0] != '\0') { - if (!_char_lookup_has (lookup, (candidates++)[0])) - return FALSE; - } - } - return TRUE; + if (candidates) { + while (candidates[0] != '\0') { + if (!_char_lookup_has(lookup, (candidates++)[0])) + return FALSE; + } + } + return TRUE; } /** @@ -1635,344 +1604,329 @@ _char_lookup_has_all (const guint8 lookup[static 256], * like "g_strstrip((char *) iter[0])". */ const char ** -nm_utils_strsplit_set_full (const char *str, - const char *delimiters, - NMUtilsStrsplitSetFlags flags) -{ - const char **ptr; - gsize num_tokens; - gsize i_token; - gsize str_len_p1; - const char *c_str; - char *s; - guint8 ch_lookup[256]; - const gboolean f_escaped = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED); - const gboolean f_allow_escaping = f_escaped || NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); - const gboolean f_preserve_empty = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); - const gboolean f_strstrip = NM_FLAGS_HAS (flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); - - if (!str) - return NULL; - - if (!delimiters) { - nm_assert_not_reached (); - delimiters = " \t\n"; - } - _char_lookup_table_init (ch_lookup, delimiters); - - nm_assert ( !f_allow_escaping - || !_char_lookup_has (ch_lookup, '\\')); - - if (!f_preserve_empty) { - while (_char_lookup_has (ch_lookup, str[0])) - str++; - } - - if (!str[0]) { - /* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY. - * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY - * different from g_strsplit_set(), which would in this case return an empty array. - * If you need to handle %NULL, and "" specially, then check the input string first. */ - return NULL; - } - -#define _char_is_escaped(str_start, str_cur) \ - ({ \ - const char *const _str_start = (str_start); \ - const char *const _str_cur = (str_cur); \ - const char *_str_i = (_str_cur); \ - \ - while ( _str_i > _str_start \ - && _str_i[-1] == '\\') \ - _str_i--; \ - (((_str_cur - _str_i) % 2) != 0); \ - }) - - num_tokens = 1; - c_str = str; - while (TRUE) { - - while (G_LIKELY (!_char_lookup_has (ch_lookup, c_str[0]))) { - if (c_str[0] == '\0') - goto done1; - c_str++; - } - - /* we assume escapings are not frequent. After we found - * this delimiter, check whether it was escaped by counting - * the backslashed before. */ - if ( f_allow_escaping - && _char_is_escaped (str, c_str)) { - /* the delimiter is escaped. This was not an accepted delimiter. */ - c_str++; - continue; - } - - c_str++; - - /* if we drop empty tokens, then we now skip over all consecutive delimiters. */ - if (!f_preserve_empty) { - while (_char_lookup_has (ch_lookup, c_str[0])) - c_str++; - if (c_str[0] == '\0') - break; - } - - num_tokens++; - } +nm_utils_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsplitSetFlags flags) +{ + const char ** ptr; + gsize num_tokens; + gsize i_token; + gsize str_len_p1; + const char * c_str; + char * s; + CharLookupTable ch_lookup; + const gboolean f_escaped = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED); + const gboolean f_allow_escaping = + f_escaped || NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); + const gboolean f_preserve_empty = + NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); + const gboolean f_strstrip = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); + + if (!str) + return NULL; + + if (!delimiters) { + nm_assert_not_reached(); + delimiters = " \t\n"; + } + _char_lookup_table_init(&ch_lookup, delimiters); + + nm_assert(!f_allow_escaping || !_char_lookup_has(&ch_lookup, '\\')); + + if (!f_preserve_empty) { + while (_char_lookup_has(&ch_lookup, str[0])) + str++; + } + + if (!str[0]) { + /* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY. + * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY + * different from g_strsplit_set(), which would in this case return an empty array. + * If you need to handle %NULL, and "" specially, then check the input string first. */ + return NULL; + } + +#define _char_is_escaped(str_start, str_cur) \ + ({ \ + const char *const _str_start = (str_start); \ + const char *const _str_cur = (str_cur); \ + const char * _str_i = (_str_cur); \ + \ + while (_str_i > _str_start && _str_i[-1] == '\\') \ + _str_i--; \ + (((_str_cur - _str_i) % 2) != 0); \ + }) + + num_tokens = 1; + c_str = str; + while (TRUE) { + while (G_LIKELY(!_char_lookup_has(&ch_lookup, c_str[0]))) { + if (c_str[0] == '\0') + goto done1; + c_str++; + } + + /* we assume escapings are not frequent. After we found + * this delimiter, check whether it was escaped by counting + * the backslashed before. */ + if (f_allow_escaping && _char_is_escaped(str, c_str)) { + /* the delimiter is escaped. This was not an accepted delimiter. */ + c_str++; + continue; + } + + c_str++; + + /* if we drop empty tokens, then we now skip over all consecutive delimiters. */ + if (!f_preserve_empty) { + while (_char_lookup_has(&ch_lookup, c_str[0])) + c_str++; + if (c_str[0] == '\0') + break; + } + + num_tokens++; + } done1: - nm_assert (c_str[0] == '\0'); + nm_assert(c_str[0] == '\0'); - str_len_p1 = (c_str - str) + 1; + str_len_p1 = (c_str - str) + 1; - nm_assert (str[str_len_p1 - 1] == '\0'); + nm_assert(str[str_len_p1 - 1] == '\0'); - ptr = g_malloc ((sizeof (const char *) * (num_tokens + 1)) + str_len_p1); - s = (char *) &ptr[num_tokens + 1]; - memcpy (s, str, str_len_p1); + ptr = g_malloc((sizeof(const char *) * (num_tokens + 1)) + str_len_p1); + s = (char *) &ptr[num_tokens + 1]; + memcpy(s, str, str_len_p1); - i_token = 0; + i_token = 0; - while (TRUE) { + while (TRUE) { + nm_assert(i_token < num_tokens); + ptr[i_token++] = s; - nm_assert (i_token < num_tokens); - ptr[i_token++] = s; + if (s[0] == '\0') { + nm_assert(f_preserve_empty); + goto done2; + } + nm_assert(f_preserve_empty || !_char_lookup_has(&ch_lookup, s[0])); - if (s[0] == '\0') { - nm_assert (f_preserve_empty); - goto done2; - } - nm_assert ( f_preserve_empty - || !_char_lookup_has (ch_lookup, s[0])); + while (!_char_lookup_has(&ch_lookup, s[0])) { + if (G_UNLIKELY(s[0] == '\\' && f_allow_escaping)) { + s++; + if (s[0] == '\0') + goto done2; + s++; + } else if (s[0] == '\0') + goto done2; + else + s++; + } - while (!_char_lookup_has (ch_lookup, s[0])) { - if (G_UNLIKELY ( s[0] == '\\' - && f_allow_escaping)) { - s++; - if (s[0] == '\0') - goto done2; - s++; - } else if (s[0] == '\0') - goto done2; - else - s++; - } + nm_assert(_char_lookup_has(&ch_lookup, s[0])); + s[0] = '\0'; + s++; - nm_assert (_char_lookup_has (ch_lookup, s[0])); - s[0] = '\0'; - s++; - - if (!f_preserve_empty) { - while (_char_lookup_has (ch_lookup, s[0])) - s++; - if (s[0] == '\0') - goto done2; - } - } + if (!f_preserve_empty) { + while (_char_lookup_has(&ch_lookup, s[0])) + s++; + if (s[0] == '\0') + goto done2; + } + } done2: - nm_assert (i_token == num_tokens); - ptr[i_token] = NULL; - - if (f_strstrip) { - gsize i; - - i_token = 0; - for (i = 0; ptr[i]; i++) { - - s = (char *) nm_str_skip_leading_spaces (ptr[i]); - if (s[0] != '\0') { - char *s_last; - - s_last = &s[strlen (s) - 1]; - while ( s_last > s - && g_ascii_isspace (s_last[0]) - && ( ! f_allow_escaping - || !_char_is_escaped (s, s_last))) - (s_last--)[0] = '\0'; - } - - if ( !f_preserve_empty - && s[0] == '\0') - continue; - - ptr[i_token++] = s; - } - - if (i_token == 0) { - g_free (ptr); - return NULL; - } - ptr[i_token] = NULL; - } - - if (f_escaped) { - gsize i, j; - - /* We no longer need ch_lookup for its original purpose. Modify it, so it - * can detect the delimiters, '\\', and (optionally) whitespaces. */ - _char_lookup_table_set_one (ch_lookup, '\\'); - if (f_strstrip) - _char_lookup_table_set_all (ch_lookup, NM_ASCII_SPACES); - - for (i_token = 0; ptr[i_token]; i_token++) { - s = (char *) ptr[i_token]; - j = 0; - for (i = 0; s[i] != '\0'; ) { - if ( s[i] == '\\' - && _char_lookup_has (ch_lookup, s[i + 1])) - i++; - s[j++] = s[i++]; - } - s[j] = '\0'; - } - } - - nm_assert (ptr && ptr[0]); - return ptr; + nm_assert(i_token == num_tokens); + ptr[i_token] = NULL; + + if (f_strstrip) { + gsize i; + + i_token = 0; + for (i = 0; ptr[i]; i++) { + s = (char *) nm_str_skip_leading_spaces(ptr[i]); + if (s[0] != '\0') { + char *s_last; + + s_last = &s[strlen(s) - 1]; + while (s_last > s && g_ascii_isspace(s_last[0]) + && (!f_allow_escaping || !_char_is_escaped(s, s_last))) + (s_last--)[0] = '\0'; + } + + if (!f_preserve_empty && s[0] == '\0') + continue; + + ptr[i_token++] = s; + } + + if (i_token == 0) { + g_free(ptr); + return NULL; + } + ptr[i_token] = NULL; + } + + if (f_escaped) { + gsize i, j; + + /* We no longer need ch_lookup for its original purpose. Modify it, so it + * can detect the delimiters, '\\', and (optionally) whitespaces. */ + _char_lookup_table_set_one(&ch_lookup, '\\'); + if (f_strstrip) + _char_lookup_table_set_all(&ch_lookup, NM_ASCII_SPACES); + + for (i_token = 0; ptr[i_token]; i_token++) { + s = (char *) ptr[i_token]; + j = 0; + for (i = 0; s[i] != '\0';) { + if (s[i] == '\\' && _char_lookup_has(&ch_lookup, s[i + 1])) + i++; + s[j++] = s[i++]; + } + s[j] = '\0'; + } + } + + nm_assert(ptr && ptr[0]); + return ptr; } /*****************************************************************************/ const char * -nm_utils_escaped_tokens_escape_full (const char *str, - const char *delimiters, - const char *delimiters_as_needed, - NMUtilsEscapedTokensEscapeFlags flags, - char **out_to_free) -{ - guint8 ch_lookup[256]; - guint8 ch_lookup_as_needed[256]; - gboolean has_ch_lookup_as_needed = FALSE; - char *ret; - gsize str_len; - gsize alloc_len; - gsize n_escapes; - gsize i, j; - gboolean escape_leading_space; - gboolean escape_trailing_space; - gboolean escape_backslash_as_needed; - - nm_assert ( !delimiters_as_needed - || ( delimiters_as_needed[0] - && NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED))); - - if (!str || str[0] == '\0') { - *out_to_free = NULL; - return str; - } - - str_len = strlen (str); - - _char_lookup_table_init (ch_lookup, delimiters); - if ( !delimiters - || NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES)) { - flags &= ~( NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE); - _char_lookup_table_set_all (ch_lookup, NM_ASCII_SPACES); - } - - if (NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS)) { - _char_lookup_table_set_one (ch_lookup, '\\'); - escape_backslash_as_needed = FALSE; - } else if (_char_lookup_has (ch_lookup, '\\')) - escape_backslash_as_needed = FALSE; - else { - escape_backslash_as_needed = NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED); - if (escape_backslash_as_needed) { - if ( NM_FLAGS_ANY (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE) - && !_char_lookup_has_all (ch_lookup, NM_ASCII_SPACES)) { - /* ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE implies that we escape backslash - * before whitespaces. */ - if (!has_ch_lookup_as_needed) { - has_ch_lookup_as_needed = TRUE; - _char_lookup_table_init (ch_lookup_as_needed, NULL); - } - _char_lookup_table_set_all (ch_lookup_as_needed, NM_ASCII_SPACES); - } - if ( delimiters_as_needed - && !_char_lookup_has_all (ch_lookup, delimiters_as_needed)) { - if (!has_ch_lookup_as_needed) { - has_ch_lookup_as_needed = TRUE; - _char_lookup_table_init (ch_lookup_as_needed, NULL); - } - _char_lookup_table_set_all (ch_lookup_as_needed, delimiters_as_needed); - } - } - } - - escape_leading_space = NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE) - && g_ascii_isspace (str[0]) - && !_char_lookup_has (ch_lookup, str[0]); - if (str_len == 1) - escape_trailing_space = FALSE; - else { - escape_trailing_space = NM_FLAGS_HAS (flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE) - && g_ascii_isspace (str[str_len - 1]) - && !_char_lookup_has (ch_lookup, str[str_len - 1]); - } - - n_escapes = 0; - for (i = 0; str[i] != '\0'; i++) { - if (_char_lookup_has (ch_lookup, str[i])) - n_escapes++; - else if ( str[i] == '\\' - && escape_backslash_as_needed - && ( _char_lookup_has (ch_lookup, str[i + 1]) - || NM_IN_SET (str[i + 1], '\0', '\\') - || ( has_ch_lookup_as_needed - && _char_lookup_has (ch_lookup_as_needed, str[i + 1])))) - n_escapes++; - } - if (escape_leading_space) - n_escapes++; - if (escape_trailing_space) - n_escapes++; - - if (n_escapes == 0u) { - *out_to_free = NULL; - return str; - } - - alloc_len = str_len + n_escapes + 1u; - ret = g_new (char, alloc_len); - - j = 0; - i = 0; - - if (escape_leading_space) { - ret[j++] = '\\'; - ret[j++] = str[i++]; - } - for (; str[i] != '\0'; i++) { - if (_char_lookup_has (ch_lookup, str[i])) - ret[j++] = '\\'; - else if ( str[i] == '\\' - && escape_backslash_as_needed - && ( _char_lookup_has (ch_lookup, str[i + 1]) - || NM_IN_SET (str[i + 1], '\0', '\\') - || ( has_ch_lookup_as_needed - && _char_lookup_has (ch_lookup_as_needed, str[i + 1])))) - ret[j++] = '\\'; - ret[j++] = str[i]; - } - if (escape_trailing_space) { - nm_assert ( !_char_lookup_has (ch_lookup, ret[j - 1]) - && g_ascii_isspace (ret[j - 1])); - ret[j] = ret[j - 1]; - ret[j - 1] = '\\'; - j++; - } - - nm_assert (j == alloc_len - 1); - ret[j] = '\0'; - nm_assert (strlen (ret) == j); - - *out_to_free = ret; - return ret; +nm_utils_escaped_tokens_escape_full(const char * str, + const char * delimiters, + const char * delimiters_as_needed, + NMUtilsEscapedTokensEscapeFlags flags, + char ** out_to_free) +{ + CharLookupTable ch_lookup; + CharLookupTable ch_lookup_as_needed; + gboolean has_ch_lookup_as_needed = FALSE; + char * ret; + gsize str_len; + gsize alloc_len; + gsize n_escapes; + gsize i, j; + gboolean escape_leading_space; + gboolean escape_trailing_space; + gboolean escape_backslash_as_needed; + + nm_assert( + !delimiters_as_needed + || (delimiters_as_needed[0] + && NM_FLAGS_HAS(flags, + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED))); + + if (!str || str[0] == '\0') { + *out_to_free = NULL; + return str; + } + + str_len = strlen(str); + + _char_lookup_table_init(&ch_lookup, delimiters); + if (!delimiters || NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES)) { + flags &= ~(NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE); + _char_lookup_table_set_all(&ch_lookup, NM_ASCII_SPACES); + } + + if (NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS)) { + _char_lookup_table_set_one(&ch_lookup, '\\'); + escape_backslash_as_needed = FALSE; + } else if (_char_lookup_has(&ch_lookup, '\\')) + escape_backslash_as_needed = FALSE; + else { + escape_backslash_as_needed = + NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED); + if (escape_backslash_as_needed) { + if (NM_FLAGS_ANY(flags, + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE) + && !_char_lookup_has_all(&ch_lookup, NM_ASCII_SPACES)) { + /* ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE implies that we escape backslash + * before whitespaces. */ + if (!has_ch_lookup_as_needed) { + has_ch_lookup_as_needed = TRUE; + _char_lookup_table_init(&ch_lookup_as_needed, NULL); + } + _char_lookup_table_set_all(&ch_lookup_as_needed, NM_ASCII_SPACES); + } + if (delimiters_as_needed && !_char_lookup_has_all(&ch_lookup, delimiters_as_needed)) { + if (!has_ch_lookup_as_needed) { + has_ch_lookup_as_needed = TRUE; + _char_lookup_table_init(&ch_lookup_as_needed, NULL); + } + _char_lookup_table_set_all(&ch_lookup_as_needed, delimiters_as_needed); + } + } + } + + escape_leading_space = + NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE) + && g_ascii_isspace(str[0]) && !_char_lookup_has(&ch_lookup, str[0]); + if (str_len == 1) + escape_trailing_space = FALSE; + else { + escape_trailing_space = + NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE) + && g_ascii_isspace(str[str_len - 1]) && !_char_lookup_has(&ch_lookup, str[str_len - 1]); + } + + n_escapes = 0; + for (i = 0; str[i] != '\0'; i++) { + if (_char_lookup_has(&ch_lookup, str[i])) + n_escapes++; + else if (str[i] == '\\' && escape_backslash_as_needed + && (_char_lookup_has(&ch_lookup, str[i + 1]) || NM_IN_SET(str[i + 1], '\0', '\\') + || (has_ch_lookup_as_needed + && _char_lookup_has(&ch_lookup_as_needed, str[i + 1])))) + n_escapes++; + } + if (escape_leading_space) + n_escapes++; + if (escape_trailing_space) + n_escapes++; + + if (n_escapes == 0u) { + *out_to_free = NULL; + return str; + } + + alloc_len = str_len + n_escapes + 1u; + ret = g_new(char, alloc_len); + + j = 0; + i = 0; + + if (escape_leading_space) { + ret[j++] = '\\'; + ret[j++] = str[i++]; + } + for (; str[i] != '\0'; i++) { + if (_char_lookup_has(&ch_lookup, str[i])) + ret[j++] = '\\'; + else if (str[i] == '\\' && escape_backslash_as_needed + && (_char_lookup_has(&ch_lookup, str[i + 1]) || NM_IN_SET(str[i + 1], '\0', '\\') + || (has_ch_lookup_as_needed + && _char_lookup_has(&ch_lookup_as_needed, str[i + 1])))) + ret[j++] = '\\'; + ret[j++] = str[i]; + } + if (escape_trailing_space) { + nm_assert(!_char_lookup_has(&ch_lookup, ret[j - 1]) && g_ascii_isspace(ret[j - 1])); + ret[j] = ret[j - 1]; + ret[j - 1] = '\\'; + j++; + } + + nm_assert(j == alloc_len - 1); + ret[j] = '\0'; + nm_assert(strlen(ret) == j); + + *out_to_free = ret; + return ret; } /** @@ -1998,66 +1952,63 @@ nm_utils_escaped_tokens_escape_full (const char *str, * not be escaped, unless they are at the beginning or the end of key/value. */ void -nm_utils_escaped_tokens_options_split (char *str, - const char **out_key, - const char **out_val) -{ - const char *val = NULL; - gsize i; - gsize j; - gsize last_space_idx; - gboolean last_space_has; - - nm_assert (str); - - i = 0; - while (g_ascii_isspace (str[i])) - i++; - - j = 0; - last_space_idx = 0; - last_space_has = FALSE; - while (str[i] != '\0') { - if (g_ascii_isspace (str[i])) { - if (!last_space_has) { - last_space_has = TRUE; - last_space_idx = j; - } - } else { - if (str[i] == '\\') { - if ( NM_IN_SET (str[i + 1u], '\\', ',', '=') - || g_ascii_isspace (str[i + 1u])) - i++; - } else if (str[i] == '=') { - /* Encounter an unescaped '=' character. When we still parse the key, this - * is the separator we were waiting for. If we are parsing the value, - * we take the character verbatim. */ - if (!val) { - if (last_space_has) { - str[last_space_idx] = '\0'; - j = last_space_idx + 1; - last_space_has = FALSE; - } else - str[j++] = '\0'; - val = &str[j]; - i++; - while (g_ascii_isspace (str[i])) - i++; - continue; - } - } - last_space_has = FALSE; - } - str[j++] = str[i++]; - } - - if (last_space_has) - str[last_space_idx] = '\0'; - else - str[j] = '\0'; - - *out_key = str; - *out_val = val; +nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val) +{ + const char *val = NULL; + gsize i; + gsize j; + gsize last_space_idx; + gboolean last_space_has; + + nm_assert(str); + + i = 0; + while (g_ascii_isspace(str[i])) + i++; + + j = 0; + last_space_idx = 0; + last_space_has = FALSE; + while (str[i] != '\0') { + if (g_ascii_isspace(str[i])) { + if (!last_space_has) { + last_space_has = TRUE; + last_space_idx = j; + } + } else { + if (str[i] == '\\') { + if (NM_IN_SET(str[i + 1u], '\\', ',', '=') || g_ascii_isspace(str[i + 1u])) + i++; + } else if (str[i] == '=') { + /* Encounter an unescaped '=' character. When we still parse the key, this + * is the separator we were waiting for. If we are parsing the value, + * we take the character verbatim. */ + if (!val) { + if (last_space_has) { + str[last_space_idx] = '\0'; + j = last_space_idx + 1; + last_space_has = FALSE; + } else + str[j++] = '\0'; + val = &str[j]; + i++; + while (g_ascii_isspace(str[i])) + i++; + continue; + } + } + last_space_has = FALSE; + } + str[j++] = str[i++]; + } + + if (last_space_has) + str[last_space_idx] = '\0'; + else + str[j] = '\0'; + + *out_key = str; + *out_val = val; } /*****************************************************************************/ @@ -2078,80 +2029,80 @@ nm_utils_escaped_tokens_options_split (char *str, * Returns: (transfer full): the split string. */ char ** -nm_utils_strsplit_quoted (const char *str) -{ - gs_unref_ptrarray GPtrArray *arr = NULL; - gs_free char *str_out = NULL; - guint8 ch_lookup[256]; - - nm_assert (str); - - _char_lookup_table_init (ch_lookup, NM_ASCII_WHITESPACES); - - for (;;) { - char quote; - gsize j; - - while (_char_lookup_has (ch_lookup, str[0])) - str++; - - if (str[0] == '\0') - break; - - if (!str_out) - str_out = g_new (char, strlen (str) + 1); - - quote = '\0'; - j = 0; - for (;;) { - if (str[0] == '\\') { - str++; - if (str[0] == '\0') - break; - str_out[j++] = str[0]; - str++; - continue; - } - if (quote) { - if (str[0] == '\0') - break; - if (str[0] == quote) { - quote = '\0'; - str++; - continue; - } - str_out[j++] = str[0]; - str++; - continue; - } - if (str[0] == '\0') - break; - if (NM_IN_SET (str[0], '\'', '"')) { - quote = str[0]; - str++; - continue; - } - if (_char_lookup_has (ch_lookup, str[0])) { - str++; - break; - } - str_out[j++] = str[0]; - str++; - } - - if (!arr) - arr = g_ptr_array_new (); - g_ptr_array_add (arr, g_strndup (str_out, j)); - } - - if (!arr) - return g_new0 (char *, 1); - - g_ptr_array_add (arr, NULL); - - /* We want to return an optimally sized strv array, with no excess - * memory allocated. Hence, clone once more. */ - return nm_memdup (arr->pdata, sizeof (char *) * arr->len); +nm_utils_strsplit_quoted(const char *str) +{ + gs_unref_ptrarray GPtrArray *arr = NULL; + gs_free char * str_out = NULL; + CharLookupTable ch_lookup; + + nm_assert(str); + + _char_lookup_table_init(&ch_lookup, NM_ASCII_WHITESPACES); + + for (;;) { + char quote; + gsize j; + + while (_char_lookup_has(&ch_lookup, str[0])) + str++; + + if (str[0] == '\0') + break; + + if (!str_out) + str_out = g_new(char, strlen(str) + 1); + + quote = '\0'; + j = 0; + for (;;) { + if (str[0] == '\\') { + str++; + if (str[0] == '\0') + break; + str_out[j++] = str[0]; + str++; + continue; + } + if (quote) { + if (str[0] == '\0') + break; + if (str[0] == quote) { + quote = '\0'; + str++; + continue; + } + str_out[j++] = str[0]; + str++; + continue; + } + if (str[0] == '\0') + break; + if (NM_IN_SET(str[0], '\'', '"')) { + quote = str[0]; + str++; + continue; + } + if (_char_lookup_has(&ch_lookup, str[0])) { + str++; + break; + } + str_out[j++] = str[0]; + str++; + } + + if (!arr) + arr = g_ptr_array_new(); + g_ptr_array_add(arr, g_strndup(str_out, j)); + } + + if (!arr) + return g_new0(char *, 1); + + g_ptr_array_add(arr, NULL); + + /* We want to return an optimally sized strv array, with no excess + * memory allocated. Hence, clone once more. */ + return nm_memdup(arr->pdata, sizeof(char *) * arr->len); } /*****************************************************************************/ @@ -2170,140 +2121,154 @@ nm_utils_strsplit_quoted (const char *str) * Returns: index of first occurrence or -1 if @needle is not found in @list. */ gssize -nm_utils_strv_find_first (char **list, gssize len, const char *needle) -{ - gssize i; - - if (len > 0) { - g_return_val_if_fail (list, -1); - - if (!needle) { - /* if we search a list with known length, %NULL is a valid @needle. */ - for (i = 0; i < len; i++) { - if (!list[i]) - return i; - } - } else { - for (i = 0; i < len; i++) { - if (list[i] && !strcmp (needle, list[i])) - return i; - } - } - } else if (len < 0) { - g_return_val_if_fail (needle, -1); - - if (list) { - for (i = 0; list[i]; i++) { - if (strcmp (needle, list[i]) == 0) - return i; - } - } - } - return -1; +nm_utils_strv_find_first(char **list, gssize len, const char *needle) +{ + gssize i; + + if (len > 0) { + g_return_val_if_fail(list, -1); + + if (!needle) { + /* if we search a list with known length, %NULL is a valid @needle. */ + for (i = 0; i < len; i++) { + if (!list[i]) + return i; + } + } else { + for (i = 0; i < len; i++) { + if (list[i] && !strcmp(needle, list[i])) + return i; + } + } + } else if (len < 0) { + g_return_val_if_fail(needle, -1); + + if (list) { + for (i = 0; list[i]; i++) { + if (strcmp(needle, list[i]) == 0) + return i; + } + } + } + return -1; } char ** -_nm_utils_strv_cleanup (char **strv, - gboolean strip_whitespace, - gboolean skip_empty, - gboolean skip_repeated) -{ - guint i, j; - - if (!strv || !*strv) - return strv; - - if (strip_whitespace) { - /* we only modify the strings pointed to by @strv if @strip_whitespace is - * requested. Otherwise, the strings themselves are untouched. */ - for (i = 0; strv[i]; i++) - g_strstrip (strv[i]); - } - if (!skip_empty && !skip_repeated) - return strv; - j = 0; - for (i = 0; strv[i]; i++) { - if ( (skip_empty && !*strv[i]) - || (skip_repeated && nm_utils_strv_find_first (strv, j, strv[i]) >= 0)) - g_free (strv[i]); - else - strv[j++] = strv[i]; - } - strv[j] = NULL; - return strv; +_nm_utils_strv_cleanup(char ** strv, + gboolean strip_whitespace, + gboolean skip_empty, + gboolean skip_repeated) +{ + guint i, j; + + if (!strv || !*strv) + return strv; + + if (strip_whitespace) { + /* we only modify the strings pointed to by @strv if @strip_whitespace is + * requested. Otherwise, the strings themselves are untouched. */ + for (i = 0; strv[i]; i++) + g_strstrip(strv[i]); + } + if (!skip_empty && !skip_repeated) + return strv; + j = 0; + for (i = 0; strv[i]; i++) { + if ((skip_empty && !*strv[i]) + || (skip_repeated && nm_utils_strv_find_first(strv, j, strv[i]) >= 0)) + g_free(strv[i]); + else + strv[j++] = strv[i]; + } + strv[j] = NULL; + return strv; +} + +/*****************************************************************************/ + +GPtrArray * +_nm_g_ptr_array_copy(GPtrArray * array, + GCopyFunc func, + gpointer user_data, + GDestroyNotify element_free_func) +{ + GPtrArray *new_array; + guint i; + + g_return_val_if_fail(array, NULL); + + new_array = g_ptr_array_new_full(array->len, element_free_func); + for (i = 0; i < array->len; i++) { + g_ptr_array_add(new_array, func ? func(array->pdata[i], user_data) : array->pdata[i]); + } + return new_array; } /*****************************************************************************/ int -_nm_utils_ascii_str_to_bool (const char *str, - int default_value) +_nm_utils_ascii_str_to_bool(const char *str, int default_value) { - gs_free char *str_free = NULL; + gs_free char *str_free = NULL; - if (!str) - return default_value; + if (!str) + return default_value; - str = nm_strstrip_avoid_copy_a (300, str, &str_free); - if (str[0] == '\0') - return default_value; + str = nm_strstrip_avoid_copy_a(300, str, &str_free); + if (str[0] == '\0') + return default_value; - if ( !g_ascii_strcasecmp (str, "true") - || !g_ascii_strcasecmp (str, "yes") - || !g_ascii_strcasecmp (str, "on") - || !g_ascii_strcasecmp (str, "1")) - return TRUE; + if (!g_ascii_strcasecmp(str, "true") || !g_ascii_strcasecmp(str, "yes") + || !g_ascii_strcasecmp(str, "on") || !g_ascii_strcasecmp(str, "1")) + return TRUE; - if ( !g_ascii_strcasecmp (str, "false") - || !g_ascii_strcasecmp (str, "no") - || !g_ascii_strcasecmp (str, "off") - || !g_ascii_strcasecmp (str, "0")) - return FALSE; + if (!g_ascii_strcasecmp(str, "false") || !g_ascii_strcasecmp(str, "no") + || !g_ascii_strcasecmp(str, "off") || !g_ascii_strcasecmp(str, "0")) + return FALSE; - return default_value; + return default_value; } /*****************************************************************************/ -NM_CACHED_QUARK_FCN ("nm-utils-error-quark", nm_utils_error_quark) +NM_CACHED_QUARK_FCN("nm-utils-error-quark", nm_utils_error_quark); void -nm_utils_error_set_cancelled (GError **error, - gboolean is_disposing, - const char *instance_name) +nm_utils_error_set_cancelled(GError **error, gboolean is_disposing, const char *instance_name) { - if (is_disposing) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING, - "Disposing %s instance", - instance_name && *instance_name ? instance_name : "source"); - } else { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, - "Request cancelled"); - } + if (is_disposing) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_CANCELLED_DISPOSING, + "Disposing %s instance", + instance_name && *instance_name ? instance_name : "source"); + } else { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Request cancelled"); + } } gboolean -nm_utils_error_is_cancelled_or_disposing (GError *error) +nm_utils_error_is_cancelled_or_disposing(GError *error) { - if (error) { - if (error->domain == G_IO_ERROR) - return NM_IN_SET (error->code, G_IO_ERROR_CANCELLED); - if (error->domain == NM_UTILS_ERROR) - return NM_IN_SET (error->code, NM_UTILS_ERROR_CANCELLED_DISPOSING); - } - return FALSE; + if (error) { + if (error->domain == G_IO_ERROR) + return NM_IN_SET(error->code, G_IO_ERROR_CANCELLED); + if (error->domain == NM_UTILS_ERROR) + return NM_IN_SET(error->code, NM_UTILS_ERROR_CANCELLED_DISPOSING); + } + return FALSE; } gboolean -nm_utils_error_is_notfound (GError *error) +nm_utils_error_is_notfound(GError *error) { - if (error) { - if (error->domain == G_IO_ERROR) - return NM_IN_SET (error->code, G_IO_ERROR_NOT_FOUND); - if (error->domain == G_FILE_ERROR) - return NM_IN_SET (error->code, G_FILE_ERROR_NOENT); - } - return FALSE; + if (error) { + if (error->domain == G_IO_ERROR) + return NM_IN_SET(error->code, G_IO_ERROR_NOT_FOUND); + if (error->domain == G_FILE_ERROR) + return NM_IN_SET(error->code, G_FILE_ERROR_NOENT); + } + return FALSE; } /*****************************************************************************/ @@ -2324,220 +2289,233 @@ nm_utils_error_is_notfound (GError *error) * Returns: whether the value was successfully set. */ gboolean -nm_g_object_set_property (GObject *object, - const char *property_name, - const GValue *value, - GError **error) -{ - GParamSpec *pspec; - nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT; - GObjectClass *klass; - - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - g_return_val_if_fail (property_name != NULL, FALSE); - g_return_val_if_fail (G_IS_VALUE (value), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - /* g_object_class_find_property() does g_param_spec_get_redirect_target(), - * where we differ from a plain g_object_set_property(). */ - pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name); - - if (!pspec) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("object class '%s' has no property named '%s'"), - G_OBJECT_TYPE_NAME (object), - property_name); - return FALSE; - } - if (!(pspec->flags & G_PARAM_WRITABLE)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("property '%s' of object class '%s' is not writable"), - pspec->name, - G_OBJECT_TYPE_NAME (object)); - return FALSE; - } - if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("construct property \"%s\" for object '%s' can't be set after construction"), - pspec->name, G_OBJECT_TYPE_NAME (object)); - return FALSE; - } - - klass = g_type_class_peek (pspec->owner_type); - if (klass == NULL) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"), - g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type)); - return FALSE; - } - - /* provide a copy to work from, convert (if necessary) and validate */ - g_value_init (&tmp_value, pspec->value_type); - if (!g_value_transform (value, &tmp_value)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("unable to set property '%s' of type '%s' from value of type '%s'"), - pspec->name, - g_type_name (pspec->value_type), - G_VALUE_TYPE_NAME (value)); - return FALSE; - } - if ( g_param_value_validate (pspec, &tmp_value) - && !(pspec->flags & G_PARAM_LAX_VALIDATION)) { - gs_free char *contents = g_strdup_value_contents (value); - - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'"), - contents, - G_VALUE_TYPE_NAME (value), - pspec->name, - g_type_name (pspec->value_type)); - return FALSE; - } - - g_object_set_property (object, property_name, &tmp_value); - return TRUE; -} - -#define _set_property(object, property_name, gtype, gtype_set, value, error) \ - G_STMT_START { \ - nm_auto_unset_gvalue GValue gvalue = { 0 }; \ - \ - g_value_init (&gvalue, gtype); \ - gtype_set (&gvalue, (value)); \ - return nm_g_object_set_property ((object), (property_name), &gvalue, (error)); \ - } G_STMT_END +nm_g_object_set_property(GObject * object, + const char * property_name, + const GValue *value, + GError ** error) +{ + GParamSpec * pspec; + nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT; + GObjectClass * klass; + + g_return_val_if_fail(G_IS_OBJECT(object), FALSE); + g_return_val_if_fail(property_name != NULL, FALSE); + g_return_val_if_fail(G_IS_VALUE(value), FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + + /* g_object_class_find_property() does g_param_spec_get_redirect_target(), + * where we differ from a plain g_object_set_property(). */ + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object), property_name); + + if (!pspec) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("object class '%s' has no property named '%s'"), + G_OBJECT_TYPE_NAME(object), + property_name); + return FALSE; + } + if (!(pspec->flags & G_PARAM_WRITABLE)) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("property '%s' of object class '%s' is not writable"), + pspec->name, + G_OBJECT_TYPE_NAME(object)); + return FALSE; + } + if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("construct property \"%s\" for object '%s' can't be set after construction"), + pspec->name, + G_OBJECT_TYPE_NAME(object)); + return FALSE; + } + + klass = g_type_class_peek(pspec->owner_type); + if (klass == NULL) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"), + g_type_name(pspec->owner_type), + pspec->name, + g_type_name(pspec->owner_type)); + return FALSE; + } + + /* provide a copy to work from, convert (if necessary) and validate */ + g_value_init(&tmp_value, pspec->value_type); + if (!g_value_transform(value, &tmp_value)) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("unable to set property '%s' of type '%s' from value of type '%s'"), + pspec->name, + g_type_name(pspec->value_type), + G_VALUE_TYPE_NAME(value)); + return FALSE; + } + if (g_param_value_validate(pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION)) { + gs_free char *contents = g_strdup_value_contents(value); + + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of " + "type '%s'"), + contents, + G_VALUE_TYPE_NAME(value), + pspec->name, + g_type_name(pspec->value_type)); + return FALSE; + } + + g_object_set_property(object, property_name, &tmp_value); + return TRUE; +} + +#define _set_property(object, property_name, gtype, gtype_set, value, error) \ + G_STMT_START \ + { \ + nm_auto_unset_gvalue GValue gvalue = {0}; \ + \ + g_value_init(&gvalue, gtype); \ + gtype_set(&gvalue, (value)); \ + return nm_g_object_set_property((object), (property_name), &gvalue, (error)); \ + } \ + G_STMT_END gboolean -nm_g_object_set_property_string (GObject *object, - const char *property_name, - const char *value, - GError **error) +nm_g_object_set_property_string(GObject * object, + const char *property_name, + const char *value, + GError ** error) { - _set_property (object, property_name, G_TYPE_STRING, g_value_set_string, value, error); + _set_property(object, property_name, G_TYPE_STRING, g_value_set_string, value, error); } gboolean -nm_g_object_set_property_string_static (GObject *object, - const char *property_name, - const char *value, - GError **error) +nm_g_object_set_property_string_static(GObject * object, + const char *property_name, + const char *value, + GError ** error) { - _set_property (object, property_name, G_TYPE_STRING, g_value_set_static_string, value, error); + _set_property(object, property_name, G_TYPE_STRING, g_value_set_static_string, value, error); } gboolean -nm_g_object_set_property_string_take (GObject *object, - const char *property_name, - char *value, - GError **error) +nm_g_object_set_property_string_take(GObject * object, + const char *property_name, + char * value, + GError ** error) { - _set_property (object, property_name, G_TYPE_STRING, g_value_take_string, value, error); + _set_property(object, property_name, G_TYPE_STRING, g_value_take_string, value, error); } gboolean -nm_g_object_set_property_boolean (GObject *object, - const char *property_name, - gboolean value, - GError **error) +nm_g_object_set_property_boolean(GObject * object, + const char *property_name, + gboolean value, + GError ** error) { - _set_property (object, property_name, G_TYPE_BOOLEAN, g_value_set_boolean, !!value, error); + _set_property(object, property_name, G_TYPE_BOOLEAN, g_value_set_boolean, !!value, error); } gboolean -nm_g_object_set_property_char (GObject *object, - const char *property_name, - gint8 value, - GError **error) +nm_g_object_set_property_char(GObject * object, + const char *property_name, + gint8 value, + GError ** error) { - /* glib says about G_TYPE_CHAR: - * - * The type designated by G_TYPE_CHAR is unconditionally an 8-bit signed integer. - * - * This is always a (signed!) char. */ - _set_property (object, property_name, G_TYPE_CHAR, g_value_set_schar, value, error); + /* glib says about G_TYPE_CHAR: + * + * The type designated by G_TYPE_CHAR is unconditionally an 8-bit signed integer. + * + * This is always a (signed!) char. */ + _set_property(object, property_name, G_TYPE_CHAR, g_value_set_schar, value, error); } gboolean -nm_g_object_set_property_uchar (GObject *object, - const char *property_name, - guint8 value, - GError **error) +nm_g_object_set_property_uchar(GObject * object, + const char *property_name, + guint8 value, + GError ** error) { - _set_property (object, property_name, G_TYPE_UCHAR, g_value_set_uchar, value, error); + _set_property(object, property_name, G_TYPE_UCHAR, g_value_set_uchar, value, error); } gboolean -nm_g_object_set_property_int (GObject *object, - const char *property_name, - int value, - GError **error) +nm_g_object_set_property_int(GObject *object, const char *property_name, int value, GError **error) { - _set_property (object, property_name, G_TYPE_INT, g_value_set_int, value, error); + _set_property(object, property_name, G_TYPE_INT, g_value_set_int, value, error); } gboolean -nm_g_object_set_property_int64 (GObject *object, - const char *property_name, - gint64 value, - GError **error) +nm_g_object_set_property_int64(GObject * object, + const char *property_name, + gint64 value, + GError ** error) { - _set_property (object, property_name, G_TYPE_INT64, g_value_set_int64, value, error); + _set_property(object, property_name, G_TYPE_INT64, g_value_set_int64, value, error); } gboolean -nm_g_object_set_property_uint (GObject *object, - const char *property_name, - guint value, - GError **error) +nm_g_object_set_property_uint(GObject * object, + const char *property_name, + guint value, + GError ** error) { - _set_property (object, property_name, G_TYPE_UINT, g_value_set_uint, value, error); + _set_property(object, property_name, G_TYPE_UINT, g_value_set_uint, value, error); } gboolean -nm_g_object_set_property_uint64 (GObject *object, - const char *property_name, - guint64 value, - GError **error) +nm_g_object_set_property_uint64(GObject * object, + const char *property_name, + guint64 value, + GError ** error) { - _set_property (object, property_name, G_TYPE_UINT64, g_value_set_uint64, value, error); + _set_property(object, property_name, G_TYPE_UINT64, g_value_set_uint64, value, error); } gboolean -nm_g_object_set_property_flags (GObject *object, - const char *property_name, - GType gtype, - guint value, - GError **error) +nm_g_object_set_property_flags(GObject * object, + const char *property_name, + GType gtype, + guint value, + GError ** error) { - nm_assert (({ - nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype); - G_IS_FLAGS_CLASS (gtypeclass); - })); - _set_property (object, property_name, gtype, g_value_set_flags, value, error); + nm_assert(({ + nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref(gtype); + G_IS_FLAGS_CLASS(gtypeclass); + })); + _set_property(object, property_name, gtype, g_value_set_flags, value, error); } gboolean -nm_g_object_set_property_enum (GObject *object, - const char *property_name, - GType gtype, - int value, - GError **error) +nm_g_object_set_property_enum(GObject * object, + const char *property_name, + GType gtype, + int value, + GError ** error) { - nm_assert (({ - nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref (gtype); - G_IS_ENUM_CLASS (gtypeclass); - })); - _set_property (object, property_name, gtype, g_value_set_enum, value, error); + nm_assert(({ + nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref(gtype); + G_IS_ENUM_CLASS(gtypeclass); + })); + _set_property(object, property_name, gtype, g_value_set_enum, value, error); } GParamSpec * -nm_g_object_class_find_property_from_gtype (GType gtype, - const char *property_name) +nm_g_object_class_find_property_from_gtype(GType gtype, const char *property_name) { - nm_auto_unref_gtypeclass GObjectClass *gclass = NULL; + nm_auto_unref_gtypeclass GObjectClass *gclass = NULL; - gclass = g_type_class_ref (gtype); - return g_object_class_find_property (gclass, property_name); + gclass = g_type_class_ref(gtype); + return g_object_class_find_property(gclass, property_name); } /*****************************************************************************/ @@ -2557,163 +2535,208 @@ nm_g_object_class_find_property_from_gtype (GType gtype, * that added @pname. */ GType -nm_g_type_find_implementing_class_for_property (GType gtype, - const char *pname) +nm_g_type_find_implementing_class_for_property(GType gtype, const char *pname) { - nm_auto_unref_gtypeclass GObjectClass *klass = NULL; - GParamSpec *pspec; + nm_auto_unref_gtypeclass GObjectClass *klass = NULL; + GParamSpec * pspec; - g_return_val_if_fail (pname, G_TYPE_INVALID); + g_return_val_if_fail(pname, G_TYPE_INVALID); - klass = g_type_class_ref (gtype); - g_return_val_if_fail (G_IS_OBJECT_CLASS (klass), G_TYPE_INVALID); + klass = g_type_class_ref(gtype); + g_return_val_if_fail(G_IS_OBJECT_CLASS(klass), G_TYPE_INVALID); - pspec = g_object_class_find_property (klass, pname); - g_return_val_if_fail (pspec, G_TYPE_INVALID); + pspec = g_object_class_find_property(klass, pname); + g_return_val_if_fail(pspec, G_TYPE_INVALID); - gtype = G_TYPE_FROM_CLASS (klass); + gtype = G_TYPE_FROM_CLASS(klass); - while (TRUE) { - nm_auto_unref_gtypeclass GObjectClass *k = NULL; + while (TRUE) { + nm_auto_unref_gtypeclass GObjectClass *k = NULL; - k = g_type_class_ref (g_type_parent (gtype)); + k = g_type_class_ref(g_type_parent(gtype)); - g_return_val_if_fail (G_IS_OBJECT_CLASS (k), G_TYPE_INVALID); + g_return_val_if_fail(G_IS_OBJECT_CLASS(k), G_TYPE_INVALID); - if (g_object_class_find_property (k, pname) != pspec) - return gtype; + if (g_object_class_find_property(k, pname) != pspec) + return gtype; - gtype = G_TYPE_FROM_CLASS (k); - } + gtype = G_TYPE_FROM_CLASS(k); + } } /*****************************************************************************/ static void -_str_buf_append_c_escape_octal (NMStrBuf *strbuf, - char ch) +_str_buf_append_c_escape_octal(NMStrBuf *strbuf, char ch) { - nm_str_buf_append_c4 (strbuf, - '\\', - '0' + ((char) ((((guchar) ch) >> 6) & 07)), - '0' + ((char) ((((guchar) ch) >> 3) & 07)), - '0' + ((char) ((((guchar) ch) ) & 07))); + nm_str_buf_append_c4(strbuf, + '\\', + '0' + ((char) ((((guchar) ch) >> 6) & 07)), + '0' + ((char) ((((guchar) ch) >> 3) & 07)), + '0' + ((char) ((((guchar) ch)) & 07))); } +/** + * nm_utils_buf_utf8safe_unescape: + * @str: (allow-none): the string to unescape. The string itself is a NUL terminated + * ASCII string, that can have C-style backslash escape sequences (which + * are to be unescaped). Non-ASCII characters (e.g. UTF-8) are taken verbatim, so + * it doesn't care that this string is UTF-8. However, usually this is a UTF-8 encoded + * string. + * @flags: flags for unescaping. The following flags are supported. + * %NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES performs a g_strstrip() on the input string, + * but preserving escaped spaces. For example, "a\\t " gives "a\t" (that is, the escaped space does + * not get stripped). Likewise, the invalid escape sequence "a\\ " results in "a " (stripping + * the unescaped space, but preserving the escaped one). + * @out_len: (out): the length of the parsed string. + * @to_free: (out): if @str requires unescaping, the function will clone the string. In + * that case, the allocated buffer will be returned here. + * + * See C-style escapes at https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences. + * Note that hex escapes ("\\xhh") and unicode escapes ("\\uhhhh", "\\Uhhhhhhhh") are not supported. + * + * Also, this function is very similar to g_strcompress() but without issuing g_warning() + * assertions and proper handling of "\\000" escape sequences. + * + * Invalid escape sequences (or non-UTF-8 input) are gracefully accepted. For example "\\ " + * is an invalid escape sequence, in this case the backslash is removed and " " gets returned. + * + * The function never leaks secrets in memory. + * + * Returns: the unescaped buffer of length @out_len. If @str is %NULL, this returns %NULL + * and sets @out_len to 0. Otherwise, a non-%NULL binary buffer is returned with + * @out_len bytes. Note that the binary buffer is guaranteed to be NUL terminated. That + * is @result[@out_len] is NUL. + * Note that the result is binary, and may have embedded NUL characters and non-UTF-8. + * If the function can avoid cloning the input string, it will return a pointer inside + * the input @str. For example, if there is no backslash, no cloning is necessary. In that + * case, @to_free will be %NULL. Otherwise, @to_free is set to a newly allocated buffer + * containing the unescaped string and returned. + */ gconstpointer -nm_utils_buf_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, gsize *out_len, gpointer *to_free) -{ - gboolean strip_spaces = NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES); - NMStrBuf strbuf; - const char *s; - gsize len; - - g_return_val_if_fail (to_free, NULL); - g_return_val_if_fail (out_len, NULL); - - if (!str) { - *out_len = 0; - *to_free = NULL; - return NULL; - } - - if (strip_spaces) - str = nm_str_skip_leading_spaces (str); - - len = strlen (str); - - s = memchr (str, '\\', len); - if (!s) { - if ( strip_spaces - && len > 0 - && g_ascii_isspace (str[len - 1])) { - len--; - while ( len > 0 - && g_ascii_isspace (str[len - 1])) - len--; - *out_len = len; - return (*to_free = g_strndup (str, len)); - } - *out_len = len; - *to_free = NULL; - return str; - } - - nm_str_buf_init (&strbuf, len + 1u, FALSE); - - nm_str_buf_append_len (&strbuf, str, s - str); - str = s; - - for (;;) { - char ch; - guint v; - - nm_assert (str[0] == '\\'); - - ch = (++str)[0]; - - if (ch == '\0') { - /* error. Trailing '\\' */ - break; - } - - if (ch >= '0' && ch <= '9') { - v = ch - '0'; - ch = (++str)[0]; - if (ch >= '0' && ch <= '7') { - v = v * 8 + (ch - '0'); - ch = (++str)[0]; - if (ch >= '0' && ch <= '7') { - /* technically, escape sequences larger than \3FF are out of range - * and invalid. We don't check for that, and do the same as - * g_strcompress(): silently clip the value with & 0xFF. */ - v = v * 8 + (ch - '0'); - ++str; - } - } - ch = v; - } else { - switch (ch) { - case 'b': ch = '\b'; break; - case 'f': ch = '\f'; break; - case 'n': ch = '\n'; break; - case 'r': ch = '\r'; break; - case 't': ch = '\t'; break; - case 'v': ch = '\v'; break; - default: - /* Here we handle "\\\\", but all other unexpected escape sequences are really a bug. - * Take them literally, after removing the escape character */ - break; - } - str++; - } - - nm_str_buf_append_c (&strbuf, ch); - - s = strchr (str, '\\'); - if (!s) { - gsize l = strlen (str); - - if (strip_spaces) { - while ( l > 0 - && g_ascii_isspace (str[l - 1])) - l--; - } - nm_str_buf_append_len (&strbuf, str, l); - break; - } - - nm_str_buf_append_len (&strbuf, str, s - str); - str = s; - } - - /* assert that no reallocation was necessary. For one, unescaping should - * never result in a longer string than the input. Also, when unescaping - * secrets, we want to ensure that we don't leak secrets in memory. */ - nm_assert (strbuf.allocated == len + 1u); - - return (*to_free = nm_str_buf_finalize (&strbuf, - out_len)); +nm_utils_buf_utf8safe_unescape(const char * str, + NMUtilsStrUtf8SafeFlags flags, + gsize * out_len, + gpointer * to_free) +{ + gboolean strip_spaces = NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES); + NMStrBuf strbuf; + const char *s; + gsize len; + + g_return_val_if_fail(to_free, NULL); + g_return_val_if_fail(out_len, NULL); + + if (!str) { + *out_len = 0; + *to_free = NULL; + return NULL; + } + + if (strip_spaces) + str = nm_str_skip_leading_spaces(str); + + len = strlen(str); + + s = memchr(str, '\\', len); + if (!s) { + if (strip_spaces && len > 0 && g_ascii_isspace(str[len - 1])) { + len--; + while (len > 0 && g_ascii_isspace(str[len - 1])) + len--; + *out_len = len; + return (*to_free = g_strndup(str, len)); + } + *out_len = len; + *to_free = NULL; + return str; + } + + nm_str_buf_init(&strbuf, len + 1u, FALSE); + + nm_str_buf_append_len(&strbuf, str, s - str); + str = s; + + for (;;) { + char ch; + guint v; + + nm_assert(str[0] == '\\'); + + ch = (++str)[0]; + + if (ch == '\0') { + /* error. Trailing '\\' */ + break; + } + + if (ch >= '0' && ch <= '9') { + v = ch - '0'; + ch = (++str)[0]; + if (ch >= '0' && ch <= '7') { + v = v * 8 + (ch - '0'); + ch = (++str)[0]; + if (ch >= '0' && ch <= '7') { + /* technically, escape sequences larger than \3FF are out of range + * and invalid. We don't check for that, and do the same as + * g_strcompress(): silently clip the value with & 0xFF. */ + v = v * 8 + (ch - '0'); + ++str; + } + } + ch = v; + } else { + switch (ch) { + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case 'v': + ch = '\v'; + break; + default: + /* Here we handle "\\\\", but all other unexpected escape sequences are really a bug. + * Take them literally, after removing the escape character */ + break; + } + str++; + } + + nm_str_buf_append_c(&strbuf, ch); + + s = strchr(str, '\\'); + if (!s) { + gsize l = strlen(str); + + if (strip_spaces) { + while (l > 0 && g_ascii_isspace(str[l - 1])) + l--; + } + nm_str_buf_append_len(&strbuf, str, l); + break; + } + + nm_str_buf_append_len(&strbuf, str, s - str); + str = s; + } + + /* assert that no reallocation was necessary. For one, unescaping should + * never result in a longer string than the input. Also, when unescaping + * secrets, we want to ensure that we don't leak secrets in memory. */ + nm_assert(strbuf.allocated == len + 1u); + + return (*to_free = nm_str_buf_finalize(&strbuf, out_len)); } /** @@ -2748,126 +2771,125 @@ nm_utils_buf_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, * with g_free. The escaping can be reverted by g_strcompress(). **/ const char * -nm_utils_buf_utf8safe_escape (gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags, char **to_free) -{ - const char *const str = buf; - const char *p = NULL; - const char *s; - gboolean nul_terminated = FALSE; - NMStrBuf strbuf; - - g_return_val_if_fail (to_free, NULL); - - *to_free = NULL; - - if (buflen == 0) - return NULL; - - if (buflen < 0) { - if (!str) - return NULL; - buflen = strlen (str); - if (buflen == 0) - return str; - nul_terminated = TRUE; - } - - if ( g_utf8_validate (str, buflen, &p) - && nul_terminated) { - /* note that g_utf8_validate() does not allow NUL character inside @str. Good. - * We can treat @str like a NUL terminated string. */ - if (!NM_STRCHAR_ANY (str, ch, - ( ch == '\\' \ - || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \ - && ch < ' ') \ - || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \ - && ((guchar) ch) >= 127)))) - return str; - } - - nm_str_buf_init (&strbuf, - buflen + 5, - NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET)); - - s = str; - do { - buflen -= p - s; - nm_assert (buflen >= 0); - - for (; s < p; s++) { - char ch = s[0]; - - nm_assert (ch); - if (ch == '\\') - nm_str_buf_append_c2 (&strbuf, '\\', '\\'); - else if ( ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) \ - && ch < ' ') \ - || ( NM_FLAGS_HAS (flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) \ - && ((guchar) ch) >= 127)) - _str_buf_append_c_escape_octal (&strbuf, ch); - else - nm_str_buf_append_c (&strbuf, ch); - } - - if (buflen <= 0) - break; - - _str_buf_append_c_escape_octal (&strbuf, p[0]); - - buflen--; - if (buflen == 0) - break; - - s = &p[1]; - (void) g_utf8_validate (s, buflen, &p); - } while (TRUE); - - return (*to_free = nm_str_buf_finalize (&strbuf, NULL)); +nm_utils_buf_utf8safe_escape(gconstpointer buf, + gssize buflen, + NMUtilsStrUtf8SafeFlags flags, + char ** to_free) +{ + const char *const str = buf; + const char * p = NULL; + const char * s; + gboolean nul_terminated = FALSE; + NMStrBuf strbuf; + + g_return_val_if_fail(to_free, NULL); + + *to_free = NULL; + + if (buflen == 0) + return NULL; + + if (buflen < 0) { + if (!str) + return NULL; + buflen = strlen(str); + if (buflen == 0) + return str; + nul_terminated = TRUE; + } + + if (g_utf8_validate(str, buflen, &p) && nul_terminated) { + /* note that g_utf8_validate() does not allow NUL character inside @str. Good. + * We can treat @str like a NUL terminated string. */ + if (!NM_STRCHAR_ANY( + str, + ch, + (ch == '\\' + || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ') + || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) + && ((guchar) ch) >= 127)))) + return str; + } + + nm_str_buf_init(&strbuf, buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET)); + + s = str; + do { + buflen -= p - s; + nm_assert(buflen >= 0); + + for (; s < p; s++) { + char ch = s[0]; + + nm_assert(ch); + if (ch == '\\') + nm_str_buf_append_c2(&strbuf, '\\', '\\'); + else if ((NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ') + || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII) + && ((guchar) ch) >= 127)) + _str_buf_append_c_escape_octal(&strbuf, ch); + else + nm_str_buf_append_c(&strbuf, ch); + } + + if (buflen <= 0) + break; + + _str_buf_append_c_escape_octal(&strbuf, p[0]); + + buflen--; + if (buflen == 0) + break; + + s = &p[1]; + (void) g_utf8_validate(s, buflen, &p); + } while (TRUE); + + return (*to_free = nm_str_buf_finalize(&strbuf, NULL)); } const char * -nm_utils_buf_utf8safe_escape_bytes (GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free) +nm_utils_buf_utf8safe_escape_bytes(GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free) { - gconstpointer p; - gsize l; + gconstpointer p; + gsize l; - if (bytes) - p = g_bytes_get_data (bytes, &l); - else { - p = NULL; - l = 0; - } + if (bytes) + p = g_bytes_get_data(bytes, &l); + else { + p = NULL; + l = 0; + } - return nm_utils_buf_utf8safe_escape (p, l, flags, to_free); + return nm_utils_buf_utf8safe_escape(p, l, flags, to_free); } char * -nm_utils_buf_utf8safe_escape_cp (gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags) +nm_utils_buf_utf8safe_escape_cp(gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags) { - const char *s_const; - char *s; + const char *s_const; + char * s; - s_const = nm_utils_buf_utf8safe_escape (buf, buflen, flags, &s); - nm_assert (!s || s == s_const); - return s ?: g_strdup (s_const); + s_const = nm_utils_buf_utf8safe_escape(buf, buflen, flags, &s); + nm_assert(!s || s == s_const); + return s ?: g_strdup(s_const); } /*****************************************************************************/ const char * -nm_utils_str_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free) +nm_utils_str_utf8safe_unescape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free) { - const char *res; - gsize len; + const char *res; + gsize len; - g_return_val_if_fail (to_free, NULL); + g_return_val_if_fail(to_free, NULL); - res = nm_utils_buf_utf8safe_unescape (str, flags, &len, (gpointer *) to_free); + res = nm_utils_buf_utf8safe_unescape(str, flags, &len, (gpointer *) to_free); - nm_assert ( (!res && len == 0) - || (strlen (res) <= len)); + nm_assert((!res && len == 0) || (strlen(res) <= len)); - return res; + return res; } /** @@ -2898,9 +2920,9 @@ nm_utils_str_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, * with g_free. The escaping can be reverted by g_strcompress(). **/ const char * -nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free) +nm_utils_str_utf8safe_escape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free) { - return nm_utils_buf_utf8safe_escape (str, -1, flags, to_free); + return nm_utils_buf_utf8safe_escape(str, -1, flags, to_free); } /** @@ -2916,34 +2938,34 @@ nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, ch * The escaping can be reverted by g_strcompress(). **/ char * -nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags) +nm_utils_str_utf8safe_escape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags) { - char *s; + char *s; - nm_utils_str_utf8safe_escape (str, flags, &s); - return s ?: g_strdup (str); + nm_utils_str_utf8safe_escape(str, flags, &s); + return s ?: g_strdup(str); } char * -nm_utils_str_utf8safe_unescape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags) +nm_utils_str_utf8safe_unescape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags) { - char *s; + char *s; - str = nm_utils_str_utf8safe_unescape (str, flags, &s); - return s ?: g_strdup (str); + str = nm_utils_str_utf8safe_unescape(str, flags, &s); + return s ?: g_strdup(str); } char * -nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags) +nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags) { - char *str_to_free; + char *str_to_free; - nm_utils_str_utf8safe_escape (str, flags, &str_to_free); - if (str_to_free) { - g_free (str); - return str_to_free; - } - return str; + nm_utils_str_utf8safe_escape(str, flags, &str_to_free); + if (str_to_free) { + g_free(str); + return str_to_free; + } + return str; } /*****************************************************************************/ @@ -2951,358 +2973,569 @@ nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags) /* taken from systemd's fd_wait_for_event(). Note that the timeout * is here in nano-seconds, not micro-seconds. */ int -nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_nsec) -{ - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; - struct timespec ts, *pts; - int r; - - if (timeout_nsec < 0) - pts = NULL; - else { - ts.tv_sec = (time_t) (timeout_nsec / NM_UTILS_NSEC_PER_SEC); - ts.tv_nsec = (long int) (timeout_nsec % NM_UTILS_NSEC_PER_SEC); - pts = &ts; - } - - r = ppoll (&pollfd, 1, pts, NULL); - if (r < 0) - return -NM_ERRNO_NATIVE (errno); - if (r == 0) - return 0; - return pollfd.revents; +nm_utils_fd_wait_for_event(int fd, int event, gint64 timeout_nsec) +{ + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; + struct timespec ts, *pts; + int r; + + if (timeout_nsec < 0) + pts = NULL; + else { + ts.tv_sec = (time_t)(timeout_nsec / NM_UTILS_NSEC_PER_SEC); + ts.tv_nsec = (long int) (timeout_nsec % NM_UTILS_NSEC_PER_SEC); + pts = &ts; + } + + r = ppoll(&pollfd, 1, pts, NULL); + if (r < 0) + return -NM_ERRNO_NATIVE(errno); + if (r == 0) + return 0; + return pollfd.revents; } /* taken from systemd's loop_read() */ ssize_t -nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll) +nm_utils_fd_read_loop(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; - ssize_t n = 0; + uint8_t *p = buf; + ssize_t n = 0; - g_return_val_if_fail (fd >= 0, -EINVAL); - g_return_val_if_fail (buf, -EINVAL); + g_return_val_if_fail(fd >= 0, -EINVAL); + g_return_val_if_fail(buf, -EINVAL); - /* If called with nbytes == 0, let's call read() at least - * once, to validate the operation */ + /* If called with nbytes == 0, let's call read() at least + * once, to validate the operation */ - if (nbytes > (size_t) SSIZE_MAX) - return -EINVAL; + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; - do { - ssize_t k; + do { + ssize_t k; - k = read (fd, p, nbytes); - if (k < 0) { - int errsv = errno; + k = read(fd, p, nbytes); + if (k < 0) { + int errsv = errno; - if (errsv == EINTR) - continue; + if (errsv == EINTR) + continue; - if (errsv == EAGAIN && do_poll) { + if (errsv == EAGAIN && do_poll) { + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ + (void) nm_utils_fd_wait_for_event(fd, POLLIN, -1); + continue; + } - (void) nm_utils_fd_wait_for_event (fd, POLLIN, -1); - continue; - } + return n > 0 ? n : -NM_ERRNO_NATIVE(errsv); + } - return n > 0 ? n : -NM_ERRNO_NATIVE (errsv); - } + if (k == 0) + return n; - if (k == 0) - return n; + g_assert((size_t) k <= nbytes); - g_assert ((size_t) k <= nbytes); + p += k; + nbytes -= k; + n += k; + } while (nbytes > 0); - p += k; - nbytes -= k; - n += k; - } while (nbytes > 0); - - return n; + return n; } /* taken from systemd's loop_read_exact() */ int -nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll) +nm_utils_fd_read_loop_exact(int fd, void *buf, size_t nbytes, bool do_poll) { - ssize_t n; + ssize_t n; - n = nm_utils_fd_read_loop (fd, buf, nbytes, do_poll); - if (n < 0) - return (int) n; - if ((size_t) n != nbytes) - return -EIO; + n = nm_utils_fd_read_loop(fd, buf, nbytes, do_poll); + if (n < 0) + return (int) n; + if ((size_t) n != nbytes) + return -EIO; - return 0; + return 0; } /*****************************************************************************/ +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) -{ - GHashTableIter iter; - NMUtilsNamedValue *values; - guint i, len; - - if ( !hash - || !(len = g_hash_table_size (hash))) { - NM_SET_OUT (out_len, 0); - return NULL; - } - - 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)) - i++; - nm_assert (i == len); - values[i].name = NULL; - values[i].value_ptr = NULL; - - if (compare_func) - nm_utils_named_value_list_sort (values, len, compare_func, user_data); - - NM_SET_OUT (out_len, len); - return values; +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; + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &values[i].name, &values[i].value_ptr)) + i++; + nm_assert(i == len); + values[i].name = NULL; + values[i].value_ptr = NULL; + + if (compare_func) + nm_utils_named_value_list_sort(values, len, compare_func, user_data); + + NM_SET_OUT(out_len, len); + return values; } gssize -nm_utils_named_value_list_find (const NMUtilsNamedValue *arr, - gsize len, - const char *name, - gboolean sorted) +nm_utils_named_value_list_find(const NMUtilsNamedValue *arr, + gsize len, + const char * name, + gboolean sorted) { - gsize i; + gsize i; - nm_assert (name); + nm_assert(name); #if NM_MORE_ASSERTS > 5 - { - for (i = 0; i < len; i++) { - const NMUtilsNamedValue *v = &arr[i]; - - nm_assert (v->name); - if ( sorted - && i > 0) - nm_assert (strcmp (arr[i - 1].name, v->name) < 0); - } - } - - nm_assert ( !sorted - || nm_utils_named_value_list_is_sorted (arr, len, FALSE, NULL, NULL)); + { + for (i = 0; i < len; i++) { + const NMUtilsNamedValue *v = &arr[i]; + + nm_assert(v->name); + if (sorted && i > 0) + nm_assert(strcmp(arr[i - 1].name, v->name) < 0); + } + } + + nm_assert(!sorted || nm_utils_named_value_list_is_sorted(arr, len, FALSE, NULL, NULL)); #endif - if (sorted) { - return nm_utils_array_find_binary_search (arr, - sizeof (NMUtilsNamedValue), - len, - &name, - nm_strcmp_p_with_data, - NULL); - } - for (i = 0; i < len; i++) { - if (nm_streq (arr[i].name, name)) - return i; - } - return ~((gssize) len); + if (sorted) { + return nm_utils_array_find_binary_search(arr, + sizeof(NMUtilsNamedValue), + len, + &name, + nm_strcmp_p_with_data, + NULL); + } + for (i = 0; i < len; i++) { + if (nm_streq(arr[i].name, name)) + return i; + } + return ~((gssize) len); } gboolean -nm_utils_named_value_list_is_sorted (const NMUtilsNamedValue *arr, - gsize len, - gboolean accept_duplicates, - GCompareDataFunc compare_func, - gpointer user_data) +nm_utils_named_value_list_is_sorted(const NMUtilsNamedValue *arr, + gsize len, + gboolean accept_duplicates, + GCompareDataFunc compare_func, + gpointer user_data) { - gsize i; - int c_limit; + gsize i; + int c_limit; - if (len == 0) - return TRUE; + if (len == 0) + return TRUE; - g_return_val_if_fail (arr, FALSE); + g_return_val_if_fail(arr, FALSE); - if (!compare_func) - compare_func = nm_strcmp_p_with_data; + if (!compare_func) + compare_func = nm_strcmp_p_with_data; - c_limit = accept_duplicates ? 0 : -1; + c_limit = accept_duplicates ? 0 : -1; - for (i = 1; i < len; i++) { - int c; + for (i = 1; i < len; i++) { + int c; - c = compare_func (&arr[i - 1], &arr[i], user_data); - if (c > c_limit) - return FALSE; - } - return TRUE; + c = compare_func(&arr[i - 1], &arr[i], user_data); + if (c > c_limit) + return FALSE; + } + return TRUE; } void -nm_utils_named_value_list_sort (NMUtilsNamedValue *arr, - gsize len, - GCompareDataFunc compare_func, - gpointer user_data) +nm_utils_named_value_list_sort(NMUtilsNamedValue *arr, + gsize len, + GCompareDataFunc compare_func, + gpointer user_data) { - if (len == 0) - return; + if (len == 0) + return; - g_return_if_fail (arr); + g_return_if_fail(arr); - if (len == 1) - return; + if (len == 1) + return; - g_qsort_with_data (arr, - len, - sizeof (NMUtilsNamedValue), - compare_func ?: nm_strcmp_p_with_data, - user_data); + g_qsort_with_data(arr, + len, + sizeof(NMUtilsNamedValue), + compare_func ?: nm_strcmp_p_with_data, + user_data); } /*****************************************************************************/ gpointer * -nm_utils_hash_keys_to_array (GHashTable *hash, - GCompareDataFunc compare_func, - gpointer user_data, - guint *out_len) -{ - guint len; - gpointer *keys; - - /* by convention, we never return an empty array. In that - * case, always %NULL. */ - if ( !hash - || g_hash_table_size (hash) == 0) { - NM_SET_OUT (out_len, 0); - return NULL; - } - - keys = g_hash_table_get_keys_as_array (hash, &len); - if ( len > 1 - && compare_func) { - g_qsort_with_data (keys, - len, - sizeof (gpointer), - compare_func, - user_data); - } - NM_SET_OUT (out_len, len); - return keys; +nm_utils_hash_keys_to_array(GHashTable * hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint * out_len) +{ + guint len; + gpointer *keys; + + /* by convention, we never return an empty array. In that + * case, always %NULL. */ + if (!hash || g_hash_table_size(hash) == 0) { + NM_SET_OUT(out_len, 0); + return NULL; + } + + keys = g_hash_table_get_keys_as_array(hash, &len); + if (len > 1 && compare_func) { + g_qsort_with_data(keys, len, sizeof(gpointer), compare_func, user_data); + } + NM_SET_OUT(out_len, len); + return keys; } gpointer * -nm_utils_hash_values_to_array (GHashTable *hash, - GCompareDataFunc compare_func, - gpointer user_data, - guint *out_len) -{ - GHashTableIter iter; - gpointer value; - gpointer *arr; - guint i, len; - - if ( !hash - || (len = g_hash_table_size (hash)) == 0u) { - NM_SET_OUT (out_len, 0); - return NULL; - } - - arr = g_new (gpointer, ((gsize) len) + 1); - i = 0; - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &value)) - arr[i++] = value; - - nm_assert (i == len); - arr[len] = NULL; - - if ( len > 1 - && compare_func) { - g_qsort_with_data (arr, - len, - sizeof (gpointer), - compare_func, - user_data); - } - - NM_SET_OUT (out_len, len); - return arr; +nm_utils_hash_values_to_array(GHashTable * hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint * out_len) +{ + GHashTableIter iter; + gpointer value; + gpointer * arr; + guint i, len; + + if (!hash || (len = g_hash_table_size(hash)) == 0u) { + NM_SET_OUT(out_len, 0); + return NULL; + } + + arr = g_new(gpointer, ((gsize) len) + 1); + i = 0; + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &value)) + arr[i++] = value; + + nm_assert(i == len); + arr[len] = NULL; + + if (len > 1 && compare_func) { + g_qsort_with_data(arr, len, sizeof(gpointer), compare_func, user_data); + } + + NM_SET_OUT(out_len, len); + return arr; +} + +static gboolean +_utils_hashtable_equal(GHashTable * hash_a, + GHashTable * hash_b, + GCompareDataFunc cmp_values, + gpointer user_data) +{ + GHashTableIter h; + gpointer a_key; + gpointer a_val; + gpointer b_val; + + nm_assert(hash_a); + nm_assert(hash_b); + nm_assert(hash_a != hash_b); + nm_assert(g_hash_table_size(hash_a) == g_hash_table_size(hash_b)); + + /* We rely on both hashes to have the same hash/equal function. Otherwise, we would have to iterate + * both hashes and check whether all keys/values are present in the respective other hash (which + * would be O(n^2), since we couldn't use the plain lookup function. That is not a useful thing + * for this function. */ + + g_hash_table_iter_init(&h, hash_a); + while (g_hash_table_iter_next(&h, &a_key, &a_val)) { + if (!g_hash_table_lookup_extended(hash_b, a_key, NULL, &b_val)) + return FALSE; + + if (!cmp_values) { + /* we accept %NULL compare function to indicate that we don't care about the key. */ + continue; + } + + if (cmp_values(a_val, b_val, user_data) != 0) + return FALSE; + } + + return TRUE; } +/** + * nm_utils_hashtable_equal: + * @a: (allow-none): the hash table or %NULL + * @b: (allow-none): the other hash table or %NULL + * @cmp_values: (allow-none): if %NULL, only the keys + * will be compared. Otherwise, this function is used to + * check whether all keys are equal. + * @user_data: the argument for @cmp_values. + * + * It is required that both @a and @b have the same hash and equals + * function. + * + * Returns: %TRUE, if both keys have the same keys and (if + * @cmp_values is given) all values are the same. + */ gboolean -nm_utils_hashtable_same_keys (const GHashTable *a, - const GHashTable *b) +nm_utils_hashtable_equal(const GHashTable *a, + const GHashTable *b, + GCompareDataFunc cmp_values, + gpointer user_data) { - GHashTableIter h; - const char *k; + GHashTable *hash_a = (GHashTable *) a; + GHashTable *hash_b = (GHashTable *) b; + gboolean same; + guint size; + + if (hash_a == hash_b) + return TRUE; - if (a == b) - return TRUE; - if (!a || !b) - return FALSE; - if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b)) - return FALSE; + if (!hash_a || !hash_b) + return FALSE; - g_hash_table_iter_init (&h, (GHashTable *) a); - while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) { - if (!g_hash_table_contains ((GHashTable *) b, k)) - return FALSE; - } + size = g_hash_table_size(hash_a); + if (size != g_hash_table_size(hash_b)) + return FALSE; + + if (size == 0) + return TRUE; + + same = _utils_hashtable_equal(hash_a, hash_b, cmp_values, user_data); #if NM_MORE_ASSERTS > 5 - g_hash_table_iter_init (&h, (GHashTable *) b); - while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) - nm_assert (g_hash_table_contains ((GHashTable *) a, k)); + nm_assert(same == _utils_hashtable_equal(hash_b, hash_a, cmp_values, user_data)); #endif - return TRUE; + return same; +} + +typedef struct { + gpointer key; + gpointer val; +} HashTableCmpData; + +typedef struct { + GCompareDataFunc cmp_keys; + gpointer user_data; +} HashTableUserData; + +static int +_hashtable_cmp_func(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const HashTableUserData *d = user_data; + const HashTableCmpData * d_a = *((const HashTableCmpData *const *) a); + const HashTableCmpData * d_b = *((const HashTableCmpData *const *) b); + + NM_CMP_RETURN(d->cmp_keys(d_a, d_b, d->user_data)); + return 0; +} + +/** + * nm_utils_hashtable_cmp: + * @a: (allow-none): the hash to compare. May be %NULL. + * @b: (allow-none): the other hash to compare. May be %NULL. + * @do_fast_precheck: if %TRUE, assume that the hashes are equal + * and that it is worth calling nm_utils_hashtable_equal() first. + * That requires, that both hashes have the same equals function + * which is compatible with the @cmp_keys function. + * @cmp_keys: the compare function for keys. Usually, the hash/equal function + * of both hashes corresponds to this function. If you set @do_fast_precheck + * to false, then this is not a requirement. + * @cmp_values: (allow-none): if %NULL, only the keys are compared. + * Otherwise, the values must are also compared with this function. + * + * Both hashes must have keys/values of the same domain, so that + * they can be effectively compared with @cmp_keys and @cmp_values. + * + * %NULL hashes compare equal to %NULL, but not to empty hashes. + * + * Returns: 0 if both hashes are equal, or -1 or 1 if one of the hashes + * sorts before/after. + */ +int +nm_utils_hashtable_cmp(const GHashTable *a, + const GHashTable *b, + gboolean do_fast_precheck, + GCompareDataFunc cmp_keys, + GCompareDataFunc cmp_values, + gpointer user_data) +{ + GHashTable *hash_a = (GHashTable *) a; + GHashTable *hash_b = (GHashTable *) b; + gs_free HashTableCmpData *cmp_array_free = NULL; + HashTableCmpData * cmp_array_a; + HashTableCmpData * cmp_array_b; + GHashTableIter h; + gpointer i_key; + gpointer i_val; + gsize size2; + guint size; + guint i; + + nm_assert(cmp_keys); + + NM_CMP_SELF(hash_a, hash_b); + + size = g_hash_table_size(hash_a); + + NM_CMP_DIRECT(size, g_hash_table_size(hash_b)); + + if (size == 0) + return 0; + + if (do_fast_precheck) { + gboolean same; + + /* we expect that the hashes are equal and the caller ensures us that they + * use the same hash/equal functions. Do a fast path check first... + * + * It's unclear whether this is worth it. The full comparison is O(n*ln(n)), + * while the fast check (using the hash lookup) is O(n). But then, the pre-check + * makes additional requirements on the hash's hash/equal functions -- the + * full comparison does not make such requirements. */ + same = _utils_hashtable_equal(hash_a, hash_b, cmp_values, user_data); +#if NM_MORE_ASSERTS > 5 + nm_assert(same == _utils_hashtable_equal(hash_b, hash_a, cmp_values, user_data)); +#endif + if (same) + return 0; + } + + size2 = ((gsize) size) * 2u; + if (size2 > 600u / sizeof(HashTableCmpData)) { + cmp_array_free = g_new(HashTableCmpData, size2); + cmp_array_a = cmp_array_free; + } else + cmp_array_a = g_newa(HashTableCmpData, size2); + cmp_array_b = &cmp_array_a[size]; + + i = 0; + g_hash_table_iter_init(&h, hash_a); + while (g_hash_table_iter_next(&h, &i_key, &i_val)) { + nm_assert(i < size); + cmp_array_a[i++] = (HashTableCmpData){ + .key = i_key, + .val = i_val, + }; + } + nm_assert(i == size); + + i = 0; + g_hash_table_iter_init(&h, hash_b); + while (g_hash_table_iter_next(&h, &i_key, &i_val)) { + nm_assert(i < size); + cmp_array_b[i++] = (HashTableCmpData){ + .key = i_key, + .val = i_val, + }; + } + nm_assert(i == size); + + g_qsort_with_data(cmp_array_a, + size, + sizeof(HashTableCmpData), + _hashtable_cmp_func, + &((HashTableUserData){ + .cmp_keys = cmp_keys, + .user_data = user_data, + })); + + g_qsort_with_data(cmp_array_b, + size, + sizeof(HashTableCmpData), + _hashtable_cmp_func, + &((HashTableUserData){ + .cmp_keys = cmp_keys, + .user_data = user_data, + })); + + for (i = 0; i < size; i++) { + NM_CMP_RETURN(cmp_keys(cmp_array_a[i].key, cmp_array_b[i].key, user_data)); + } + + if (cmp_values) { + for (i = 0; i < size; i++) { + NM_CMP_RETURN(cmp_values(cmp_array_a[i].val, cmp_array_b[i].val, user_data)); + } + } + + /* the fast-precheck should have already told that the arrays are equal. */ + nm_assert(!do_fast_precheck); + + return 0; } char ** -nm_utils_strv_make_deep_copied (const char **strv) +nm_utils_strv_make_deep_copied(const char **strv) { - gsize i; + gsize i; - /* it takes a strv list, and copies each - * strings. Note that this updates @strv *in-place* - * and returns it. */ + /* it takes a strv list, and copies each + * strings. Note that this updates @strv *in-place* + * and returns it. */ - if (!strv) - return NULL; - for (i = 0; strv[i]; i++) - strv[i] = g_strdup (strv[i]); + if (!strv) + return NULL; + for (i = 0; strv[i]; i++) + strv[i] = g_strdup(strv[i]); - return (char **) strv; + return (char **) strv; } char ** -nm_utils_strv_make_deep_copied_n (const char **strv, gsize len) +nm_utils_strv_make_deep_copied_n(const char **strv, gsize len) { - gsize i; + gsize i; - /* it takes a strv array with len elements, and copies each - * strings. Note that this updates @strv *in-place* - * and returns it. */ + /* it takes a strv array with len elements, and copies each + * strings. Note that this updates @strv *in-place* + * and returns it. */ - if (!strv) - return NULL; - for (i = 0; i < len; i++) - strv[i] = g_strdup (strv[i]); + if (!strv) + return NULL; + for (i = 0; i < len; i++) + strv[i] = g_strdup(strv[i]); - return (char **) strv; + return (char **) strv; } /** @@ -3324,7 +3557,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 @@ -3332,124 +3565,198 @@ nm_utils_strv_make_deep_copied_n (const char **strv, gsize len) * cloned or not. */ char ** -nm_utils_strv_dup (gpointer strv, - gssize len, - gboolean deep_copied) -{ - gsize i, l; - char **v; - const char *const *const src = strv; - - if (len < 0) - l = NM_PTRARRAY_LEN (src); - else - l = len; - if (l == 0) { - /* this function never returns an empty strv array. If you - * need that, handle it yourself. */ - return NULL; - } - - v = g_new (char *, l + 1); - for (i = 0; i < l; i++) { - - if (G_UNLIKELY (!src[i])) { - /* NULL strings are not allowed. Clear the remainder of the array - * and return it (with assertion failure). */ - l++; - for (; i < l; i++) - v[i] = NULL; - g_return_val_if_reached (v); - } - - if (deep_copied) - v[i] = g_strdup (src[i]); - else - v[i] = (char *) src[i]; - } - v[l] = NULL; - return v; +_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied) +{ + gsize i, l; + char **v; + + if (len < 0) + l = NM_PTRARRAY_LEN(strv); + else + l = len; + if (l == 0) { + /* this function never returns an empty strv array. If you + * need that, handle it yourself. */ + return NULL; + } + + v = g_new(char *, l + 1); + for (i = 0; i < l; i++) { + if (G_UNLIKELY(!strv[i])) { + /* NULL strings are not allowed. Clear the remainder of the array + * and return it (with assertion failure). */ + l++; + for (; i < l; i++) + v[i] = NULL; + g_return_val_if_reached(v); + } + + if (deep_copied) + v[i] = g_strdup(strv[i]); + else + v[i] = (char *) strv[i]; + } + v[l] = NULL; + return v; +} + +const char ** +_nm_utils_strv_dup_packed(const char *const *strv, gssize len) + +{ + gs_free gsize *str_len_free = NULL; + gsize * str_len; + const char ** result; + gsize mem_len; + gsize pre_len; + gsize len2; + char * sbuf; + gsize i; + + nm_assert(len >= -1); + + if (G_LIKELY(len < 0)) { + if (!strv || !strv[0]) { + /* This function never returns an empty strv array. If you need that, handle it + * yourself. */ + return NULL; + } + len2 = NM_PTRARRAY_LEN(strv); + } else { + if (len == 0) + return NULL; + len2 = len; + } + + if (len2 > 300u / sizeof(gsize)) { + str_len_free = g_new(gsize, len2); + str_len = str_len_free; + } else + str_len = g_newa(gsize, len2); + + mem_len = 0; + for (i = 0; i < len2; i++) { + gsize l; + + if (G_LIKELY(strv[i])) + l = strlen(strv[i]) + 1u; + else + l = 0; + str_len[i] = l; + mem_len += l; + } + + pre_len = sizeof(const char *) * (len2 + 1u); + + result = g_malloc(pre_len + mem_len); + sbuf = &(((char *) result)[pre_len]); + for (i = 0; i < len2; i++) { + gsize l; + + if (G_UNLIKELY(!strv[i])) { + /* Technically there is no problem with accepting NULL strings. But that + * does not really result in a strv array, and likely this only happens due + * to a bug. We want to catch such bugs by asserting. + * + * We clear the remainder of the buffer and fail with an assertion. */ + len2++; + for (; i < len2; i++) + result[i] = NULL; + g_return_val_if_reached(result); + } + + result[i] = sbuf; + + l = str_len[i]; + memcpy(sbuf, strv[i], l); + sbuf += l; + } + result[i] = NULL; + nm_assert(i == len2); + nm_assert(sbuf == (&((const char *) result)[pre_len]) + mem_len); + + return result; } /*****************************************************************************/ gssize -nm_utils_ptrarray_find_binary_search (gconstpointer *list, - gsize len, - gconstpointer needle, - GCompareDataFunc cmpfcn, - gpointer user_data, - gssize *out_idx_first, - gssize *out_idx_last) -{ - gssize imin, imax, imid, i2min, i2max, i2mid; - int cmp; - - g_return_val_if_fail (list || !len, ~((gssize) 0)); - g_return_val_if_fail (cmpfcn, ~((gssize) 0)); - - imin = 0; - if (len > 0) { - imax = len - 1; - - while (imin <= imax) { - imid = imin + (imax - imin) / 2; - - cmp = cmpfcn (list[imid], needle, user_data); - if (cmp == 0) { - /* we found a matching entry at index imid. - * - * Does the caller request the first/last index as well (in case that - * there are multiple entries which compare equal). */ - - if (out_idx_first) { - i2min = imin; - i2max = imid + 1; - while (i2min <= i2max) { - i2mid = i2min + (i2max - i2min) / 2; - - cmp = cmpfcn (list[i2mid], needle, user_data); - if (cmp == 0) - i2max = i2mid -1; - else { - nm_assert (cmp < 0); - i2min = i2mid + 1; - } - } - *out_idx_first = i2min; - } - if (out_idx_last) { - i2min = imid + 1; - i2max = imax; - while (i2min <= i2max) { - i2mid = i2min + (i2max - i2min) / 2; - - cmp = cmpfcn (list[i2mid], needle, user_data); - if (cmp == 0) - i2min = i2mid + 1; - else { - nm_assert (cmp > 0); - i2max = i2mid - 1; - } - } - *out_idx_last = i2min - 1; - } - return imid; - } - - if (cmp < 0) - imin = imid + 1; - else - imax = imid - 1; - } - } - - /* return the inverse of @imin. This is a negative number, but - * also is ~imin the position where the value should be inserted. */ - imin = ~imin; - NM_SET_OUT (out_idx_first, imin); - NM_SET_OUT (out_idx_last, imin); - return imin; +nm_utils_ptrarray_find_binary_search(gconstpointer * list, + gsize len, + gconstpointer needle, + GCompareDataFunc cmpfcn, + gpointer user_data, + gssize * out_idx_first, + gssize * out_idx_last) +{ + gssize imin, imax, imid, i2min, i2max, i2mid; + int cmp; + + g_return_val_if_fail(list || !len, ~((gssize) 0)); + g_return_val_if_fail(cmpfcn, ~((gssize) 0)); + + imin = 0; + if (len > 0) { + imax = len - 1; + + while (imin <= imax) { + imid = imin + (imax - imin) / 2; + + cmp = cmpfcn(list[imid], needle, user_data); + if (cmp == 0) { + /* we found a matching entry at index imid. + * + * Does the caller request the first/last index as well (in case that + * there are multiple entries which compare equal). */ + + if (out_idx_first) { + i2min = imin; + i2max = imid + 1; + while (i2min <= i2max) { + i2mid = i2min + (i2max - i2min) / 2; + + cmp = cmpfcn(list[i2mid], needle, user_data); + if (cmp == 0) + i2max = i2mid - 1; + else { + nm_assert(cmp < 0); + i2min = i2mid + 1; + } + } + *out_idx_first = i2min; + } + if (out_idx_last) { + i2min = imid + 1; + i2max = imax; + while (i2min <= i2max) { + i2mid = i2min + (i2max - i2min) / 2; + + cmp = cmpfcn(list[i2mid], needle, user_data); + if (cmp == 0) + i2min = i2mid + 1; + else { + nm_assert(cmp > 0); + i2max = i2mid - 1; + } + } + *out_idx_last = i2min - 1; + } + return imid; + } + + if (cmp < 0) + imin = imid + 1; + else + imax = imid - 1; + } + } + + /* return the inverse of @imin. This is a negative number, but + * also is ~imin the position where the value should be inserted. */ + imin = ~imin; + NM_SET_OUT(out_idx_first, imin); + NM_SET_OUT(out_idx_last, imin); + return imin; } /*****************************************************************************/ @@ -3479,42 +3786,42 @@ nm_utils_ptrarray_find_binary_search (gconstpointer *list, * position where it should be. */ gssize -nm_utils_array_find_binary_search (gconstpointer list, - gsize elem_size, - gsize len, - gconstpointer needle, - GCompareDataFunc cmpfcn, - gpointer user_data) +nm_utils_array_find_binary_search(gconstpointer list, + gsize elem_size, + gsize len, + gconstpointer needle, + GCompareDataFunc cmpfcn, + gpointer user_data) { - gssize imin, imax, imid; - int cmp; + gssize imin, imax, imid; + int cmp; - g_return_val_if_fail (list || !len, ~((gssize) 0)); - g_return_val_if_fail (cmpfcn, ~((gssize) 0)); - g_return_val_if_fail (elem_size > 0, ~((gssize) 0)); + g_return_val_if_fail(list || !len, ~((gssize) 0)); + g_return_val_if_fail(cmpfcn, ~((gssize) 0)); + g_return_val_if_fail(elem_size > 0, ~((gssize) 0)); - imin = 0; - if (len == 0) - return ~imin; + imin = 0; + if (len == 0) + return ~imin; - imax = len - 1; + imax = len - 1; - while (imin <= imax) { - imid = imin + (imax - imin) / 2; + while (imin <= imax) { + imid = imin + (imax - imin) / 2; - cmp = cmpfcn (&((const char *) list)[elem_size * imid], needle, user_data); - if (cmp == 0) - return imid; + cmp = cmpfcn(&((const char *) list)[elem_size * imid], needle, user_data); + if (cmp == 0) + return imid; - if (cmp < 0) - imin = imid + 1; - else - imax = imid - 1; - } + if (cmp < 0) + imin = imid + 1; + else + imax = imid - 1; + } - /* return the inverse of @imin. This is a negative number, but - * also is ~imin the position where the value should be inserted. */ - return ~imin; + /* return the inverse of @imin. This is a negative number, but + * also is ~imin the position where the value should be inserted. */ + return ~imin; } /*****************************************************************************/ @@ -3540,38 +3847,37 @@ nm_utils_array_find_binary_search (gconstpointer list, * Returns: %TRUE, if both dictionaries have the same content. */ gboolean -nm_utils_hash_table_equal (const GHashTable *a, - const GHashTable *b, - gboolean treat_null_as_empty, - NMUtilsHashTableEqualFunc equal_func) -{ - guint n; - GHashTableIter iter; - gconstpointer key, v_a, v_b; - - if (a == b) - return TRUE; - if (!treat_null_as_empty) { - if (!a || !b) - return FALSE; - } - - n = a ? g_hash_table_size ((GHashTable *) a) : 0; - if (n != (b ? g_hash_table_size ((GHashTable *) b) : 0)) - return FALSE; - - if (n > 0) { - g_hash_table_iter_init (&iter, (GHashTable *) a); - while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &v_a)) { - if (!g_hash_table_lookup_extended ((GHashTable *) b, key, NULL, (gpointer *) &v_b)) - return FALSE; - if ( equal_func - && !equal_func (v_a, v_b)) - return FALSE; - } - } - - return TRUE; +nm_utils_hash_table_equal(const GHashTable * a, + const GHashTable * b, + gboolean treat_null_as_empty, + NMUtilsHashTableEqualFunc equal_func) +{ + guint n; + GHashTableIter iter; + gconstpointer key, v_a, v_b; + + if (a == b) + return TRUE; + if (!treat_null_as_empty) { + if (!a || !b) + return FALSE; + } + + n = a ? g_hash_table_size((GHashTable *) a) : 0; + if (n != (b ? g_hash_table_size((GHashTable *) b) : 0)) + return FALSE; + + if (n > 0) { + g_hash_table_iter_init(&iter, (GHashTable *) a); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &v_a)) { + if (!g_hash_table_lookup_extended((GHashTable *) b, key, NULL, (gpointer *) &v_b)) + return FALSE; + if (equal_func && !equal_func(v_a, v_b)) + return FALSE; + } + } + + return TRUE; } /*****************************************************************************/ @@ -3591,65 +3897,65 @@ nm_utils_hash_table_equal (const GHashTable *a, * The returned start time counts since boot, in the unit HZ (with HZ usually being (1/100) seconds) **/ guint64 -nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid) +nm_utils_get_start_time_for_pid(pid_t pid, char *out_state, pid_t *out_ppid) { - guint64 start_time; - char filename[256]; - gs_free char *contents = NULL; - size_t length; - gs_free const char **tokens = NULL; - char *p; - char state = ' '; - gint64 ppid = 0; + guint64 start_time; + char filename[256]; + gs_free char * contents = NULL; + size_t length; + gs_free const char **tokens = NULL; + char * p; + char state = ' '; + gint64 ppid = 0; - start_time = 0; - contents = NULL; + start_time = 0; + contents = NULL; - g_return_val_if_fail (pid > 0, 0); + g_return_val_if_fail(pid > 0, 0); - G_STATIC_ASSERT_EXPR (sizeof (GPid) >= sizeof (pid_t)); + G_STATIC_ASSERT_EXPR(sizeof(GPid) >= sizeof(pid_t)); - nm_sprintf_buf (filename, "/proc/%"G_PID_FORMAT"/stat", (GPid) pid); + nm_sprintf_buf(filename, "/proc/%" G_PID_FORMAT "/stat", (GPid) pid); - if (!g_file_get_contents (filename, &contents, &length, NULL)) - goto fail; + if (!g_file_get_contents(filename, &contents, &length, NULL)) + goto fail; - /* start time is the token at index 19 after the '(process name)' entry - since only this - * field can contain the ')' character, search backwards for this to avoid malicious - * processes trying to fool us - */ - p = strrchr (contents, ')'); - if (!p) - goto fail; - p += 2; /* skip ') ' */ - if (p - contents >= (int) length) - goto fail; + /* start time is the token at index 19 after the '(process name)' entry - since only this + * field can contain the ')' character, search backwards for this to avoid malicious + * processes trying to fool us + */ + p = strrchr(contents, ')'); + if (!p) + goto fail; + p += 2; /* skip ') ' */ + if (p - contents >= (int) length) + goto fail; - state = p[0]; + state = p[0]; - tokens = nm_utils_strsplit_set (p, " "); + tokens = nm_utils_strsplit_set(p, " "); - if (NM_PTRARRAY_LEN (tokens) < 20) - goto fail; + if (NM_PTRARRAY_LEN(tokens) < 20) + goto fail; - if (out_ppid) { - ppid = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 1, G_MAXINT, 0); - if (ppid == 0) - goto fail; - } + if (out_ppid) { + ppid = _nm_utils_ascii_str_to_int64(tokens[1], 10, 1, G_MAXINT, 0); + if (ppid == 0) + goto fail; + } - start_time = _nm_utils_ascii_str_to_int64 (tokens[19], 10, 1, G_MAXINT64, 0); - if (start_time == 0) - goto fail; + start_time = _nm_utils_ascii_str_to_int64(tokens[19], 10, 1, G_MAXINT64, 0); + if (start_time == 0) + goto fail; - NM_SET_OUT (out_state, state); - NM_SET_OUT (out_ppid, ppid); - return start_time; + NM_SET_OUT(out_state, state); + NM_SET_OUT(out_ppid, ppid); + return start_time; fail: - NM_SET_OUT (out_state, ' '); - NM_SET_OUT (out_ppid, 0); - return 0; + NM_SET_OUT(out_state, ' '); + NM_SET_OUT(out_ppid, 0); + return 0; } /*****************************************************************************/ @@ -3669,29 +3975,25 @@ fail: * comparison. */ void -_nm_utils_strv_sort (const char **strv, gssize len) +_nm_utils_strv_sort(const char **strv, gssize len) { - GCompareDataFunc cmp; - gsize l; + GCompareDataFunc cmp; + gsize l; - if (len < 0) { - l = NM_PTRARRAY_LEN (strv); - cmp = nm_strcmp_p_with_data; - } else { - l = len; - cmp = nm_strcmp0_p_with_data; - } + if (len < 0) { + l = NM_PTRARRAY_LEN(strv); + cmp = nm_strcmp_p_with_data; + } else { + l = len; + cmp = nm_strcmp0_p_with_data; + } - if (l <= 1) - return; + if (l <= 1) + return; - nm_assert (l <= (gsize) G_MAXINT); + nm_assert(l <= (gsize) G_MAXINT); - g_qsort_with_data (strv, - l, - sizeof (const char *), - cmp, - NULL); + g_qsort_with_data(strv, l, sizeof(const char *), cmp, NULL); } /** @@ -3718,31 +4020,28 @@ _nm_utils_strv_sort (const char **strv, gssize len) * Returns: 0 if the arrays are equal (using strcmp). **/ int -_nm_utils_strv_cmp_n (const char *const*strv1, - gssize len1, - const char *const*strv2, - gssize len2) +_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2) { - gsize n, n2; + gsize n, n2; - if (len1 < 0) { - if (!strv1) - return (len2 < 0 && !strv2) ? 0 : -1; - n = NM_PTRARRAY_LEN (strv1); - } else - n = len1; + if (len1 < 0) { + if (!strv1) + return (len2 < 0 && !strv2) ? 0 : -1; + n = NM_PTRARRAY_LEN(strv1); + } else + n = len1; - if (len2 < 0) { - if (!strv2) - return 1; - n2 = NM_PTRARRAY_LEN (strv2); - } else - n2 = len2; + if (len2 < 0) { + if (!strv2) + return 1; + n2 = NM_PTRARRAY_LEN(strv2); + } else + n2 = len2; - NM_CMP_DIRECT (n, n2); - for (; n > 0; n--, strv1++, strv2++) - NM_CMP_DIRECT_STRCMP0 (*strv1, *strv2); - return 0; + NM_CMP_DIRECT(n, n2); + for (; n > 0; n--, strv1++, strv2++) + NM_CMP_DIRECT_STRCMP0(*strv1, *strv2); + return 0; } /*****************************************************************************/ @@ -3760,17 +4059,16 @@ _nm_utils_strv_cmp_n (const char *const*strv1, * %NULL if not found. */ GSList * -nm_utils_g_slist_find_str (const GSList *list, - const char *needle) +nm_utils_g_slist_find_str(const GSList *list, const char *needle) { - nm_assert (needle); + nm_assert(needle); - for (; list; list = list->next) { - nm_assert (list->data); - if (nm_streq (list->data, needle)) - return (GSList *) list; - } - return NULL; + for (; list; list = list->next) { + nm_assert(list->data); + if (nm_streq(list->data, needle)) + return (GSList *) list; + } + return NULL; } /** @@ -3779,250 +4077,246 @@ 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. */ int -nm_utils_g_slist_strlist_cmp (const GSList *a, const GSList *b) +nm_utils_g_slist_strlist_cmp(const GSList *a, const GSList *b) { - while (TRUE) { - if (!a) - return !b ? 0 : -1; - if (!b) - return 1; - NM_CMP_DIRECT_STRCMP0 (a->data, b->data); - a = a->next; - b = b->next; - } + while (TRUE) { + if (!a) + return !b ? 0 : -1; + if (!b) + return 1; + NM_CMP_DIRECT_STRCMP0(a->data, b->data); + a = a->next; + b = b->next; + } } char * -nm_utils_g_slist_strlist_join (const GSList *a, const char *separator) +nm_utils_g_slist_strlist_join(const GSList *a, const char *separator) { - GString *str = NULL; + GString *str = NULL; - if (!a) - return NULL; + if (!a) + return NULL; - for (; a; a = a->next) { - if (!str) - str = g_string_new (NULL); - else - g_string_append (str, separator); - g_string_append (str, a->data); - } - return g_string_free (str, FALSE); + for (; a; a = a->next) { + if (!str) + str = g_string_new(NULL); + else + g_string_append(str, separator); + g_string_append(str, a->data); + } + return g_string_free(str, FALSE); } /*****************************************************************************/ gpointer -_nm_utils_user_data_pack (int nargs, gconstpointer *args) +_nm_utils_user_data_pack(int nargs, gconstpointer *args) { - int i; - gpointer *data; + int i; + gpointer *data; - nm_assert (nargs > 0); - nm_assert (args); + nm_assert(nargs > 0); + nm_assert(args); - data = g_slice_alloc (((gsize) nargs) * sizeof (gconstpointer)); - for (i = 0; i < nargs; i++) - data[i] = (gpointer) args[i]; - return data; + data = g_slice_alloc(((gsize) nargs) * sizeof(gconstpointer)); + for (i = 0; i < nargs; i++) + data[i] = (gpointer) args[i]; + return data; } void -_nm_utils_user_data_unpack (gpointer user_data, int nargs, ...) +_nm_utils_user_data_unpack(gpointer user_data, int nargs, ...) { - gpointer *data = user_data; - va_list ap; - int i; + gpointer *data = user_data; + va_list ap; + int i; - nm_assert (data); - nm_assert (nargs > 0); + nm_assert(data); + nm_assert(nargs > 0); - va_start (ap, nargs); - for (i = 0; i < nargs; i++) { - gpointer *dst; + va_start(ap, nargs); + for (i = 0; i < nargs; i++) { + gpointer *dst; - dst = va_arg (ap, gpointer *); - nm_assert (dst); + dst = va_arg(ap, gpointer *); + nm_assert(dst); - *dst = data[i]; - } - va_end (ap); + *dst = data[i]; + } + va_end(ap); - g_slice_free1 (((gsize) nargs) * sizeof (gconstpointer), data); + g_slice_free1(((gsize) nargs) * sizeof(gconstpointer), data); } /*****************************************************************************/ typedef struct { - gpointer callback_user_data; - GCancellable *cancellable; - GSource *source; - NMUtilsInvokeOnIdleCallback callback; - gulong cancelled_id; + gpointer callback_user_data; + GCancellable * cancellable; + GSource * source; + NMUtilsInvokeOnIdleCallback callback; + gulong cancelled_id; } InvokeOnIdleData; static gboolean -_nm_utils_invoke_on_idle_cb_idle (gpointer user_data) +_nm_utils_invoke_on_idle_cb_idle(gpointer user_data) { - InvokeOnIdleData *data = user_data; + InvokeOnIdleData *data = user_data; - nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id); + nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id); - data->callback (data->callback_user_data, data->cancellable); + data->callback(data->callback_user_data, data->cancellable); - nm_g_object_unref (data->cancellable); - g_source_destroy (data->source); - nm_g_slice_free (data); - return G_SOURCE_REMOVE; + nm_g_object_unref(data->cancellable); + g_source_destroy(data->source); + nm_g_slice_free(data); + return G_SOURCE_REMOVE; } static void -_nm_utils_invoke_on_idle_cb_cancelled (GCancellable *cancellable, - InvokeOnIdleData *data) +_nm_utils_invoke_on_idle_cb_cancelled(GCancellable *cancellable, InvokeOnIdleData *data) { - /* on cancellation, we invoke the callback synchronously. */ - nm_clear_g_signal_handler (data->cancellable, &data->cancelled_id); - nm_clear_g_source_inst (&data->source); - data->callback (data->callback_user_data, data->cancellable); - nm_g_object_unref (data->cancellable); - nm_g_slice_free (data); + /* on cancellation, we invoke the callback synchronously. */ + nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id); + nm_clear_g_source_inst(&data->source); + data->callback(data->callback_user_data, data->cancellable); + nm_g_object_unref(data->cancellable); + nm_g_slice_free(data); } static void -_nm_utils_invoke_on_idle_start (gboolean use_timeout, - guint timeout_msec, - GCancellable *cancellable, - NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data) -{ - InvokeOnIdleData *data; - GSource *source; - - g_return_if_fail (callback); - - data = g_slice_new (InvokeOnIdleData); - *data = (InvokeOnIdleData) { - .callback = callback, - .callback_user_data = callback_user_data, - .cancellable = nm_g_object_ref (cancellable), - .cancelled_id = 0, - }; - - if (cancellable) { - if (g_cancellable_is_cancelled (cancellable)) { - /* the cancellable is already cancelled. We ignore the timeout - * and always schedule an idle action. */ - use_timeout = FALSE; - } else { - /* if we are passed a non-cancelled cancellable, we register to the "cancelled" - * signal an invoke the callback synchronously (from the signal handler). - * - * We don't do that, - * - if the cancellable is already cancelled (because we don't want to invoke - * the callback synchronously from the caller). - * - if we have no cancellable at hand. */ - data->cancelled_id = g_signal_connect (cancellable, - "cancelled", - G_CALLBACK (_nm_utils_invoke_on_idle_cb_cancelled), - data); - } - } - - if (use_timeout) { - source = nm_g_timeout_source_new (timeout_msec, - G_PRIORITY_DEFAULT, - _nm_utils_invoke_on_idle_cb_idle, - data, - NULL); - } else { - source = nm_g_idle_source_new (G_PRIORITY_DEFAULT, - _nm_utils_invoke_on_idle_cb_idle, - data, - NULL); - } - - /* use the current thread default context. */ - g_source_attach (source, - g_main_context_get_thread_default ()); - - data->source = source; +_nm_utils_invoke_on_idle_start(gboolean use_timeout, + guint timeout_msec, + GCancellable * cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data) +{ + InvokeOnIdleData *data; + GSource * source; + + g_return_if_fail(callback); + + data = g_slice_new(InvokeOnIdleData); + *data = (InvokeOnIdleData){ + .callback = callback, + .callback_user_data = callback_user_data, + .cancellable = nm_g_object_ref(cancellable), + .cancelled_id = 0, + }; + + if (cancellable) { + if (g_cancellable_is_cancelled(cancellable)) { + /* the cancellable is already cancelled. We ignore the timeout + * and always schedule an idle action. */ + use_timeout = FALSE; + } else { + /* if we are passed a non-cancelled cancellable, we register to the "cancelled" + * signal an invoke the callback synchronously (from the signal handler). + * + * We don't do that, + * - if the cancellable is already cancelled (because we don't want to invoke + * the callback synchronously from the caller). + * - if we have no cancellable at hand. */ + data->cancelled_id = g_signal_connect(cancellable, + "cancelled", + G_CALLBACK(_nm_utils_invoke_on_idle_cb_cancelled), + data); + } + } + + if (use_timeout) { + source = nm_g_timeout_source_new(timeout_msec, + G_PRIORITY_DEFAULT, + _nm_utils_invoke_on_idle_cb_idle, + data, + NULL); + } else { + source = + nm_g_idle_source_new(G_PRIORITY_DEFAULT, _nm_utils_invoke_on_idle_cb_idle, data, NULL); + } + + /* use the current thread default context. */ + g_source_attach(source, g_main_context_get_thread_default()); + + data->source = source; } void -nm_utils_invoke_on_idle (GCancellable *cancellable, - NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data) +nm_utils_invoke_on_idle(GCancellable * cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data) { - _nm_utils_invoke_on_idle_start (FALSE, 0, cancellable, callback, callback_user_data); + _nm_utils_invoke_on_idle_start(FALSE, 0, cancellable, callback, callback_user_data); } void -nm_utils_invoke_on_timeout (guint timeout_msec, - GCancellable *cancellable, - NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data) +nm_utils_invoke_on_timeout(guint timeout_msec, + GCancellable * cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data) { - _nm_utils_invoke_on_idle_start (TRUE, timeout_msec, cancellable, callback, callback_user_data); + _nm_utils_invoke_on_idle_start(TRUE, timeout_msec, cancellable, callback, callback_user_data); } /*****************************************************************************/ int -nm_utils_getpagesize (void) +nm_utils_getpagesize(void) { - static volatile int val = 0; - long l; - int v; + static volatile int val = 0; + long l; + int v; - v = g_atomic_int_get (&val); + v = g_atomic_int_get(&val); - if (G_UNLIKELY (v == 0)) { - l = sysconf (_SC_PAGESIZE); + if (G_UNLIKELY(v == 0)) { + l = sysconf(_SC_PAGESIZE); - g_return_val_if_fail (l > 0 && l < G_MAXINT, 4*1024); + g_return_val_if_fail(l > 0 && l < G_MAXINT, 4 * 1024); - v = (int) l; - if (!g_atomic_int_compare_and_exchange (&val, 0, v)) { - v = g_atomic_int_get (&val); - g_return_val_if_fail (v > 0, 4*1024); - } - } + v = (int) l; + if (!g_atomic_int_compare_and_exchange(&val, 0, v)) { + v = g_atomic_int_get(&val); + g_return_val_if_fail(v > 0, 4 * 1024); + } + } - nm_assert (v > 0); + nm_assert(v > 0); #if NM_MORE_ASSERTS > 5 - nm_assert (v == getpagesize ()); - nm_assert (v == sysconf (_SC_PAGESIZE)); + nm_assert(v == getpagesize()); + nm_assert(v == sysconf(_SC_PAGESIZE)); #endif - return v; + return v; } gboolean -nm_utils_memeqzero (gconstpointer data, gsize length) +nm_utils_memeqzero(gconstpointer data, gsize length) { - const unsigned char *p = data; - int len; + const unsigned char *p = data; + int len; - /* Taken from https://github.com/rustyrussell/ccan/blob/9d2d2c49f053018724bcc6e37029da10b7c3d60d/ccan/mem/mem.c#L92, - * CC-0 licensed. */ + /* Taken from https://github.com/rustyrussell/ccan/blob/9d2d2c49f053018724bcc6e37029da10b7c3d60d/ccan/mem/mem.c#L92, + * CC-0 licensed. */ - /* Check first 16 bytes manually */ - for (len = 0; len < 16; len++) { - if (!length) - return TRUE; - if (*p) - return FALSE; - p++; - length--; - } + /* Check first 16 bytes manually */ + for (len = 0; len < 16; len++) { + if (!length) + return TRUE; + if (*p) + return FALSE; + p++; + length--; + } - /* Now we know that's zero, memcmp with self. */ - return memcmp (data, p, length) == 0; + /* Now we know that's zero, memcmp with self. */ + return memcmp(data, p, length) == 0; } /** @@ -4046,273 +4340,255 @@ 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, - gsize length, - char delimiter, - gboolean upper_case, - char *out) -{ - const guint8 *in = addr; - const char *LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef"; - char *out0; - - if (out) - out0 = out; - else { - out0 = out = g_new (char, length == 0 - ? 1u - : ( delimiter == '\0' - ? length * 2u + 1u - : length * 3u)); - } - - /* @out must contain at least @length*3 bytes if @delimiter is set, - * otherwise, @length*2+1. */ - - if (length > 0) { - nm_assert (in); - for (;;) { - const guint8 v = *in++; - - *out++ = LOOKUP[v >> 4]; - *out++ = LOOKUP[v & 0x0F]; - length--; - if (!length) - break; - if (delimiter) - *out++ = delimiter; - } - } - - *out = '\0'; - return out0; +nm_utils_bin2hexstr_full(gconstpointer addr, + gsize length, + char delimiter, + gboolean upper_case, + char * out) +{ + const guint8 *in = addr; + const char * LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef"; + char * out0; + + if (out) + out0 = out; + else { + out0 = out = + g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u)); + } + + /* @out must contain at least @length*3 bytes if @delimiter is set, + * otherwise, @length*2+1. */ + + if (length > 0) { + nm_assert(in); + for (;;) { + const guint8 v = *in++; + + *out++ = LOOKUP[v >> 4]; + *out++ = LOOKUP[v & 0x0F]; + length--; + if (!length) + break; + if (delimiter) + *out++ = delimiter; + } + } + + *out = '\0'; + return out0; } guint8 * -nm_utils_hexstr2bin_full (const char *hexstr, - gboolean allow_0x_prefix, - gboolean delimiter_required, - const char *delimiter_candidates, - gsize required_len, - guint8 *buffer, - gsize buffer_len, - gsize *out_len) -{ - const char *in = hexstr; - guint8 *out = buffer; - gboolean delimiter_has = TRUE; - guint8 delimiter = '\0'; - gsize len; - - nm_assert (hexstr); - nm_assert (buffer); - nm_assert (required_len > 0 || out_len); - - if ( allow_0x_prefix - && in[0] == '0' - && in[1] == 'x') - in += 2; - - while (TRUE) { - const guint8 d1 = in[0]; - guint8 d2; - int i1, i2; - - i1 = nm_utils_hexchar_to_int (d1); - if (i1 < 0) - goto fail; - - /* If there's no leading zero (ie "aa:b:cc") then fake it */ - d2 = in[1]; - if ( d2 - && (i2 = nm_utils_hexchar_to_int (d2)) >= 0) { - *out++ = (i1 << 4) + i2; - d2 = in[2]; - if (!d2) - break; - in += 2; - } else { - /* Fake leading zero */ - *out++ = i1; - if (!d2) { - if (!delimiter_has) { - /* when using no delimiter, there must be pairs of hex chars */ - goto fail; - } - break; - } - in += 1; - } - - if (--buffer_len == 0) - goto fail; - - if (delimiter_has) { - if (d2 != delimiter) { - if (delimiter) - goto fail; - if (delimiter_candidates) { - while (delimiter_candidates[0]) { - if (delimiter_candidates++[0] == d2) - delimiter = d2; - } - } - if (!delimiter) { - if (delimiter_required) - goto fail; - delimiter_has = FALSE; - continue; - } - } - in++; - } - } - - len = out - buffer; - if ( required_len == 0 - || len == required_len) { - NM_SET_OUT (out_len, len); - return buffer; - } +nm_utils_hexstr2bin_full(const char *hexstr, + gboolean allow_0x_prefix, + gboolean delimiter_required, + gboolean hexdigit_pairs_required, + const char *delimiter_candidates, + gsize required_len, + guint8 * buffer, + gsize buffer_len, + gsize * out_len) +{ + const char *in = hexstr; + guint8 * out = buffer; + gboolean delimiter_has = TRUE; + guint8 delimiter = '\0'; + gsize len; + + nm_assert(hexstr); + nm_assert(buffer); + nm_assert(required_len > 0 || out_len); + + if (allow_0x_prefix && in[0] == '0' && in[1] == 'x') + in += 2; + + while (TRUE) { + const guint8 d1 = in[0]; + guint8 d2; + int i1, i2; + + i1 = nm_utils_hexchar_to_int(d1); + if (i1 < 0) + goto fail; + + /* If there's no leading zero (ie "aa:b:cc") then fake it */ + d2 = in[1]; + if (d2 && (i2 = nm_utils_hexchar_to_int(d2)) >= 0) { + *out++ = (i1 << 4) + i2; + d2 = in[2]; + if (!d2) + break; + in += 2; + } else { + /* Fake leading zero */ + *out++ = i1; + if (!d2) { + if (!delimiter_has || hexdigit_pairs_required) { + /* when using no delimiter, there must be pairs of hex chars */ + goto fail; + } + break; + } else if (hexdigit_pairs_required) + goto fail; + in += 1; + } + + if (--buffer_len == 0) + goto fail; + + if (delimiter_has) { + if (d2 != delimiter) { + if (delimiter) + goto fail; + if (delimiter_candidates) { + while (delimiter_candidates[0]) { + if (delimiter_candidates++[0] == d2) + delimiter = d2; + } + } + if (!delimiter) { + if (delimiter_required) + goto fail; + delimiter_has = FALSE; + continue; + } + } + in++; + } + } + + len = out - buffer; + if (required_len == 0 || len == required_len) { + NM_SET_OUT(out_len, len); + return buffer; + } fail: - NM_SET_OUT (out_len, 0); - return NULL; + NM_SET_OUT(out_len, 0); + return NULL; } guint8 * -nm_utils_hexstr2bin_alloc (const char *hexstr, - gboolean allow_0x_prefix, - gboolean delimiter_required, - const char *delimiter_candidates, - gsize required_len, - gsize *out_len) -{ - guint8 *buffer; - gsize buffer_len, len; - - if (G_UNLIKELY (!hexstr)) { - NM_SET_OUT (out_len, 0); - g_return_val_if_fail (hexstr, NULL); - } - - nm_assert (required_len > 0 || out_len); - - if ( allow_0x_prefix - && hexstr[0] == '0' - && hexstr[1] == 'x') - hexstr += 2; - - if (!hexstr[0]) - goto fail; - - if (required_len > 0) - buffer_len = required_len; - else - buffer_len = strlen (hexstr) / 2 + 3; - - buffer = g_malloc (buffer_len); - - if (nm_utils_hexstr2bin_full (hexstr, - FALSE, - delimiter_required, - delimiter_candidates, - required_len, - buffer, - buffer_len, - &len)) { - NM_SET_OUT (out_len, len); - return buffer; - } - - g_free (buffer); +nm_utils_hexstr2bin_alloc(const char *hexstr, + gboolean allow_0x_prefix, + gboolean delimiter_required, + const char *delimiter_candidates, + gsize required_len, + gsize * out_len) +{ + guint8 *buffer; + gsize buffer_len, len; + + if (G_UNLIKELY(!hexstr)) { + NM_SET_OUT(out_len, 0); + g_return_val_if_fail(hexstr, NULL); + } + + nm_assert(required_len > 0 || out_len); + + if (allow_0x_prefix && hexstr[0] == '0' && hexstr[1] == 'x') + hexstr += 2; + + if (!hexstr[0]) + goto fail; + + if (required_len > 0) + buffer_len = required_len; + else + buffer_len = strlen(hexstr) / 2 + 3; + + buffer = g_malloc(buffer_len); + + if (nm_utils_hexstr2bin_full(hexstr, + FALSE, + delimiter_required, + FALSE, + delimiter_candidates, + required_len, + buffer, + buffer_len, + &len)) { + NM_SET_OUT(out_len, len); + return buffer; + } + + g_free(buffer); fail: - NM_SET_OUT (out_len, 0); - return NULL; + NM_SET_OUT(out_len, 0); + return NULL; } /*****************************************************************************/ GVariant * -nm_utils_gvariant_vardict_filter (GVariant *src, - gboolean (*filter_fcn) (const char *key, - GVariant *val, - char **out_key, - GVariant **out_val, - gpointer user_data), - gpointer user_data) -{ - GVariantIter iter; - GVariantBuilder builder; - const char *key; - GVariant *val; - - g_return_val_if_fail (src && g_variant_is_of_type (src, G_VARIANT_TYPE_VARDICT), NULL); - g_return_val_if_fail (filter_fcn, NULL); - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - - g_variant_iter_init (&iter, src); - while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) { - _nm_unused gs_unref_variant GVariant *val_free = val; - gs_free char *key2 = NULL; - gs_unref_variant GVariant *val2 = NULL; - - if (filter_fcn (key, - val, - &key2, - &val2, - user_data)) { - g_variant_builder_add (&builder, - "{sv}", - key2 ?: key, - val2 ?: val); - } - } - - return g_variant_builder_end (&builder); +nm_utils_gvariant_vardict_filter(GVariant *src, + gboolean (*filter_fcn)(const char *key, + GVariant * val, + char ** out_key, + GVariant ** out_val, + gpointer user_data), + gpointer user_data) +{ + GVariantIter iter; + GVariantBuilder builder; + const char * key; + GVariant * val; + + g_return_val_if_fail(src && g_variant_is_of_type(src, G_VARIANT_TYPE_VARDICT), NULL); + g_return_val_if_fail(filter_fcn, NULL); + + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + + g_variant_iter_init(&iter, src); + while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) { + _nm_unused gs_unref_variant GVariant *val_free = val; + gs_free char * key2 = NULL; + gs_unref_variant GVariant *val2 = NULL; + + if (filter_fcn(key, val, &key2, &val2, user_data)) { + g_variant_builder_add(&builder, "{sv}", key2 ?: key, val2 ?: val); + } + } + + return g_variant_builder_end(&builder); } static gboolean -_gvariant_vardict_filter_drop_one (const char *key, - GVariant *val, - char **out_key, - GVariant **out_val, - gpointer user_data) +_gvariant_vardict_filter_drop_one(const char *key, + GVariant * val, + char ** out_key, + GVariant ** out_val, + gpointer user_data) { - return !nm_streq (key, user_data); + return !nm_streq(key, user_data); } GVariant * -nm_utils_gvariant_vardict_filter_drop_one (GVariant *src, - const char *key) +nm_utils_gvariant_vardict_filter_drop_one(GVariant *src, const char *key) { - return nm_utils_gvariant_vardict_filter (src, - _gvariant_vardict_filter_drop_one, - (gpointer) key); + return nm_utils_gvariant_vardict_filter(src, _gvariant_vardict_filter_drop_one, (gpointer) key); } /*****************************************************************************/ static gboolean -debug_key_matches (const char *key, - const char *token, - guint length) +debug_key_matches(const char *key, const char *token, guint length) { - /* may not call GLib functions: see note in g_parse_debug_string() */ - for (; length; length--, key++, token++) { - char k = (*key == '_') ? '-' : g_ascii_tolower (*key ); - char t = (*token == '_') ? '-' : g_ascii_tolower (*token); + /* may not call GLib functions: see note in g_parse_debug_string() */ + for (; length; length--, key++, token++) { + char k = (*key == '_') ? '-' : g_ascii_tolower(*key); + char t = (*token == '_') ? '-' : g_ascii_tolower(*token); - if (k != t) - return FALSE; - } + if (k != t) + return FALSE; + } - return *key == '\0'; + return *key == '\0'; } /** @@ -4327,415 +4603,436 @@ debug_key_matches (const char *key, * Returns: the flags */ guint -nm_utils_parse_debug_string (const char *string, - const GDebugKey *keys, - guint nkeys) +nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, guint nkeys) { - guint i; - guint result = 0; - const char *q; + guint i; + guint result = 0; + const char *q; - if (string == NULL) - return 0; + if (string == NULL) + return 0; - while (*string) { - q = strpbrk (string, ":;, \t"); - if (!q) - q = string + strlen (string); + while (*string) { + q = strpbrk(string, ":;, \t"); + if (!q) + q = string + strlen(string); - for (i = 0; i < nkeys; i++) { - if (debug_key_matches (keys[i].key, string, q - string)) - result |= keys[i].value; - } + for (i = 0; i < nkeys; i++) { + if (debug_key_matches(keys[i].key, string, q - string)) + result |= keys[i].value; + } - string = q; - if (*string) - string++; - } + string = q; + if (*string) + string++; + } - return result; + return result; } /*****************************************************************************/ GSource * -nm_g_idle_source_new (int priority, - GSourceFunc func, - gpointer user_data, - GDestroyNotify destroy_notify) +nm_g_idle_source_new(int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify) { - GSource *source; + GSource *source; - source = g_idle_source_new (); - if (priority != G_PRIORITY_DEFAULT) - g_source_set_priority (source, priority); - g_source_set_callback (source, func, user_data, destroy_notify); - return source; + source = g_idle_source_new(); + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority(source, priority); + g_source_set_callback(source, func, user_data, destroy_notify); + return source; } GSource * -nm_g_timeout_source_new (guint timeout_msec, - int priority, - GSourceFunc func, - gpointer user_data, - GDestroyNotify destroy_notify) +nm_g_timeout_source_new(guint timeout_msec, + int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify) { - GSource *source; + GSource *source; - source = g_timeout_source_new (timeout_msec); - if (priority != G_PRIORITY_DEFAULT) - g_source_set_priority (source, priority); - g_source_set_callback (source, func, user_data, destroy_notify); - return source; + source = g_timeout_source_new(timeout_msec); + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority(source, priority); + g_source_set_callback(source, func, user_data, destroy_notify); + return source; } GSource * -nm_g_unix_signal_source_new (int signum, - int priority, - GSourceFunc handler, - gpointer user_data, - GDestroyNotify notify) +nm_g_timeout_source_new_seconds(guint timeout_sec, + int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify) { - GSource *source; + GSource *source; - source = g_unix_signal_source_new (signum); + source = g_timeout_source_new_seconds(timeout_sec); + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority(source, priority); + g_source_set_callback(source, func, user_data, destroy_notify); + return source; +} + +GSource * +nm_g_unix_signal_source_new(int signum, + int priority, + GSourceFunc handler, + gpointer user_data, + GDestroyNotify notify) +{ + GSource *source; + + source = g_unix_signal_source_new(signum); - if (priority != G_PRIORITY_DEFAULT) - g_source_set_priority (source, priority); - g_source_set_callback (source, handler, user_data, notify); - return source; + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority(source, priority); + g_source_set_callback(source, handler, user_data, notify); + return source; } GSource * -nm_g_unix_fd_source_new (int fd, - GIOCondition io_condition, - int priority, - gboolean (*source_func) (int fd, - GIOCondition condition, - gpointer user_data), - gpointer user_data, - GDestroyNotify destroy_notify) +nm_g_unix_fd_source_new(int fd, + GIOCondition io_condition, + int priority, + gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data), + gpointer user_data, + GDestroyNotify destroy_notify) { - GSource *source; + GSource *source; - source = g_unix_fd_source_new (fd, io_condition); + source = g_unix_fd_source_new(fd, io_condition); - if (priority != G_PRIORITY_DEFAULT) - g_source_set_priority (source, priority); - g_source_set_callback (source, G_SOURCE_FUNC (source_func), user_data, destroy_notify); - return source; + if (priority != G_PRIORITY_DEFAULT) + g_source_set_priority(source, priority); + g_source_set_callback(source, G_SOURCE_FUNC(source_func), user_data, destroy_notify); + return source; } /*****************************************************************************/ -#define _CTX_LOG(fmt, ...) \ - G_STMT_START { \ - if (FALSE) { \ - gint64 _ts = g_get_monotonic_time () / 100; \ - \ - g_printerr (">>>> [%"G_GINT64_FORMAT".%05"G_GINT64_FORMAT"] [src:%p]: " fmt "\n", \ - _ts / 10000, \ - _ts % 10000, \ - (ctx_src), \ - ##__VA_ARGS__); \ - } \ - } G_STMT_END +#define _CTX_LOG(fmt, ...) \ + G_STMT_START \ + { \ + if (FALSE) { \ + gint64 _ts = g_get_monotonic_time() / 100; \ + \ + g_printerr(">>>> [%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] [src:%p]: " fmt "\n", \ + _ts / 10000, \ + _ts % 10000, \ + (ctx_src), \ + ##__VA_ARGS__); \ + } \ + } \ + G_STMT_END typedef struct { - int fd; - guint events; - guint registered_events; - union { - int one; - int *many; - } idx; - gpointer tag; - bool stale:1; - bool has_many_idx:1; + int fd; + guint events; + guint registered_events; + union { + int one; + int *many; + } idx; + gpointer tag; + bool stale : 1; + bool has_many_idx : 1; } PollData; typedef struct { - GSource source; - GMainContext *context; - GHashTable *fds; - GPollFD *fds_arr; - int fds_len; - int max_priority; - bool acquired:1; + GSource source; + GMainContext *context; + GHashTable * fds; + GPollFD * fds_arr; + int fds_len; + int max_priority; + bool acquired : 1; } CtxIntegSource; static void -_poll_data_free (gpointer user_data) +_poll_data_free(gpointer user_data) { - PollData *poll_data = user_data; + PollData *poll_data = user_data; - if (poll_data->has_many_idx) - g_free (poll_data->idx.many); - nm_g_slice_free (poll_data); + if (poll_data->has_many_idx) + g_free(poll_data->idx.many); + nm_g_slice_free(poll_data); } static void -_ctx_integ_source_reacquire (CtxIntegSource *ctx_src) +_ctx_integ_source_reacquire(CtxIntegSource *ctx_src) { - if (G_LIKELY ( ctx_src->acquired - && g_main_context_is_owner (ctx_src->context))) - return; + if (G_LIKELY(ctx_src->acquired && g_main_context_is_owner(ctx_src->context))) + return; - /* the parent context now iterates on a different thread. - * We need to release and reacquire the inner context. */ + /* the parent context now iterates on a different thread. + * We need to release and reacquire the inner context. */ - if (ctx_src->acquired) - g_main_context_release (ctx_src->context); + if (ctx_src->acquired) + g_main_context_release(ctx_src->context); - if (G_UNLIKELY (!g_main_context_acquire (ctx_src->context))) { - /* Nobody is supposed to reacquire the context while we use it. This is a bug - * of the user. */ - ctx_src->acquired = FALSE; - g_return_if_reached (); - } - ctx_src->acquired = TRUE; + if (G_UNLIKELY(!g_main_context_acquire(ctx_src->context))) { + /* Nobody is supposed to reacquire the context while we use it. This is a bug + * of the user. */ + ctx_src->acquired = FALSE; + g_return_if_reached(); + } + ctx_src->acquired = TRUE; } static gboolean -_ctx_integ_source_prepare (GSource *source, - int *out_timeout) -{ - CtxIntegSource *ctx_src = ((CtxIntegSource *) source); - int max_priority; - int timeout = -1; - gboolean any_ready; - int fds_allocated; - int fds_len_old; - gs_free GPollFD *fds_arr_old = NULL; - GHashTableIter h_iter; - PollData *poll_data; - gboolean fds_changed; - int i; - - _CTX_LOG ("prepare..."); - - _ctx_integ_source_reacquire (ctx_src); - - any_ready = g_main_context_prepare (ctx_src->context, &max_priority); - - fds_arr_old = g_steal_pointer (&ctx_src->fds_arr); - fds_len_old = ctx_src->fds_len; - - fds_allocated = NM_MAX (1, fds_len_old); /* there is at least the wakeup's FD */ - ctx_src->fds_arr = g_new (GPollFD, fds_allocated); - - while ((ctx_src->fds_len = g_main_context_query (ctx_src->context, - max_priority, - &timeout, - ctx_src->fds_arr, - fds_allocated)) > fds_allocated) { - fds_allocated = ctx_src->fds_len; - g_free (ctx_src->fds_arr); - ctx_src->fds_arr = g_new (GPollFD, fds_allocated); - } - - fds_changed = FALSE; - if (fds_len_old != ctx_src->fds_len) - fds_changed = TRUE; - else { - for (i = 0; i < ctx_src->fds_len; i++) { - if ( fds_arr_old[i].fd != ctx_src->fds_arr[i].fd - || fds_arr_old[i].events != ctx_src->fds_arr[i].events) { - fds_changed = TRUE; - break; - } - } - } - - if (G_UNLIKELY (fds_changed)) { - - g_hash_table_iter_init (&h_iter, ctx_src->fds); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) - poll_data->stale = TRUE; - - for (i = 0; i < ctx_src->fds_len; i++) { - const GPollFD *fd = &ctx_src->fds_arr[i]; - - poll_data = g_hash_table_lookup (ctx_src->fds, &fd->fd); - - if (G_UNLIKELY (!poll_data)) { - poll_data = g_slice_new (PollData); - *poll_data = (PollData) { - .fd = fd->fd, - .idx.one = i, - .has_many_idx = FALSE, - .events = fd->events, - .registered_events = 0, - .tag = NULL, - .stale = FALSE, - }; - g_hash_table_add (ctx_src->fds, poll_data); - nm_assert (poll_data == g_hash_table_lookup (ctx_src->fds, &fd->fd)); - continue; - } - - if (G_LIKELY (poll_data->stale)) { - if (poll_data->has_many_idx) { - g_free (poll_data->idx.many); - poll_data->has_many_idx = FALSE; - } - poll_data->events = fd->events; - poll_data->idx.one = i; - poll_data->stale = FALSE; - continue; - } - - /* How odd. We have duplicate FDs. In fact, currently g_main_context_query() always - * coalesces the FDs and this cannot happen. However, that is not documented behavior, - * so we should not rely on that. So we need to keep a list of indexes... */ - poll_data->events |= fd->events; - if (!poll_data->has_many_idx) { - int idx0; - - idx0 = poll_data->idx.one; - poll_data->has_many_idx = TRUE; - poll_data->idx.many = g_new (int, 4); - poll_data->idx.many[0] = 2; /* number allocated */ - poll_data->idx.many[1] = 2; /* number used */ - poll_data->idx.many[2] = idx0; - poll_data->idx.many[3] = i; - } else { - if (poll_data->idx.many[0] == poll_data->idx.many[1]) { - poll_data->idx.many[0] *= 2; - poll_data->idx.many = g_realloc (poll_data->idx.many, sizeof (int) * (2 + poll_data->idx.many[0])); - } - poll_data->idx.many[2 + poll_data->idx.many[1]] = i; - poll_data->idx.many[1]++; - } - - } - - g_hash_table_iter_init (&h_iter, ctx_src->fds); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) { - if (poll_data->stale) { - nm_assert (poll_data->tag); - nm_assert (poll_data->events == poll_data->registered_events); - _CTX_LOG ("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); - g_source_remove_unix_fd (&ctx_src->source, poll_data->tag); - g_hash_table_iter_remove (&h_iter); - continue; - } - if (!poll_data->tag) { - _CTX_LOG ("prepare: add poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); - poll_data->registered_events = poll_data->events; - poll_data->tag = g_source_add_unix_fd (&ctx_src->source, poll_data->fd, poll_data->registered_events); - continue; - } - if (poll_data->registered_events != poll_data->events) { - _CTX_LOG ("prepare: update poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); - poll_data->registered_events = poll_data->events; - g_source_modify_unix_fd (&ctx_src->source, poll_data->tag, poll_data->registered_events); - } - } - } - - NM_SET_OUT (out_timeout, timeout); - ctx_src->max_priority = max_priority; - - _CTX_LOG ("prepare: done, any-ready=%d, timeout=%d, max-priority=%d", any_ready, timeout, max_priority); - - /* we always need to poll, because we have some file descriptors. */ - return FALSE; +_ctx_integ_source_prepare(GSource *source, int *out_timeout) +{ + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + int max_priority; + int timeout = -1; + gboolean any_ready; + int fds_allocated; + int fds_len_old; + gs_free GPollFD *fds_arr_old = NULL; + GHashTableIter h_iter; + PollData * poll_data; + gboolean fds_changed; + int i; + + _CTX_LOG("prepare..."); + + _ctx_integ_source_reacquire(ctx_src); + + any_ready = g_main_context_prepare(ctx_src->context, &max_priority); + + fds_arr_old = g_steal_pointer(&ctx_src->fds_arr); + fds_len_old = ctx_src->fds_len; + + fds_allocated = NM_MAX(1, fds_len_old); /* there is at least the wakeup's FD */ + ctx_src->fds_arr = g_new(GPollFD, fds_allocated); + + while ((ctx_src->fds_len = g_main_context_query(ctx_src->context, + max_priority, + &timeout, + ctx_src->fds_arr, + fds_allocated)) + > fds_allocated) { + fds_allocated = ctx_src->fds_len; + g_free(ctx_src->fds_arr); + ctx_src->fds_arr = g_new(GPollFD, fds_allocated); + } + + fds_changed = FALSE; + if (fds_len_old != ctx_src->fds_len) + fds_changed = TRUE; + else { + for (i = 0; i < ctx_src->fds_len; i++) { + if (fds_arr_old[i].fd != ctx_src->fds_arr[i].fd + || fds_arr_old[i].events != ctx_src->fds_arr[i].events) { + fds_changed = TRUE; + break; + } + } + } + + if (G_UNLIKELY(fds_changed)) { + g_hash_table_iter_init(&h_iter, ctx_src->fds); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) + poll_data->stale = TRUE; + + for (i = 0; i < ctx_src->fds_len; i++) { + const GPollFD *fd = &ctx_src->fds_arr[i]; + + poll_data = g_hash_table_lookup(ctx_src->fds, &fd->fd); + + if (G_UNLIKELY(!poll_data)) { + poll_data = g_slice_new(PollData); + *poll_data = (PollData){ + .fd = fd->fd, + .idx.one = i, + .has_many_idx = FALSE, + .events = fd->events, + .registered_events = 0, + .tag = NULL, + .stale = FALSE, + }; + g_hash_table_add(ctx_src->fds, poll_data); + nm_assert(poll_data == g_hash_table_lookup(ctx_src->fds, &fd->fd)); + continue; + } + + if (G_LIKELY(poll_data->stale)) { + if (poll_data->has_many_idx) { + g_free(poll_data->idx.many); + poll_data->has_many_idx = FALSE; + } + poll_data->events = fd->events; + poll_data->idx.one = i; + poll_data->stale = FALSE; + continue; + } + + /* How odd. We have duplicate FDs. In fact, currently g_main_context_query() always + * coalesces the FDs and this cannot happen. However, that is not documented behavior, + * so we should not rely on that. So we need to keep a list of indexes... */ + poll_data->events |= fd->events; + if (!poll_data->has_many_idx) { + int idx0; + + idx0 = poll_data->idx.one; + poll_data->has_many_idx = TRUE; + poll_data->idx.many = g_new(int, 4); + poll_data->idx.many[0] = 2; /* number allocated */ + poll_data->idx.many[1] = 2; /* number used */ + poll_data->idx.many[2] = idx0; + poll_data->idx.many[3] = i; + } else { + if (poll_data->idx.many[0] == poll_data->idx.many[1]) { + poll_data->idx.many[0] *= 2; + poll_data->idx.many = + g_realloc(poll_data->idx.many, sizeof(int) * (2 + poll_data->idx.many[0])); + } + poll_data->idx.many[2 + poll_data->idx.many[1]] = i; + poll_data->idx.many[1]++; + } + } + + g_hash_table_iter_init(&h_iter, ctx_src->fds); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) { + if (poll_data->stale) { + nm_assert(poll_data->tag); + nm_assert(poll_data->events == poll_data->registered_events); + _CTX_LOG("prepare: remove poll fd=%d, events=0x%x", + poll_data->fd, + poll_data->events); + g_source_remove_unix_fd(&ctx_src->source, poll_data->tag); + g_hash_table_iter_remove(&h_iter); + continue; + } + if (!poll_data->tag) { + _CTX_LOG("prepare: add poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); + poll_data->registered_events = poll_data->events; + poll_data->tag = g_source_add_unix_fd(&ctx_src->source, + poll_data->fd, + poll_data->registered_events); + continue; + } + if (poll_data->registered_events != poll_data->events) { + _CTX_LOG("prepare: update poll fd=%d, events=0x%x", + poll_data->fd, + poll_data->events); + poll_data->registered_events = poll_data->events; + g_source_modify_unix_fd(&ctx_src->source, + poll_data->tag, + poll_data->registered_events); + } + } + } + + NM_SET_OUT(out_timeout, timeout); + ctx_src->max_priority = max_priority; + + _CTX_LOG("prepare: done, any-ready=%d, timeout=%d, max-priority=%d", + any_ready, + timeout, + max_priority); + + /* we always need to poll, because we have some file descriptors. */ + return FALSE; } static gboolean -_ctx_integ_source_check (GSource *source) +_ctx_integ_source_check(GSource *source) { - CtxIntegSource *ctx_src = ((CtxIntegSource *) source); - GHashTableIter h_iter; - gboolean some_ready; - PollData *poll_data; + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + GHashTableIter h_iter; + gboolean some_ready; + PollData * poll_data; - nm_assert (ctx_src->context); + nm_assert(ctx_src->context); - _CTX_LOG ("check"); + _CTX_LOG("check"); - _ctx_integ_source_reacquire (ctx_src); + _ctx_integ_source_reacquire(ctx_src); - g_hash_table_iter_init (&h_iter, ctx_src->fds); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) { - guint revents; + g_hash_table_iter_init(&h_iter, ctx_src->fds); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) { + guint revents; - revents = g_source_query_unix_fd (&ctx_src->source, poll_data->tag); - if (G_UNLIKELY (poll_data->has_many_idx)) { - int num = poll_data->idx.many[1]; - int *p_idx = &poll_data->idx.many[2]; + revents = g_source_query_unix_fd(&ctx_src->source, poll_data->tag); + if (G_UNLIKELY(poll_data->has_many_idx)) { + int num = poll_data->idx.many[1]; + int *p_idx = &poll_data->idx.many[2]; - for (; num > 0; num--, p_idx++) - ctx_src->fds_arr[*p_idx].revents = revents; - } else - ctx_src->fds_arr[poll_data->idx.one].revents = revents; - } + for (; num > 0; num--, p_idx++) + ctx_src->fds_arr[*p_idx].revents = revents; + } else + ctx_src->fds_arr[poll_data->idx.one].revents = revents; + } - some_ready = g_main_context_check (ctx_src->context, - ctx_src->max_priority, - ctx_src->fds_arr, - ctx_src->fds_len); + some_ready = g_main_context_check(ctx_src->context, + ctx_src->max_priority, + ctx_src->fds_arr, + ctx_src->fds_len); - _CTX_LOG ("check (some-ready=%d)...", some_ready); + _CTX_LOG("check (some-ready=%d)...", some_ready); - return some_ready; + return some_ready; } static gboolean -_ctx_integ_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) +_ctx_integ_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { - CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); - nm_assert (ctx_src->context); + nm_assert(ctx_src->context); - _ctx_integ_source_reacquire (ctx_src); + _ctx_integ_source_reacquire(ctx_src); - _CTX_LOG ("dispatch"); + _CTX_LOG("dispatch"); - g_main_context_dispatch (ctx_src->context); + g_main_context_dispatch(ctx_src->context); - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } static void -_ctx_integ_source_finalize (GSource *source) +_ctx_integ_source_finalize(GSource *source) { - CtxIntegSource *ctx_src = ((CtxIntegSource *) source); - GHashTableIter h_iter; - PollData *poll_data; + CtxIntegSource *ctx_src = ((CtxIntegSource *) source); + GHashTableIter h_iter; + PollData * poll_data; - g_return_if_fail (ctx_src->context); + g_return_if_fail(ctx_src->context); - _CTX_LOG ("finalize..."); + _CTX_LOG("finalize..."); - g_hash_table_iter_init (&h_iter, ctx_src->fds); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &poll_data, NULL)) { - nm_assert (poll_data->tag); - _CTX_LOG ("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); - g_source_remove_unix_fd (&ctx_src->source, poll_data->tag); - g_hash_table_iter_remove (&h_iter); - } + g_hash_table_iter_init(&h_iter, ctx_src->fds); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) { + nm_assert(poll_data->tag); + _CTX_LOG("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events); + g_source_remove_unix_fd(&ctx_src->source, poll_data->tag); + g_hash_table_iter_remove(&h_iter); + } - nm_clear_pointer (&ctx_src->fds, g_hash_table_unref); - nm_clear_g_free (&ctx_src->fds_arr); - ctx_src->fds_len = 0; + nm_clear_pointer(&ctx_src->fds, g_hash_table_unref); + nm_clear_g_free(&ctx_src->fds_arr); + ctx_src->fds_len = 0; - if (ctx_src->acquired) { - ctx_src->acquired = FALSE; - g_main_context_release (ctx_src->context); - } + if (ctx_src->acquired) { + ctx_src->acquired = FALSE; + g_main_context_release(ctx_src->context); + } - nm_clear_pointer (&ctx_src->context, g_main_context_unref); + nm_clear_pointer(&ctx_src->context, g_main_context_unref); } static GSourceFuncs ctx_integ_source_funcs = { - .prepare = _ctx_integ_source_prepare, - .check = _ctx_integ_source_check, - .dispatch = _ctx_integ_source_dispatch, - .finalize = _ctx_integ_source_finalize, + .prepare = _ctx_integ_source_prepare, + .check = _ctx_integ_source_check, + .dispatch = _ctx_integ_source_dispatch, + .finalize = _ctx_integ_source_finalize, }; /** @@ -4760,260 +5057,260 @@ static GSourceFuncs ctx_integ_source_funcs = { * outer context. */ GSource * -nm_utils_g_main_context_create_integrate_source (GMainContext *inner_context) +nm_utils_g_main_context_create_integrate_source(GMainContext *inner_context) { - CtxIntegSource *ctx_src; + CtxIntegSource *ctx_src; - g_return_val_if_fail (inner_context, NULL); + g_return_val_if_fail(inner_context, NULL); - if (!g_main_context_acquire (inner_context)) { - /* We require to acquire the context while it's integrated. We need to keep it acquired - * for the entire duration. - * - * This is also necessary because g_source_attach() only wakes up the context, if - * the context is currently acquired. */ - g_return_val_if_reached (NULL); - } + if (!g_main_context_acquire(inner_context)) { + /* We require to acquire the context while it's integrated. We need to keep it acquired + * for the entire duration. + * + * This is also necessary because g_source_attach() only wakes up the context, if + * the context is currently acquired. */ + g_return_val_if_reached(NULL); + } - ctx_src = (CtxIntegSource *) g_source_new (&ctx_integ_source_funcs, sizeof (CtxIntegSource)); + ctx_src = (CtxIntegSource *) g_source_new(&ctx_integ_source_funcs, sizeof(CtxIntegSource)); - g_source_set_name (&ctx_src->source, "ContextIntegrateSource"); + g_source_set_name(&ctx_src->source, "ContextIntegrateSource"); - ctx_src->context = g_main_context_ref (inner_context); - ctx_src->fds = g_hash_table_new_full (nm_pint_hash, nm_pint_equals, _poll_data_free, NULL); - ctx_src->fds_len = 0; - ctx_src->fds_arr = NULL; - ctx_src->acquired = TRUE; - ctx_src->max_priority = G_MAXINT; + ctx_src->context = g_main_context_ref(inner_context); + ctx_src->fds = g_hash_table_new_full(nm_pint_hash, nm_pint_equals, _poll_data_free, NULL); + ctx_src->fds_len = 0; + ctx_src->fds_arr = NULL; + ctx_src->acquired = TRUE; + ctx_src->max_priority = G_MAXINT; - _CTX_LOG ("create new integ-source for %p", inner_context); + _CTX_LOG("create new integ-source for %p", inner_context); - return &ctx_src->source; + return &ctx_src->source; } gboolean -nm_utils_ifname_valid_kernel (const char *name, GError **error) -{ - int i; - - /* This function follows kernel's interface validation - * function dev_valid_name() in net/core/dev.c. - */ - - if (!name) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name is missing")); - return FALSE; - } - - if (name[0] == '\0') { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name is too short")); - return FALSE; - } - - if ( name[0] == '.' - && ( name[1] == '\0' - || ( name[1] == '.' - && name[2] == '\0'))) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name is reserved")); - return FALSE; - } - - for (i = 0; i < IFNAMSIZ; i++) { - char ch = name[i]; - - if (ch == '\0') - return TRUE; - if ( NM_IN_SET (ch, '/', ':') - || g_ascii_isspace (ch)) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name contains an invalid character")); - return FALSE; - } - } - - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name is longer than 15 characters")); - return FALSE; +nm_utils_ifname_valid_kernel(const char *name, GError **error) +{ + int i; + + /* This function follows kernel's interface validation + * function dev_valid_name() in net/core/dev.c. + */ + + if (!name) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name is missing")); + return FALSE; + } + + if (name[0] == '\0') { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name is too short")); + return FALSE; + } + + if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name is reserved")); + return FALSE; + } + + for (i = 0; i < IFNAMSIZ; i++) { + char ch = name[i]; + + if (ch == '\0') + return TRUE; + if (NM_IN_SET(ch, '/', ':') || g_ascii_isspace(ch)) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name contains an invalid character")); + return FALSE; + } + } + + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name is longer than 15 characters")); + return FALSE; } /*****************************************************************************/ static gboolean -_nm_utils_ifname_valid_kernel (const char *name, GError **error) -{ - if (!nm_utils_ifname_valid_kernel (name, error)) - return FALSE; - - if (strchr (name, '%')) { - /* Kernel's dev_valid_name() accepts (almost) any binary up to 15 chars. - * However, '%' is treated special as a format specifier. Try - * - * ip link add 'dummy%dx' type dummy - * - * Don't allow that for "connection.interface-name", which either - * matches an existing netdev name (thus, it cannot have a '%') or - * is used to configure a name (in which case we don't want kernel - * to replace the format specifier). */ - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("'%%' is not allowed in interface names")); - return FALSE; - } - - if (NM_IN_STRSET (name, "all", - "default", - "bonding_masters")) { - /* Certain names are not allowed. The "all" and "default" names are reserved - * due to their directories in "/proc/sys/net/ipv4/conf/" and "/proc/sys/net/ipv6/conf/". - * - * Also, there is "/sys/class/net/bonding_masters" file. - */ - nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, - _("'%s' is not allowed as interface name"), name); - return FALSE; - } - - return TRUE; +_nm_utils_ifname_valid_kernel(const char *name, GError **error) +{ + if (!nm_utils_ifname_valid_kernel(name, error)) + return FALSE; + + if (strchr(name, '%')) { + /* Kernel's dev_valid_name() accepts (almost) any binary up to 15 chars. + * However, '%' is treated special as a format specifier. Try + * + * ip link add 'dummy%dx' type dummy + * + * Don't allow that for "connection.interface-name", which either + * matches an existing netdev name (thus, it cannot have a '%') or + * is used to configure a name (in which case we don't want kernel + * to replace the format specifier). */ + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("'%%' is not allowed in interface names")); + return FALSE; + } + + if (NM_IN_STRSET(name, "all", "default", "bonding_masters")) { + /* Certain names are not allowed. The "all" and "default" names are reserved + * due to their directories in "/proc/sys/net/ipv4/conf/" and "/proc/sys/net/ipv6/conf/". + * + * Also, there is "/sys/class/net/bonding_masters" file. + */ + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + _("'%s' is not allowed as interface name"), + name); + return FALSE; + } + + return TRUE; } static gboolean -_nm_utils_ifname_valid_ovs (const char *name, GError **error) -{ - const char *ch; - - /* OVS actually accepts a wider range of chars (all printable UTF-8 chars), - NetworkManager restricts this to ASCII char as it's a safer option for - now since OVS is not well documented on this matter. - */ - for (ch = name; *ch; ++ch) { - if ( *ch == '\\' - || *ch == '/' - || !g_ascii_isgraph (*ch)) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name must be alphanumerical with " - "no forward or backward slashes")); - return FALSE; - } - }; - return TRUE; +_nm_utils_ifname_valid_ovs(const char *name, GError **error) +{ + const char *ch; + + /* OVS actually accepts a wider range of chars (all printable UTF-8 chars), + * NetworkManager restricts this to ASCII char as it's a safer option for + * now since OVS is not well documented on this matter. + **/ + for (ch = name; *ch; ++ch) { + if (*ch == '\\' || *ch == '/' || !g_ascii_isgraph(*ch)) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name must be alphanumerical with " + "no forward or backward slashes")); + return FALSE; + } + }; + return TRUE; } gboolean -nm_utils_ifname_valid (const char* name, - NMUtilsIfaceType type, - GError **error) -{ - g_return_val_if_fail (!error || !(*error), FALSE); - - if (!name || !(name[0])) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name must not be empty")); - return FALSE; - } - - if (!g_utf8_validate (name, -1, NULL)) { - g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - _("interface name must be UTF-8 encoded")); - return FALSE; - } - - switch (type) { - case NMU_IFACE_KERNEL: - return _nm_utils_ifname_valid_kernel (name, error); - case NMU_IFACE_OVS: - return _nm_utils_ifname_valid_ovs (name, error); - case NMU_IFACE_OVS_AND_KERNEL: - return _nm_utils_ifname_valid_kernel (name, error) - && _nm_utils_ifname_valid_ovs (name, error); - case NMU_IFACE_ANY: { - gs_free_error GError *local = NULL; - - if (_nm_utils_ifname_valid_kernel (name, error ? &local : NULL)) - return TRUE; - if (_nm_utils_ifname_valid_ovs (name, NULL)) - return TRUE; - if (error) - g_propagate_error (error, g_steal_pointer (&local)); - return FALSE; - } - } - - g_return_val_if_reached (FALSE); +nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError **error) +{ + g_return_val_if_fail(!error || !(*error), FALSE); + + if (!name || !(name[0])) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name must not be empty")); + return FALSE; + } + + if (!g_utf8_validate(name, -1, NULL)) { + g_set_error_literal(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("interface name must be UTF-8 encoded")); + return FALSE; + } + + switch (type) { + case NMU_IFACE_KERNEL: + return _nm_utils_ifname_valid_kernel(name, error); + case NMU_IFACE_OVS: + return _nm_utils_ifname_valid_ovs(name, error); + case NMU_IFACE_OVS_AND_KERNEL: + return _nm_utils_ifname_valid_kernel(name, error) + && _nm_utils_ifname_valid_ovs(name, error); + case NMU_IFACE_ANY: + { + gs_free_error GError *local = NULL; + + if (_nm_utils_ifname_valid_kernel(name, error ? &local : NULL)) + return TRUE; + if (_nm_utils_ifname_valid_ovs(name, NULL)) + return TRUE; + if (error) + g_propagate_error(error, g_steal_pointer(&local)); + return FALSE; + } + } + + g_return_val_if_reached(FALSE); } /*****************************************************************************/ void -_nm_str_buf_ensure_size (NMStrBuf *strbuf, - gsize new_size, - gboolean reserve_exact) +_nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact) { - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); - /* Currently this only supports strictly growing the buffer. */ - nm_assert (new_size > strbuf->_priv_allocated); + /* Currently, this only supports strictly growing the buffer. */ + nm_assert(new_size > strbuf->_priv_allocated); - if (!reserve_exact) { - new_size = nm_utils_get_next_realloc_size (!strbuf->_priv_do_bzero_mem, - new_size); - } + if (!reserve_exact) { + new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size); + } - strbuf->_priv_str = nm_secret_mem_realloc (strbuf->_priv_str, - strbuf->_priv_do_bzero_mem, - strbuf->_priv_allocated, - new_size); - strbuf->_priv_allocated = new_size; + strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str, + strbuf->_priv_do_bzero_mem, + strbuf->_priv_allocated, + new_size); + strbuf->_priv_allocated = new_size; } void -nm_str_buf_append_printf (NMStrBuf *strbuf, - const char *format, - ...) +nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) { - va_list args; - gsize available; - int l; + va_list args; + gsize available; + int l; - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); - available = strbuf->_priv_allocated - strbuf->_priv_len; + available = strbuf->_priv_allocated - strbuf->_priv_len; - nm_assert (available < G_MAXULONG); + nm_assert(available < G_MAXULONG); - va_start (args, format); - l = g_vsnprintf (&strbuf->_priv_str[strbuf->_priv_len], - available, - format, - args); - va_end (args); + va_start(args, format); + l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], available, format, args); + va_end(args); - nm_assert (l >= 0); - nm_assert (l < G_MAXINT); + nm_assert(l >= 0); + nm_assert(l < G_MAXINT); - if ((gsize) l >= available) { - gsize l2; + if ((gsize) l >= available) { + gsize l2; - if (l == 0) - return; + if (l == 0) + return; - l2 = ((gsize) l) + 1u; + l2 = ((gsize) l) + 1u; - nm_str_buf_maybe_expand (strbuf, l2, FALSE); + nm_str_buf_maybe_expand(strbuf, l2, FALSE); - va_start (args, format); - l = g_vsnprintf (&strbuf->_priv_str[strbuf->_priv_len], - l2, - format, - args); - va_end (args); + va_start(args, format); + l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], l2, format, args); + va_end(args); - nm_assert (l >= 0); - nm_assert ((gsize) l == l2 - 1u); - } + nm_assert(l >= 0); + nm_assert((gsize) l == l2 - 1u); + } - strbuf->_priv_len += (gsize) l; + strbuf->_priv_len += (gsize) l; } /*****************************************************************************/ @@ -5029,109 +5326,285 @@ nm_str_buf_append_printf (NMStrBuf *strbuf, * the first pointer. */ void -nm_indirect_g_free (gpointer arg) +nm_indirect_g_free(gpointer arg) { - gpointer *p = arg; + gpointer *p = arg; - nm_clear_g_free (p); + nm_clear_g_free(p); } /*****************************************************************************/ static char * -attribute_escape (const char *src, char c1, char c2) +attribute_escape(const char *src, char c1, char c2) { - char *ret, *dest; + char *ret, *dest; - dest = ret = g_malloc (strlen (src) * 2 + 1); + dest = ret = g_malloc(strlen(src) * 2 + 1); - while (*src) { - if (*src == c1 || *src == c2 || *src == '\\') - *dest++ = '\\'; - *dest++ = *src++; - } - *dest++ = '\0'; + while (*src) { + if (*src == c1 || *src == c2 || *src == '\\') + *dest++ = '\\'; + *dest++ = *src++; + } + *dest++ = '\0'; - return ret; + return ret; } void -_nm_utils_format_variant_attributes_full (GString *str, - const NMUtilsNamedValue *values, - guint num_values, - char attr_separator, - char key_value_separator) -{ - const char *name, *value; - GVariant *variant; - char *escaped; - char buf[64]; - char sep = 0; - guint i; - - for (i = 0; i < num_values; i++) { - name = values[i].name; - variant = (GVariant *) values[i].value_ptr; - value = NULL; - - if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)) - value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant)); - else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32)) - value = nm_sprintf_buf (buf, "%d", (int) g_variant_get_int32 (variant)); - else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64)) - value = nm_sprintf_buf (buf, "%"G_GUINT64_FORMAT, g_variant_get_uint64 (variant)); - else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)) - value = nm_sprintf_buf (buf, "%hhu", g_variant_get_byte (variant)); - else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) - value = g_variant_get_boolean (variant) ? "true" : "false"; - else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) - value = g_variant_get_string (variant, NULL); - else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING)) { - /* FIXME: there is no guarantee that the byte array - * is valid UTF-8.*/ - value = g_variant_get_bytestring (variant); - } else - continue; - - if (sep) - g_string_append_c (str, sep); - - escaped = attribute_escape (name, attr_separator, key_value_separator); - g_string_append (str, escaped); - g_free (escaped); - - 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); - - sep = attr_separator; - } +_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; + char buf[64]; + char sep = 0; + guint i; + + for (i = 0; i < num_values; i++) { + name = values[i].name; + 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)); + else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT32)) + value = nm_sprintf_buf(buf, "%d", (int) g_variant_get_int32(variant)); + else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT64)) + value = nm_sprintf_buf(buf, "%" G_GUINT64_FORMAT, g_variant_get_uint64(variant)); + else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTE)) + value = nm_sprintf_buf(buf, "%hhu", g_variant_get_byte(variant)); + else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) + value = g_variant_get_boolean(variant) ? "true" : "false"; + else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) + value = g_variant_get_string(variant, NULL); + else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTESTRING)) { + /* FIXME: there is no guarantee that the byte array + * is valid UTF-8.*/ + value = g_variant_get_bytestring(variant); + } else + continue; + + if (sep) + g_string_append_c(str, sep); + + escaped = attribute_escape(name, attr_separator, key_value_separator); + g_string_append(str, escaped); + g_free(escaped); + + 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); + } + + sep = attr_separator; + } } char * -_nm_utils_format_variant_attributes (GHashTable *attributes, - char attr_separator, - char key_value_separator) +_nm_utils_format_variant_attributes(GHashTable * attributes, + const NMVariantAttributeSpec *const *spec, + char attr_separator, + char key_value_separator) { - GString *str = NULL; - gs_free NMUtilsNamedValue *values = NULL; - guint len; + gs_free NMUtilsNamedValue *values_free = NULL; + NMUtilsNamedValue values_prepared[20]; + const NMUtilsNamedValue * values; + GString * str = NULL; + guint len; + + g_return_val_if_fail(attr_separator, NULL); + g_return_val_if_fail(key_value_separator, NULL); - g_return_val_if_fail (attr_separator, NULL); - g_return_val_if_fail (key_value_separator, NULL); + if (!attributes) + return NULL; - if (!attributes || !g_hash_table_size (attributes)) - return NULL; + values = nm_utils_named_values_from_strdict(attributes, &len, values_prepared, &values_free); + if (len == 0) + return NULL; - values = nm_utils_named_values_from_str_dict (attributes, &len); + 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); +} + +/*****************************************************************************/ + +gboolean +nm_utils_is_localhost(const char *name) +{ + static const char *const NAMES[] = { + "localhost", + "localhost4", + "localhost6", + "localhost.localdomain", + "localhost4.localdomain4", + "localhost6.localdomain6", + }; + gsize name_len; + int i; - str = g_string_new (""); - _nm_utils_format_variant_attributes_full (str, - values, - len, - attr_separator, - key_value_separator); - return g_string_free (str, FALSE); + if (!name) + return FALSE; + + /* This tries to identify local host and domain names + * described in RFC6761 plus the redhatism of localdomain. + * + * Similar to systemd's is_localhost(). */ + + name_len = strlen(name); + + if (name_len == 0) + return FALSE; + + if (name[name_len - 1] == '.') { + /* one trailing dot is fine. Hide it. */ + name_len--; + } + + for (i = 0; i < (int) G_N_ELEMENTS(NAMES); i++) { + const char *n = NAMES[i]; + gsize l = strlen(n); + gsize s; + + if (name_len < l) + continue; + + s = name_len - l; + + if (g_ascii_strncasecmp(&name[s], n, l) != 0) + continue; + + /* we accept the name if it is equal to one of the well-known names, + * or if it is some prefix, a '.' and the well-known name. */ + if (s == 0) + return TRUE; + if (name[s - 1] == '.') + return TRUE; + } + + return FALSE; +} + +gboolean +nm_utils_is_specific_hostname(const char *name) +{ + if (nm_str_is_empty(name)) + return FALSE; + + if (nm_streq(name, "(none)")) { + /* This is not a special hostname. Probably an artefact by somebody wrongly + * printing NULL. */ + return FALSE; + } + + if (nm_utils_is_localhost(name)) + return FALSE; + + /* FIXME: properly validate the hostname, like systemd's hostname_is_valid() */ + + return TRUE; +} + +/*****************************************************************************/ + +/* taken from systemd's uid_to_name(). */ +char * +nm_utils_uid_to_name(uid_t uid) +{ + gs_free char *buf_heap = NULL; + char buf_stack[4096]; + gsize bufsize; + char * buf; + + bufsize = sizeof(buf_stack); + buf = buf_stack; + + for (;;) { + struct passwd pwbuf; + struct passwd *pw = NULL; + int r; + + r = getpwuid_r(uid, &pwbuf, buf, bufsize, &pw); + if (r == 0 && pw) + return nm_strdup_not_empty(pw->pw_name); + + if (r != ERANGE) + return NULL; + + if (bufsize > G_MAXSIZE / 2u) + return NULL; + + bufsize *= 2u; + g_free(buf_heap); + buf_heap = g_malloc(bufsize); + buf = buf_heap; + } +} + +/* taken from systemd's nss_user_record_by_name() */ +gboolean +nm_utils_name_to_uid(const char *name, uid_t *out_uid) +{ + gs_free char *buf_heap = NULL; + char buf_stack[4096]; + gsize bufsize; + char * buf; + + if (!name) + return nm_assert_unreachable_val(FALSE); + + bufsize = sizeof(buf_stack); + buf = buf_stack; + + for (;;) { + struct passwd *result; + struct passwd pwd; + int r; + + r = getpwnam_r(name, &pwd, buf, bufsize, &result); + if (r == 0) { + if (!result) + return FALSE; + NM_SET_OUT(out_uid, pwd.pw_uid); + return TRUE; + } + + if (r != ERANGE) + return FALSE; + + if (bufsize > G_MAXSIZE / 2u) + return FALSE; + + bufsize *= 2u; + g_free(buf_heap); + buf_heap = g_malloc(bufsize); + buf = buf_heap; + } } diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index b17c8d1a..83e1c284 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2016 Red Hat, Inc. */ @@ -8,35 +8,51 @@ #include <netinet/in.h> +static inline gboolean +nm_is_ascii(char ch) +{ + return ((uint8_t) ch) < 128; +} + /*****************************************************************************/ -pid_t nm_utils_gettid (void); +pid_t nm_utils_gettid(void); -gboolean _nm_assert_on_main_thread (void); +gboolean _nm_assert_on_main_thread(void); #if NM_MORE_ASSERTS > 5 -#define NM_ASSERT_ON_MAIN_THREAD() G_STMT_START { nm_assert (_nm_assert_on_main_thread ()); } G_STMT_END + #define NM_ASSERT_ON_MAIN_THREAD() \ + G_STMT_START \ + { \ + nm_assert(_nm_assert_on_main_thread()); \ + } \ + G_STMT_END #else -#define NM_ASSERT_ON_MAIN_THREAD() G_STMT_START { ; } G_STMT_END + #define NM_ASSERT_ON_MAIN_THREAD() \ + G_STMT_START \ + { \ + ; \ + } \ + G_STMT_END #endif /*****************************************************************************/ static inline gboolean -_NM_INT_NOT_NEGATIVE (gssize val) -{ - /* whether an enum (without negative values) is a signed int, depends on compiler options - * and compiler implementation. - * - * When using such an enum for accessing an array, one naturally wants to check - * that the enum is not negative. However, the compiler doesn't like a plain - * comparison "enum_val >= 0", because (if the enum is unsigned), it will warn - * that the expression is always true *duh*. Not even a cast to a signed - * type helps to avoid the compiler warning in any case. - * - * The sole purpose of this function is to avoid a compiler warning, when checking - * that an enum is not negative. */ - return val >= 0; +_NM_INT_NOT_NEGATIVE(gssize val) +{ + /* whether an enum (without negative values) is a signed int, depends on compiler options + * and compiler implementation. + * + * When using such an enum for accessing an array, one naturally wants to check + * that the enum is not negative. However, the compiler doesn't like a plain + * comparison "enum_val >= 0", because (if the enum is unsigned), it will warn + * that the expression is always true *duh*. Not even a cast to a signed + * type helps to avoid the compiler warning in any case. + * + * The sole purpose of this function is to avoid a compiler warning, when checking + * that an enum is not negative. */ + return val >= 0; } /* check whether the integer value is smaller than G_MAXINT32. This macro exists @@ -47,133 +63,127 @@ _NM_INT_NOT_NEGATIVE (gssize val) * exists to catch cases where that is not true. * * Together with the G_STATIC_ASSERT(), we make sure that this is always satisfied. */ -G_STATIC_ASSERT (sizeof (int) == sizeof (gint32)); +G_STATIC_ASSERT(sizeof(int) == sizeof(gint32)); #if _NM_CC_SUPPORT_GENERIC -#define _NM_INT_LE_MAXINT32(value) \ - ({ \ - _nm_unused typeof (value) _value = (value); \ - \ - _Generic((value), \ - int: TRUE \ - ); \ - }) + #define _NM_INT_LE_MAXINT32(value) \ + ({ \ + _nm_unused typeof(value) _value = (value); \ + \ + _Generic((value), int : TRUE); \ + }) #else -#define _NM_INT_LE_MAXINT32(value) ({ \ - _nm_unused typeof (value) _value = (value); \ - _nm_unused const int *_p_value = &_value; \ - \ - TRUE; \ - }) + #define _NM_INT_LE_MAXINT32(value) \ + ({ \ + _nm_unused typeof(value) _value = (value); \ + _nm_unused const int *_p_value = &_value; \ + \ + TRUE; \ + }) #endif /*****************************************************************************/ -static inline char -nm_utils_addr_family_to_char (int addr_family) -{ - switch (addr_family) { - case AF_UNSPEC: return 'X'; - case AF_INET: return '4'; - case AF_INET6: return '6'; - } - g_return_val_if_reached ('?'); -} +typedef struct { + guint8 ether_addr_octet[6 /*ETH_ALEN*/]; +} NMEtherAddr; + +#define NM_ETHER_ADDR_FORMAT_STR "%02X:%02X:%02X:%02X:%02X:%02X" +#define NM_ETHER_ADDR_FORMAT_VAL(x) \ + (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], \ + (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] +#define NM_ETHER_ADDR_INIT(...) \ + { \ + .ether_addr_octet = {__VA_ARGS__}, \ + } -static inline gsize -nm_utils_addr_family_to_size (int addr_family) +static inline int +nm_ether_addr_cmp(const NMEtherAddr *a, const NMEtherAddr *b) { - switch (addr_family) { - case AF_INET: return sizeof (in_addr_t); - case AF_INET6: return sizeof (struct in6_addr); - } - g_return_val_if_reached (0); + NM_CMP_SELF(a, b); + NM_CMP_DIRECT_MEMCMP(a, b, sizeof(NMEtherAddr)); + return 0; } -static inline int -nm_utils_addr_family_from_size (gsize len) +static inline gboolean +nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b) { - switch (len) { - case sizeof (in_addr_t): return AF_INET; - case sizeof (struct in6_addr): return AF_INET6; - } - return AF_UNSPEC; + return nm_ether_addr_cmp(a, b) == 0; } -#define nm_assert_addr_family(addr_family) \ - nm_assert (NM_IN_SET ((addr_family), AF_INET, AF_INET6)) - /*****************************************************************************/ typedef struct { - union { - guint8 addr_ptr[1]; - in_addr_t addr4; - struct in_addr addr4_struct; - struct in6_addr addr6; - - /* NMIPAddr is really a union for IP addresses. - * However, as ethernet addresses fit in here nicely, use - * it also for an ethernet MAC address. */ - guint8 addr_eth[6 /*ETH_ALEN*/]; - - guint8 array[sizeof (struct in6_addr)]; - }; + union { + guint8 addr_ptr[1]; + in_addr_t addr4; + struct in_addr addr4_struct; + struct in6_addr addr6; + + /* NMIPAddr is really a union for IP addresses. + * However, as ethernet addresses fit in here nicely, use + * it also for an ethernet MAC address. */ + guint8 ether_addr_octet[6 /*ETH_ALEN*/]; + NMEtherAddr ether_addr; + + guint8 array[sizeof(struct in6_addr)]; + }; } NMIPAddr; -#define NM_IP_ADDR_INIT { .array = { 0 } } +#define NM_IP_ADDR_INIT \ + { \ + .array = { 0 } \ + } extern const NMIPAddr nm_ip_addr_zero; +#define nm_ether_addr_zero (nm_ip_addr_zero.ether_addr) + static inline int -nm_ip_addr_cmp (int addr_family, gconstpointer a, gconstpointer b) +nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b) { - nm_assert_addr_family (addr_family); - nm_assert (a); - nm_assert (b); + nm_assert_addr_family(addr_family); + nm_assert(a); + nm_assert(b); - return memcmp (a, b, nm_utils_addr_family_to_size (addr_family)); + return memcmp(a, b, nm_utils_addr_family_to_size(addr_family)); } static inline gboolean -nm_ip_addr_equal (int addr_family, gconstpointer a, gconstpointer b) +nm_ip_addr_equal(int addr_family, gconstpointer a, gconstpointer b) { - return nm_ip_addr_cmp (addr_family, a, b) == 0; + return nm_ip_addr_cmp(addr_family, a, b) == 0; } static inline gboolean -nm_ip_addr_is_null (int addr_family, gconstpointer addr) +nm_ip_addr_is_null(int addr_family, gconstpointer addr) { - nm_assert (addr); - if (addr_family == AF_INET6) - return IN6_IS_ADDR_UNSPECIFIED ((const struct in6_addr *) addr); - nm_assert (addr_family == AF_INET); - return ((const struct in_addr *) addr)->s_addr == 0; + nm_assert(addr); + if (addr_family == AF_INET6) + return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr); + nm_assert(addr_family == AF_INET); + return ((const struct in_addr *) addr)->s_addr == 0; } static inline void -nm_ip_addr_set (int addr_family, gpointer dst, gconstpointer src) +nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src) { - nm_assert_addr_family (addr_family); - nm_assert (dst); - nm_assert (src); + nm_assert_addr_family(addr_family); + nm_assert(dst); + nm_assert(src); - memcpy (dst, - src, - (addr_family != AF_INET6) - ? sizeof (in_addr_t) - : sizeof (struct in6_addr)); + memcpy(dst, src, (addr_family != AF_INET6) ? sizeof(in_addr_t) : sizeof(struct in6_addr)); } -gboolean nm_ip_addr_set_from_untrusted (int addr_family, - gpointer dst, - gconstpointer src, - gsize src_len, - int *out_addr_family); +gboolean nm_ip_addr_set_from_untrusted(int addr_family, + gpointer dst, + gconstpointer src, + gsize src_len, + int * out_addr_family); static inline gboolean -nm_ip4_addr_is_localhost (in_addr_t addr4) +nm_ip4_addr_is_localhost(in_addr_t addr4) { - return (addr4 & htonl (0xFF000000u)) == htonl (0x7F000000u); + return (addr4 & htonl(0xFF000000u)) == htonl(0x7F000000u); } /*****************************************************************************/ @@ -181,17 +191,17 @@ nm_ip4_addr_is_localhost (in_addr_t addr4) struct ether_addr; static inline int -nm_utils_ether_addr_cmp (const struct ether_addr *a1, const struct ether_addr *a2) +nm_utils_ether_addr_cmp(const struct ether_addr *a1, const struct ether_addr *a2) { - nm_assert (a1); - nm_assert (a2); - return memcmp (a1, a2, 6 /*ETH_ALEN*/); + nm_assert(a1); + nm_assert(a2); + return memcmp(a1, a2, 6 /*ETH_ALEN*/); } static inline gboolean -nm_utils_ether_addr_equal (const struct ether_addr *a1, const struct ether_addr *a2) +nm_utils_ether_addr_equal(const struct ether_addr *a1, const struct ether_addr *a2) { - return nm_utils_ether_addr_cmp (a1, a2) == 0; + return nm_utils_ether_addr_cmp(a1, a2) == 0; } /*****************************************************************************/ @@ -199,743 +209,652 @@ nm_utils_ether_addr_equal (const struct ether_addr *a1, const struct ether_addr #define NM_UTILS_INET_ADDRSTRLEN INET6_ADDRSTRLEN static inline const char * -nm_utils_inet_ntop (int addr_family, gconstpointer addr, char *dst) +nm_utils_inet_ntop(int addr_family, gconstpointer addr, char *dst) { - const char *s; + const char *s; - const char *inet_ntop (int af, - const void *src, - char *dst, - socklen_t size); + const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); - nm_assert_addr_family (addr_family); - nm_assert (addr); - nm_assert (dst); + nm_assert_addr_family(addr_family); + nm_assert(addr); + nm_assert(dst); - s = inet_ntop (addr_family, - addr, - dst, - addr_family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN); - nm_assert (s); - return s; + s = inet_ntop(addr_family, + addr, + dst, + addr_family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN); + nm_assert(s); + return s; } static inline const char * -_nm_utils_inet4_ntop (in_addr_t addr, char dst[static INET_ADDRSTRLEN]) +_nm_utils_inet4_ntop(in_addr_t addr, char dst[static INET_ADDRSTRLEN]) { - return nm_utils_inet_ntop (AF_INET, &addr, dst); + return nm_utils_inet_ntop(AF_INET, &addr, dst); } static inline const char * -_nm_utils_inet6_ntop (const struct in6_addr *addr, char dst[static INET6_ADDRSTRLEN]) +_nm_utils_inet6_ntop(const struct in6_addr *addr, char dst[static INET6_ADDRSTRLEN]) { - return nm_utils_inet_ntop (AF_INET6, addr, dst); + return nm_utils_inet_ntop(AF_INET6, addr, dst); } static inline char * -nm_utils_inet_ntop_dup (int addr_family, gconstpointer addr) +nm_utils_inet_ntop_dup(int addr_family, gconstpointer addr) { - char buf[NM_UTILS_INET_ADDRSTRLEN]; + char buf[NM_UTILS_INET_ADDRSTRLEN]; - return g_strdup (nm_utils_inet_ntop (addr_family, addr, buf)); + return g_strdup(nm_utils_inet_ntop(addr_family, addr, buf)); } static inline char * -nm_utils_inet4_ntop_dup (in_addr_t addr) +nm_utils_inet4_ntop_dup(in_addr_t addr) { - return nm_utils_inet_ntop_dup (AF_INET, &addr); + return nm_utils_inet_ntop_dup(AF_INET, &addr); } static inline char * -nm_utils_inet6_ntop_dup (const struct in6_addr *addr) +nm_utils_inet6_ntop_dup(const struct in6_addr *addr) { - return nm_utils_inet_ntop_dup (AF_INET6, addr); + return nm_utils_inet_ntop_dup(AF_INET6, addr); } /*****************************************************************************/ -gboolean nm_utils_ipaddr_is_valid (int addr_family, - const char *str_addr); +gboolean nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr); -gboolean nm_utils_ipaddr_is_normalized (int addr_family, - const char *str_addr); +gboolean nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr); /*****************************************************************************/ -#define NM_CMP_RETURN(c) \ - G_STMT_START { \ - const int _cc = (c); \ - if (_cc) \ - return _cc < 0 ? -1 : 1; \ - } G_STMT_END - -#define NM_CMP_RETURN_DIRECT(c) \ - G_STMT_START { \ - const int _cc = (c); \ - if (_cc) \ - return _cc; \ - } G_STMT_END - -#define NM_CMP_SELF(a, b) \ - G_STMT_START { \ - typeof (a) _a = (a); \ - typeof (b) _b = (b); \ - \ - if (_a == _b) \ - return 0; \ - if (!_a) \ - return -1; \ - if (!_b) \ - return 1; \ - } G_STMT_END - -#define NM_CMP_DIRECT(a, b) \ - G_STMT_START { \ - typeof (a) _a = (a); \ - typeof (b) _b = (b); \ - \ - if (_a != _b) \ - return (_a < _b) ? -1 : 1; \ - } G_STMT_END - -/* In the general case, direct pointer comparison is undefined behavior in C. - * Avoid that by casting pointers to void* and then to uintptr_t. This comparison - * is not really meaningful, except that it provides some kind of stable sort order - * between pointers (that can otherwise not be compared). */ -#define NM_CMP_DIRECT_PTR(a, b) \ - NM_CMP_DIRECT ((uintptr_t) ((void *) (a)), \ - (uintptr_t) ((void *) (b))) - -#define NM_CMP_DIRECT_MEMCMP(a, b, size) \ - NM_CMP_RETURN (memcmp ((a), (b), (size))) - -#define NM_CMP_DIRECT_STRCMP(a, b) \ - NM_CMP_RETURN_DIRECT (strcmp ((a), (b))) - -#define NM_CMP_DIRECT_STRCMP0(a, b) \ - NM_CMP_RETURN_DIRECT (nm_strcmp0 ((a), (b))) - -#define NM_CMP_DIRECT_IN6ADDR(a, b) \ - G_STMT_START { \ - const struct in6_addr *const _a = (a); \ - const struct in6_addr *const _b = (b); \ - NM_CMP_RETURN (memcmp (_a, _b, sizeof (struct in6_addr))); \ - } G_STMT_END - -#define NM_CMP_FIELD(a, b, field) \ - NM_CMP_DIRECT (((a)->field), ((b)->field)) - -#define NM_CMP_FIELD_UNSAFE(a, b, field) \ - G_STMT_START { \ - /* it's unsafe, because it evaluates the arguments more then once. - * This is necessary for bitfields, for which typeof() doesn't work. */ \ - if (((a)->field) != ((b)->field)) \ - return ((a)->field < ((b)->field)) ? -1 : 1; \ - } G_STMT_END - -#define NM_CMP_FIELD_BOOL(a, b, field) \ - NM_CMP_DIRECT (!!((a)->field), !!((b)->field)) - -#define NM_CMP_FIELD_STR(a, b, field) \ - NM_CMP_RETURN (strcmp (((a)->field), ((b)->field))) - -#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \ - G_STMT_START { \ - const char *_a = ((a)->field); \ - const char *_b = ((b)->field); \ - \ - if (_a != _b) { \ - NM_CMP_RETURN_DIRECT (nm_strcmp0 (_a, _b)); \ - } \ - } G_STMT_END - -#define NM_CMP_FIELD_STR0(a, b, field) \ - NM_CMP_RETURN_DIRECT (nm_strcmp0 (((a)->field), ((b)->field))) - -#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \ - NM_CMP_RETURN (memcmp (&((a)->field), &((b)->field), \ - NM_MIN (len, sizeof ((a)->field)))) - -#define NM_CMP_FIELD_MEMCMP(a, b, field) \ - NM_CMP_RETURN (memcmp (&((a)->field), \ - &((b)->field), \ - sizeof ((a)->field))) - -#define NM_CMP_FIELD_IN6ADDR(a, b, field) \ - G_STMT_START { \ - const struct in6_addr *const _a = &((a)->field); \ - const struct in6_addr *const _b = &((b)->field); \ - NM_CMP_RETURN (memcmp (_a, _b, sizeof (struct in6_addr))); \ - } G_STMT_END - -/*****************************************************************************/ - -gboolean nm_utils_memeqzero (gconstpointer data, gsize length); +gboolean nm_utils_memeqzero(gconstpointer data, gsize length); /*****************************************************************************/ extern const void *const _NM_PTRARRAY_EMPTY[1]; -#define NM_PTRARRAY_EMPTY(type) ((type const*) _NM_PTRARRAY_EMPTY) +#define NM_PTRARRAY_EMPTY(type) ((type const *) _NM_PTRARRAY_EMPTY) static inline void -_nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len) +_nm_utils_strbuf_init(char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len) { - NM_SET_OUT (p_buf_len, len); - NM_SET_OUT (p_buf_ptr, buf); - buf[0] = '\0'; + NM_SET_OUT(p_buf_len, len); + NM_SET_OUT(p_buf_ptr, buf); + buf[0] = '\0'; } -#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len) \ - G_STMT_START { \ - G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) > sizeof (char *)); \ - _nm_utils_strbuf_init ((buf), sizeof (buf), (p_buf_ptr), (p_buf_len)); \ - } G_STMT_END -void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4); -void nm_utils_strbuf_append_c (char **buf, gsize *len, char c); -void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str); -void nm_utils_strbuf_append_bin (char **buf, gsize *len, gconstpointer str, gsize str_len); -void nm_utils_strbuf_seek_end (char **buf, gsize *len); +#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len) \ + G_STMT_START \ + { \ + G_STATIC_ASSERT(G_N_ELEMENTS(buf) == sizeof(buf) && sizeof(buf) > sizeof(char *)); \ + _nm_utils_strbuf_init((buf), sizeof(buf), (p_buf_ptr), (p_buf_len)); \ + } \ + G_STMT_END +void nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...) _nm_printf(3, 4); +void nm_utils_strbuf_append_c(char **buf, gsize *len, char c); +void nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str); +void nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len); +void nm_utils_strbuf_seek_end(char **buf, gsize *len); -const char *nm_strquote (char *buf, gsize buf_len, const char *str); +const char *nm_strquote(char *buf, gsize buf_len, const char *str); static inline gboolean -nm_utils_is_separator (const char c) +nm_utils_is_separator(const char c) { - return NM_IN_SET (c, ' ', '\t'); + return NM_IN_SET(c, ' ', '\t'); } /*****************************************************************************/ -GBytes *nm_gbytes_get_empty (void); +GBytes *nm_gbytes_get_empty(void); static inline gboolean -nm_gbytes_equal0 (GBytes *a, GBytes *b) +nm_gbytes_equal0(GBytes *a, GBytes *b) { - return a == b || (a && b && g_bytes_equal (a, b)); + return a == b || (a && b && g_bytes_equal(a, b)); } -gboolean nm_utils_gbytes_equal_mem (GBytes *bytes, - gconstpointer mem_data, - gsize mem_len); +gboolean nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len); -GVariant *nm_utils_gbytes_to_variant_ay (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_ass(GHashTable *strdict); +GVariant *nm_utils_strdict_to_variant_asv(GHashTable *strdict); /*****************************************************************************/ -GVariant *nm_utils_gvariant_vardict_filter (GVariant *src, - gboolean (*filter_fcn) (const char *key, - GVariant *val, - char **out_key, - GVariant **out_val, - gpointer user_data), - gpointer user_data); +GVariant *nm_utils_gvariant_vardict_filter(GVariant *src, + gboolean (*filter_fcn)(const char *key, + GVariant * val, + char ** out_key, + GVariant ** out_val, + gpointer user_data), + gpointer user_data); -GVariant * -nm_utils_gvariant_vardict_filter_drop_one (GVariant *src, - const char *key); +GVariant *nm_utils_gvariant_vardict_filter_drop_one(GVariant *src, const char *key); /*****************************************************************************/ static inline int -nm_utils_hexchar_to_int (char ch) +nm_utils_hexchar_to_int(char ch) { - G_STATIC_ASSERT_EXPR ('0' < 'A'); - G_STATIC_ASSERT_EXPR ('A' < 'a'); + G_STATIC_ASSERT_EXPR('0' < 'A'); + G_STATIC_ASSERT_EXPR('A' < 'a'); - if (ch >= '0') { - if (ch <= '9') - return ch - '0'; - if (ch >= 'A') { - if (ch <= 'F') - return ((int) ch) + (10 - (int) 'A'); - if (ch >= 'a' && ch <= 'f') - return ((int) ch) + (10 - (int) 'a'); - } - } - return -1; + if (ch >= '0') { + if (ch <= '9') + return ch - '0'; + if (ch >= 'A') { + if (ch <= 'F') + return ((int) ch) + (10 - (int) 'A'); + if (ch >= 'a' && ch <= 'f') + return ((int) ch) + (10 - (int) 'a'); + } + } + return -1; } /*****************************************************************************/ -const char *nm_utils_dbus_path_get_last_component (const char *dbus_path); +const char *nm_utils_dbus_path_get_last_component(const char *dbus_path); -int nm_utils_dbus_path_cmp (const char *dbus_path_a, const char *dbus_path_b); +int nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b); /*****************************************************************************/ typedef enum { - NM_UTILS_STRSPLIT_SET_FLAGS_NONE = 0, - - /* by default, strsplit will coalesce consecutive delimiters and remove - * them from the result. If this flag is present, empty values are preserved - * and returned. - * - * When combined with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets - * empty after strstrip(), it also gets removed. */ - NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0), - - /* %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed - * by a backslash are not treated as a separator. Such delimiters and their escape - * character are copied to the current word without unescaping them. In general, - * nm_utils_strsplit_set_full() does not remove any backslash escape characters - * and does no unescaping. It only considers them for skipping to split at - * an escaped delimiter. - * - * If this is combined with (or implied by %NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED), then - * the backslash escapes are removed from the result. - */ - NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1), - - /* If flag is set, does the same as g_strstrip() on the returned tokens. - * This will remove leading and trailing ascii whitespaces (g_ascii_isspace() - * and NM_ASCII_SPACES). - * - * - when combined with !%NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, - * empty tokens will be removed (and %NULL will be returned if that - * results in an empty string array). - * - when combined with %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING, - * trailing whitespace escaped by backslash are not stripped. */ - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2), - - /* This implies %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING. - * - * This will do a final run over all tokens and remove all backslash - * escape characters that - * - precede a delimiter. - * - precede a backslash. - * - preceed a whitespace (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). - * - * Note that with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, it is only - * necessary to escape the very last whitespace (if the delimiters - * are not whitespace themself). So, technically, it would be sufficient - * to only unescape a backslash before the last whitespace and the user - * still could express everything. However, such a rule would be complicated - * to understand, so when using backslash escaping with nm_utils_strsplit_set_full(), - * then all characters (including backslash) are treated verbatim, except: - * - * - "\\$DELIMITER" (escaped delimiter) - * - "\\\\" (escaped backslash) - * - "\\$SPACE" (escaped space) (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). - * - * Note that all other escapes like "\\n" or "\\001" are left alone. - * That makes the escaping/unescaping rules simple. Also, for the most part - * a text is just taken as-is, with little additional rules. Only backslashes - * need extra care, and then only if they proceed one of the relevant characters. - */ - NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3), + NM_UTILS_STRSPLIT_SET_FLAGS_NONE = 0, + + /* by default, strsplit will coalesce consecutive delimiters and remove + * them from the result. If this flag is present, empty values are preserved + * and returned. + * + * When combined with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets + * empty after strstrip(), it also gets removed. */ + NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0), + + /* %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed + * by a backslash are not treated as a separator. Such delimiters and their escape + * character are copied to the current word without unescaping them. In general, + * nm_utils_strsplit_set_full() does not remove any backslash escape characters + * and does no unescaping. It only considers them for skipping to split at + * an escaped delimiter. + * + * If this is combined with (or implied by %NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED), then + * the backslash escapes are removed from the result. + */ + NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1), + + /* If flag is set, does the same as g_strstrip() on the returned tokens. + * This will remove leading and trailing ascii whitespaces (g_ascii_isspace() + * and NM_ASCII_SPACES). + * + * - when combined with !%NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY, + * empty tokens will be removed (and %NULL will be returned if that + * results in an empty string array). + * - when combined with %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING, + * trailing whitespace escaped by backslash are not stripped. */ + NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2), + + /* This implies %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING. + * + * This will do a final run over all tokens and remove all backslash + * escape characters that + * - precede a delimiter. + * - precede a backslash. + * - preceed a whitespace (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). + * + * Note that with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, it is only + * necessary to escape the very last whitespace (if the delimiters + * are not whitespace themself). So, technically, it would be sufficient + * to only unescape a backslash before the last whitespace and the user + * still could express everything. However, such a rule would be complicated + * to understand, so when using backslash escaping with nm_utils_strsplit_set_full(), + * then all characters (including backslash) are treated verbatim, except: + * + * - "\\$DELIMITER" (escaped delimiter) + * - "\\\\" (escaped backslash) + * - "\\$SPACE" (escaped space) (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP). + * + * Note that all other escapes like "\\n" or "\\001" are left alone. + * That makes the escaping/unescaping rules simple. Also, for the most part + * a text is just taken as-is, with little additional rules. Only backslashes + * need extra care, and then only if they proceed one of the relevant characters. + */ + NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3), } NMUtilsStrsplitSetFlags; -const char **nm_utils_strsplit_set_full (const char *str, - const char *delimiter, - NMUtilsStrsplitSetFlags flags); +const char ** +nm_utils_strsplit_set_full(const char *str, const char *delimiter, NMUtilsStrsplitSetFlags flags); static inline const char ** -nm_utils_strsplit_set_with_empty (const char *str, - const char *delimiters) +nm_utils_strsplit_set_with_empty(const char *str, const char *delimiters) { - /* this returns the same result as g_strsplit_set(str, delimiters, -1), except - * it does not deep-clone the strv array. - * Also, for @str == "", this returns %NULL while g_strsplit_set() would return - * an empty strv array. */ - return nm_utils_strsplit_set_full (str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); + /* this returns the same result as g_strsplit_set(str, delimiters, -1), except + * it does not deep-clone the strv array. + * Also, for @str == "", this returns %NULL while g_strsplit_set() would return + * an empty strv array. */ + return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY); } static inline const char ** -nm_utils_strsplit_set (const char *str, - const char *delimiters) +nm_utils_strsplit_set(const char *str, const char *delimiters) { - return nm_utils_strsplit_set_full (str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_NONE); + return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_NONE); } -gssize nm_utils_strv_find_first (char **list, gssize len, const char *needle); +gssize nm_utils_strv_find_first(char **list, gssize len, const char *needle); -char **_nm_utils_strv_cleanup (char **strv, - gboolean strip_whitespace, - gboolean skip_empty, - gboolean skip_repeated); +char **_nm_utils_strv_cleanup(char ** strv, + gboolean strip_whitespace, + gboolean skip_empty, + gboolean skip_repeated); + +/*****************************************************************************/ + +static inline gpointer +nm_copy_func_g_strdup(gconstpointer arg, gpointer user_data) +{ + return g_strdup(arg); +} /*****************************************************************************/ static inline const char ** -nm_utils_escaped_tokens_split (const char *str, - const char *delimiters) +nm_utils_escaped_tokens_split(const char *str, const char *delimiters) { - return nm_utils_strsplit_set_full (str, - delimiters, - NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED - | NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); + return nm_utils_strsplit_set_full(str, + delimiters, + NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED + | NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); } typedef enum { - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_NONE = 0, - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES = (1ull << 0), - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE = (1ull << 1), - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE = (1ull << 2), - - /* Backslash characters will be escaped as "\\\\" if they precede another - * character that makes it necessary. Such characters are: - * - * 1) before another '\\' backslash. - * 2) before any delimiter in @delimiters. - * 3) before any delimiter in @delimiters_as_needed. - * 4) before a white space, if ESCAPE_LEADING_SPACE or ESCAPE_TRAILING_SPACE is set. - * 5) before the end of the word - * - * Rule 4) is an extension. It's not immediately clear why with ESCAPE_LEADING_SPACE - * and ESCAPE_TRAILING_SPACE we want *all* backslashes before a white space escaped. - * The reason is, that we obviously want to use ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE - * in cases, where we later parse the backslash escaped strings back, but allowing to strip - * unescaped white spaces. That means, we want that " a " gets escaped as "\\ a\\ ". - * On the other hand, we also want that " a\\ b " gets escaped as "\\ a\\\\ b\\ ", - * and not "\\ a\\ b\\ ". Because otherwise, the parser would need to treat "\\ " - * differently depending on whether the sequence is at the beginning, end or middle - * of the word. - * - * Rule 5) is also not immediately obvious. When used with ESCAPE_TRAILING_SPACE, - * we clearly want to allow that an escaped word can have arbitrary - * whitespace suffixes. That's why this mode exists. So we must escape "a\\" as - * "a\\\\", so that appending " " does not change the meaning. - * Also without ESCAPE_TRAILING_SPACE, we want in general that we can concatenate - * two escaped words without changing their meaning. If the words would be "a\\" - * and "," (with ',' being a delimiter), then the result must be "a\\\\" and "\\," - * so that the concatenated word ("a\\\\\\,") is still the same. If we would escape - * them instead as "a\\" + "\\,", then the concatenated word would be "a\\\\," and - * different. - * */ - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED = (1ull << 3), - - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS = (1ull << 4), + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_NONE = 0, + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES = (1ull << 0), + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE = (1ull << 1), + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE = (1ull << 2), + + /* Backslash characters will be escaped as "\\\\" if they precede another + * character that makes it necessary. Such characters are: + * + * 1) before another '\\' backslash. + * 2) before any delimiter in @delimiters. + * 3) before any delimiter in @delimiters_as_needed. + * 4) before a white space, if ESCAPE_LEADING_SPACE or ESCAPE_TRAILING_SPACE is set. + * 5) before the end of the word + * + * Rule 4) is an extension. It's not immediately clear why with ESCAPE_LEADING_SPACE + * and ESCAPE_TRAILING_SPACE we want *all* backslashes before a white space escaped. + * The reason is, that we obviously want to use ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE + * in cases, where we later parse the backslash escaped strings back, but allowing to strip + * unescaped white spaces. That means, we want that " a " gets escaped as "\\ a\\ ". + * On the other hand, we also want that " a\\ b " gets escaped as "\\ a\\\\ b\\ ", + * and not "\\ a\\ b\\ ". Because otherwise, the parser would need to treat "\\ " + * differently depending on whether the sequence is at the beginning, end or middle + * of the word. + * + * Rule 5) is also not immediately obvious. When used with ESCAPE_TRAILING_SPACE, + * we clearly want to allow that an escaped word can have arbitrary + * whitespace suffixes. That's why this mode exists. So we must escape "a\\" as + * "a\\\\", so that appending " " does not change the meaning. + * Also without ESCAPE_TRAILING_SPACE, we want in general that we can concatenate + * two escaped words without changing their meaning. If the words would be "a\\" + * and "," (with ',' being a delimiter), then the result must be "a\\\\" and "\\," + * so that the concatenated word ("a\\\\\\,") is still the same. If we would escape + * them instead as "a\\" + "\\,", then the concatenated word would be "a\\\\," and + * different. + * */ + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED = (1ull << 3), + + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS = (1ull << 4), } NMUtilsEscapedTokensEscapeFlags; -const char *nm_utils_escaped_tokens_escape_full (const char *str, - const char *delimiters, - const char *delimiters_as_needed, - NMUtilsEscapedTokensEscapeFlags flags, - char **out_to_free); +const char *nm_utils_escaped_tokens_escape_full(const char *str, + const char *delimiters, + const char *delimiters_as_needed, + NMUtilsEscapedTokensEscapeFlags flags, + char ** out_to_free); static inline const char * -nm_utils_escaped_tokens_escape (const char *str, - const char *delimiters, - char **out_to_free) +nm_utils_escaped_tokens_escape(const char *str, const char *delimiters, char **out_to_free) { - return nm_utils_escaped_tokens_escape_full (str, - delimiters, - NULL, - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE, - out_to_free); + return nm_utils_escaped_tokens_escape_full( + str, + delimiters, + NULL, + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE, + 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); - - { - gs_free char *str_to_free = NULL; - const char *str0; - - str0 = nm_utils_escaped_tokens_escape (str, delimiters, &str_to_free); - nm_assert (str0 == str); - nm_assert (!str_to_free); - } + nm_assert(str); + nm_assert(delimiters); + + { + gs_free char *str_to_free = NULL; + const char * str0; + + str0 = nm_utils_escaped_tokens_escape(str, delimiters, &str_to_free); + nm_assert(str0 == str); + nm_assert(!str_to_free); + } #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 * -nm_utils_escaped_tokens_escape_gstr (const char *str, - const char *delimiters, - GString *gstring) +nm_utils_escaped_tokens_escape_gstr(const char *str, const char *delimiters, GString *gstring) { - gs_free char *str_to_free = NULL; + gs_free char *str_to_free = NULL; - nm_assert (str); - nm_assert (gstring); + nm_assert(str); + nm_assert(gstring); - g_string_append (gstring, - nm_utils_escaped_tokens_escape (str, delimiters, &str_to_free)); - return gstring; + g_string_append(gstring, nm_utils_escaped_tokens_escape(str, delimiters, &str_to_free)); + return gstring; } /*****************************************************************************/ -char **nm_utils_strsplit_quoted (const char *str); +char **nm_utils_strsplit_quoted(const char *str); /*****************************************************************************/ static inline const char ** -nm_utils_escaped_tokens_options_split_list (const char *str) +nm_utils_escaped_tokens_options_split_list(const char *str) { - return nm_utils_strsplit_set_full (str, - ",", - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP - | NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); + return nm_utils_strsplit_set_full(str, + ",", + NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP + | NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING); } -void nm_utils_escaped_tokens_options_split (char *str, - const char **out_key, - const char **out_val); +void nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val); static inline const char * -nm_utils_escaped_tokens_options_escape_key (const char *key, - char **out_to_free) +nm_utils_escaped_tokens_options_escape_key(const char *key, char **out_to_free) { - return nm_utils_escaped_tokens_escape_full (key, - ",=", - NULL, - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE, - out_to_free); + return nm_utils_escaped_tokens_escape_full( + key, + ",=", + NULL, + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE, + out_to_free); } static inline const char * -nm_utils_escaped_tokens_options_escape_val (const char *val, - char **out_to_free) +nm_utils_escaped_tokens_options_escape_val(const char *val, char **out_to_free) { - return nm_utils_escaped_tokens_escape_full (val, - ",", - "=", - NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE - | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE, - out_to_free); + return nm_utils_escaped_tokens_escape_full( + val, + ",", + "=", + NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE + | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE, + out_to_free); } /*****************************************************************************/ -#define NM_UTILS_CHECKSUM_LENGTH_MD5 16 -#define NM_UTILS_CHECKSUM_LENGTH_SHA1 20 -#define NM_UTILS_CHECKSUM_LENGTH_SHA256 32 - -#define nm_utils_checksum_get_digest(sum, arr) \ - G_STMT_START { \ - GChecksum *const _sum = (sum); \ - gsize _len; \ - \ - G_STATIC_ASSERT_EXPR ( sizeof (arr) == NM_UTILS_CHECKSUM_LENGTH_MD5 \ - || sizeof (arr) == NM_UTILS_CHECKSUM_LENGTH_SHA1 \ - || sizeof (arr) == NM_UTILS_CHECKSUM_LENGTH_SHA256); \ - G_STATIC_ASSERT_EXPR (sizeof (arr) == G_N_ELEMENTS (arr)); \ - \ - nm_assert (_sum); \ - \ - _len = G_N_ELEMENTS (arr); \ - \ - g_checksum_get_digest (_sum, (arr), &_len); \ - nm_assert (_len == G_N_ELEMENTS (arr)); \ - } G_STMT_END - -#define nm_utils_checksum_get_digest_len(sum, buf, len) \ - G_STMT_START { \ - GChecksum *const _sum = (sum); \ - const gsize _len0 = (len); \ - gsize _len; \ - \ - nm_assert (NM_IN_SET (_len0, NM_UTILS_CHECKSUM_LENGTH_MD5, \ - NM_UTILS_CHECKSUM_LENGTH_SHA1, \ - NM_UTILS_CHECKSUM_LENGTH_SHA256)); \ - nm_assert (_sum); \ - \ - _len = _len0; \ - g_checksum_get_digest (_sum, (buf), &_len); \ - nm_assert (_len == _len0); \ - } G_STMT_END +#define NM_UTILS_CHECKSUM_LENGTH_MD5 16 +#define NM_UTILS_CHECKSUM_LENGTH_SHA1 20 +#define NM_UTILS_CHECKSUM_LENGTH_SHA256 32 + +#define nm_utils_checksum_get_digest(sum, arr) \ + G_STMT_START \ + { \ + GChecksum *const _sum = (sum); \ + gsize _len; \ + \ + G_STATIC_ASSERT_EXPR(sizeof(arr) == NM_UTILS_CHECKSUM_LENGTH_MD5 \ + || sizeof(arr) == NM_UTILS_CHECKSUM_LENGTH_SHA1 \ + || sizeof(arr) == NM_UTILS_CHECKSUM_LENGTH_SHA256); \ + G_STATIC_ASSERT_EXPR(sizeof(arr) == G_N_ELEMENTS(arr)); \ + \ + nm_assert(_sum); \ + \ + _len = G_N_ELEMENTS(arr); \ + \ + g_checksum_get_digest(_sum, (arr), &_len); \ + nm_assert(_len == G_N_ELEMENTS(arr)); \ + } \ + G_STMT_END + +#define nm_utils_checksum_get_digest_len(sum, buf, len) \ + G_STMT_START \ + { \ + GChecksum *const _sum = (sum); \ + const gsize _len0 = (len); \ + gsize _len; \ + \ + nm_assert(NM_IN_SET(_len0, \ + NM_UTILS_CHECKSUM_LENGTH_MD5, \ + NM_UTILS_CHECKSUM_LENGTH_SHA1, \ + NM_UTILS_CHECKSUM_LENGTH_SHA256)); \ + nm_assert(_sum); \ + \ + _len = _len0; \ + g_checksum_get_digest(_sum, (buf), &_len); \ + nm_assert(_len == _len0); \ + } \ + G_STMT_END /*****************************************************************************/ -guint32 _nm_utils_ip4_prefix_to_netmask (guint32 prefix); -guint32 _nm_utils_ip4_get_default_prefix (guint32 ip); +guint32 _nm_utils_ip4_prefix_to_netmask(guint32 prefix); +guint32 _nm_utils_ip4_get_default_prefix(guint32 ip); -gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen); -in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen); -const struct in6_addr *nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen); -int nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen); +gconstpointer +nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen); +in_addr_t nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint8 plen); +const struct in6_addr *nm_utils_ip6_address_clear_host_address(struct in6_addr * dst, + const struct in6_addr *src, + guint8 plen); +int nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a, + const struct in6_addr *addr_b, + guint8 plen); -gboolean nm_utils_ip_is_site_local (int addr_family, - const void *address); +gboolean nm_utils_ip_is_site_local(int addr_family, const void *address); /*****************************************************************************/ -gboolean nm_utils_parse_inaddr_bin_full (int addr_family, - gboolean accept_legacy, - const char *text, - int *out_addr_family, - gpointer out_addr); +gboolean nm_utils_parse_inaddr_bin_full(int addr_family, + gboolean accept_legacy, + const char *text, + int * out_addr_family, + gpointer out_addr); static inline gboolean -nm_utils_parse_inaddr_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr) +nm_utils_parse_inaddr_bin(int addr_family, + const char *text, + int * out_addr_family, + gpointer out_addr) { - return nm_utils_parse_inaddr_bin_full (addr_family, FALSE, text, out_addr_family, out_addr); + return nm_utils_parse_inaddr_bin_full(addr_family, FALSE, text, out_addr_family, out_addr); } -gboolean nm_utils_parse_inaddr (int addr_family, - const char *text, - char **out_addr); +gboolean nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr); -gboolean nm_utils_parse_inaddr_prefix_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr, - int *out_prefix); +gboolean nm_utils_parse_inaddr_prefix_bin(int addr_family, + const char *text, + int * out_addr_family, + gpointer out_addr, + int * out_prefix); -gboolean nm_utils_parse_inaddr_prefix (int addr_family, - const char *text, - char **out_addr, - int *out_prefix); +gboolean +nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix); -gboolean nm_utils_parse_next_line (const char **inout_ptr, - gsize *inout_len, - const char **out_line, - gsize *out_line_len); +gboolean nm_utils_parse_next_line(const char **inout_ptr, + gsize * inout_len, + const char **out_line, + gsize * out_line_len); -gint64 nm_g_ascii_strtoll (const char *nptr, - char **endptr, - guint base); +gint64 nm_g_ascii_strtoll(const char *nptr, char **endptr, guint base); -guint64 nm_g_ascii_strtoull (const char *nptr, - char **endptr, - guint base); +guint64 nm_g_ascii_strtoull(const char *nptr, char **endptr, guint base); -double nm_g_ascii_strtod (const char *nptr, - char **endptr); +double nm_g_ascii_strtod(const char *nptr, char **endptr); -gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback); -guint64 _nm_utils_ascii_str_to_uint64 (const char *str, guint base, guint64 min, guint64 max, guint64 fallback); +gint64 +_nm_utils_ascii_str_to_int64(const char *str, guint base, gint64 min, gint64 max, gint64 fallback); +guint64 _nm_utils_ascii_str_to_uint64(const char *str, + guint base, + guint64 min, + guint64 max, + guint64 fallback); -int _nm_utils_ascii_str_to_bool (const char *str, - int default_value); +int _nm_utils_ascii_str_to_bool(const char *str, int default_value); /*****************************************************************************/ extern char _nm_utils_to_string_buffer[2096]; -void nm_utils_to_string_buffer_init (char **buf, gsize *len); -gboolean nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len); +void nm_utils_to_string_buffer_init(char **buf, gsize *len); +gboolean nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len); /*****************************************************************************/ typedef struct { - unsigned flag; - const char *name; + unsigned flag; + const char *name; } NMUtilsFlags2StrDesc; -#define NM_UTILS_FLAGS2STR(f, n) { .flag = f, .name = ""n, } - -#define NM_UTILS_FLAGS2STR_DEFINE(fcn_name, flags_type, ...) \ -const char * \ -fcn_name (flags_type flags, char *buf, gsize len) \ -{ \ - static const NMUtilsFlags2StrDesc descs[] = { \ - __VA_ARGS__ \ - }; \ - G_STATIC_ASSERT (sizeof (flags_type) <= sizeof (unsigned)); \ - return nm_utils_flags2str (descs, G_N_ELEMENTS (descs), flags, buf, len); \ -}; - -const char *nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, - gsize n_descs, - unsigned flags, - char *buf, - gsize len); +#define NM_UTILS_FLAGS2STR(f, n) \ + { \ + .flag = f, .name = "" n, \ + } + +#define NM_UTILS_FLAGS2STR_DEFINE(fcn_name, flags_type, ...) \ + const char *fcn_name(flags_type flags, char *buf, gsize len) \ + { \ + static const NMUtilsFlags2StrDesc descs[] = {__VA_ARGS__}; \ + G_STATIC_ASSERT(sizeof(flags_type) <= sizeof(unsigned)); \ + return nm_utils_flags2str(descs, G_N_ELEMENTS(descs), flags, buf, len); \ + }; + +const char *nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs, + gsize n_descs, + unsigned flags, + char * buf, + gsize len); /*****************************************************************************/ -#define NM_UTILS_ENUM2STR(v, n) (void) 0; case v: s = ""n""; break; (void) 0 -#define NM_UTILS_ENUM2STR_IGNORE(v) (void) 0; case v: break; (void) 0 +#define NM_UTILS_ENUM2STR(v, n) \ + (void) 0; \ +case v: \ + s = "" n ""; \ + break; \ + (void) 0 +#define NM_UTILS_ENUM2STR_IGNORE(v) \ + (void) 0; \ +case v: \ + break; \ + (void) 0 #define NM_UTILS_ENUM2STR_DEFINE_FULL(fcn_name, lookup_type, int_fmt, ...) \ -const char * \ -fcn_name (lookup_type val, char *buf, gsize len) \ -{ \ - nm_utils_to_string_buffer_init (&buf, &len); \ - if (len) { \ - const char *s = NULL; \ - switch (val) { \ - (void) 0, \ - __VA_ARGS__ \ - (void) 0; \ - }; \ - if (s) \ - g_strlcpy (buf, s, len); \ - else \ - g_snprintf (buf, len, "(%"int_fmt")", val); \ - } \ - return buf; \ -} + const char *fcn_name(lookup_type val, char *buf, gsize len) \ + { \ + nm_utils_to_string_buffer_init(&buf, &len); \ + if (len) { \ + const char *s = NULL; \ + switch (val) { \ + (void) 0, __VA_ARGS__(void) 0; \ + }; \ + if (s) \ + g_strlcpy(buf, s, len); \ + else \ + g_snprintf(buf, len, "(%" int_fmt ")", val); \ + } \ + return buf; \ + } #define NM_UTILS_ENUM2STR_DEFINE(fcn_name, lookup_type, ...) \ - NM_UTILS_ENUM2STR_DEFINE_FULL (fcn_name, lookup_type, "d", __VA_ARGS__) + NM_UTILS_ENUM2STR_DEFINE_FULL(fcn_name, lookup_type, "d", __VA_ARGS__) /*****************************************************************************/ -#define _nm_g_slice_free_fcn_define(mem_size) \ -static inline void \ -_nm_g_slice_free_fcn_##mem_size (gpointer mem_block) \ -{ \ - g_slice_free1 (mem_size, mem_block); \ -} - -_nm_g_slice_free_fcn_define (1) -_nm_g_slice_free_fcn_define (2) -_nm_g_slice_free_fcn_define (4) -_nm_g_slice_free_fcn_define (8) -_nm_g_slice_free_fcn_define (10) -_nm_g_slice_free_fcn_define (12) -_nm_g_slice_free_fcn_define (16) -_nm_g_slice_free_fcn_define (32) - -#define nm_g_slice_free_fcn1(mem_size) \ - ({ \ - void (*_fcn) (gpointer); \ - \ - /* If mem_size is a compile time constant, the compiler - * will be able to optimize this. Hence, you don't want - * to call this with a non-constant size argument. */ \ - G_STATIC_ASSERT_EXPR ( ((mem_size) == 1) \ - || ((mem_size) == 2) \ - || ((mem_size) == 4) \ - || ((mem_size) == 8) \ - || ((mem_size) == 10) \ - || ((mem_size) == 12) \ - || ((mem_size) == 16) \ - || ((mem_size) == 32)); \ - switch ((mem_size)) { \ - case 1: _fcn = _nm_g_slice_free_fcn_1; break; \ - case 2: _fcn = _nm_g_slice_free_fcn_2; break; \ - case 4: _fcn = _nm_g_slice_free_fcn_4; break; \ - case 8: _fcn = _nm_g_slice_free_fcn_8; break; \ - case 10: _fcn = _nm_g_slice_free_fcn_10; break; \ - case 12: _fcn = _nm_g_slice_free_fcn_12; break; \ - case 16: _fcn = _nm_g_slice_free_fcn_16; break; \ - case 32: _fcn = _nm_g_slice_free_fcn_32; break; \ - default: g_assert_not_reached (); _fcn = NULL; break; \ - } \ - _fcn; \ - }) +#define _nm_g_slice_free_fcn_define(mem_size) \ + static inline void _nm_g_slice_free_fcn_##mem_size(gpointer mem_block) \ + { \ + g_slice_free1(mem_size, mem_block); \ + } + +_nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_fcn_define(4) + _nm_g_slice_free_fcn_define(8) _nm_g_slice_free_fcn_define(10) _nm_g_slice_free_fcn_define(12) + _nm_g_slice_free_fcn_define(16) _nm_g_slice_free_fcn_define(32) + +#define nm_g_slice_free_fcn1(mem_size) \ + ({ \ + void (*_fcn)(gpointer); \ + \ + /* If mem_size is a compile time constant, the compiler + * will be able to optimize this. Hence, you don't want + * to call this with a non-constant size argument. */ \ + G_STATIC_ASSERT_EXPR(((mem_size) == 1) || ((mem_size) == 2) || ((mem_size) == 4) \ + || ((mem_size) == 8) || ((mem_size) == 10) || ((mem_size) == 12) \ + || ((mem_size) == 16) || ((mem_size) == 32)); \ + switch ((mem_size)) { \ + case 1: \ + _fcn = _nm_g_slice_free_fcn_1; \ + break; \ + case 2: \ + _fcn = _nm_g_slice_free_fcn_2; \ + break; \ + case 4: \ + _fcn = _nm_g_slice_free_fcn_4; \ + break; \ + case 8: \ + _fcn = _nm_g_slice_free_fcn_8; \ + break; \ + case 10: \ + _fcn = _nm_g_slice_free_fcn_10; \ + break; \ + case 12: \ + _fcn = _nm_g_slice_free_fcn_12; \ + break; \ + case 16: \ + _fcn = _nm_g_slice_free_fcn_16; \ + break; \ + case 32: \ + _fcn = _nm_g_slice_free_fcn_32; \ + break; \ + default: \ + g_assert_not_reached(); \ + _fcn = NULL; \ + break; \ + } \ + _fcn; \ + }) /** * nm_g_slice_free_fcn: @@ -947,9 +866,9 @@ _nm_g_slice_free_fcn_define (32) * * Only certain types are implemented. You'll get a compile time * error for the wrong types. */ -#define nm_g_slice_free_fcn(type) (nm_g_slice_free_fcn1 (sizeof (type))) +#define nm_g_slice_free_fcn(type) (nm_g_slice_free_fcn1(sizeof(type))) -#define nm_g_slice_free_fcn_gint64 (nm_g_slice_free_fcn (gint64)) +#define nm_g_slice_free_fcn_gint64 (nm_g_slice_free_fcn(gint64)) /*****************************************************************************/ @@ -959,44 +878,43 @@ _nm_g_slice_free_fcn_define (32) * be inlined. This macro calls the getter only if there is an error (lazy). * - accept a list of allowed codes, instead of only one. */ -#define nm_g_error_matches(error, err_domain, ...) \ - ({ \ - const GError *const _error = (error); \ - \ - _error \ - && _error->domain == (err_domain) \ - && NM_IN_SET (_error->code, __VA_ARGS__); \ - }) - -static inline void -nm_g_set_error_take (GError **error, GError *error_take) -{ - if (!error_take) - g_return_if_reached (); - if (!error) { - g_error_free (error_take); - return; - } - if (*error) { - g_error_free (error_take); - g_return_if_reached (); - } - *error = error_take; -} - -#define nm_g_set_error_take_lazy(error, error_take_lazy) \ - G_STMT_START { \ - GError **_error = (error); \ - \ - if (_error) \ - nm_g_set_error_take (_error, (error_take_lazy)); \ - } G_STMT_END +#define nm_g_error_matches(error, err_domain, ...) \ + ({ \ + const GError *const _error = (error); \ + \ + _error && _error->domain == (err_domain) && NM_IN_SET(_error->code, __VA_ARGS__); \ + }) + + static inline void nm_g_set_error_take(GError **error, GError *error_take) +{ + if (!error_take) + g_return_if_reached(); + if (!error) { + g_error_free(error_take); + return; + } + if (*error) { + g_error_free(error_take); + g_return_if_reached(); + } + *error = error_take; +} + +#define nm_g_set_error_take_lazy(error, error_take_lazy) \ + G_STMT_START \ + { \ + GError **_error = (error); \ + \ + if (_error) \ + nm_g_set_error_take(_error, (error_take_lazy)); \ + } \ + G_STMT_END /** * 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. @@ -1017,606 +935,705 @@ nm_g_set_error_take (GError **error, GError *error_take) * @NM_UTILS_ERROR_INVALID_ARGUMENT: invalid argument. */ typedef enum { - NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ - NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/ - NM_UTILS_ERROR_INVALID_ARGUMENT, /*< nick=InvalidArgument >*/ - - /* the following codes have a special meaning and are exactly used for - * nm_device_check_connection_compatible() and nm_device_check_connection_available(). - * - * Actually, their meaning is not very important (so, don't think too - * hard about the name of these error codes). What is important, is their - * relative order (i.e. the integer value of the codes). When manager - * searches for a suitable device, it will check all devices whether - * a profile can be activated. If they all fail, it will pick the error - * message from the device that returned the *highest* error code, - * in the hope that this message makes the most sense for the caller. - * */ - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - - NM_UTILS_ERROR_SETTING_MISSING, + NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ + NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/ + NM_UTILS_ERROR_INVALID_ARGUMENT, /*< nick=InvalidArgument >*/ + + /* the following codes have a special meaning and are exactly used for + * nm_device_check_connection_compatible() and nm_device_check_connection_available(). + * + * Actually, their meaning is not very important (so, don't think too + * hard about the name of these error codes). What is important, is their + * relative order (i.e. the integer value of the codes). When manager + * searches for a suitable device, it will check all devices whether + * a profile can be activated. If they all fail, it will pick the error + * message from the device that returned the *highest* error code, + * in the hope that this message makes the most sense for the caller. + * */ + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + + NM_UTILS_ERROR_SETTING_MISSING, } NMUtilsError; -#define NM_UTILS_ERROR (nm_utils_error_quark ()) -GQuark nm_utils_error_quark (void); +#define NM_UTILS_ERROR (nm_utils_error_quark()) +GQuark nm_utils_error_quark(void); -void nm_utils_error_set_cancelled (GError **error, - gboolean is_disposing, - const char *instance_name); +void nm_utils_error_set_cancelled(GError **error, gboolean is_disposing, const char *instance_name); static inline GError * -nm_utils_error_new_cancelled (gboolean is_disposing, - const char *instance_name) +nm_utils_error_new_cancelled(gboolean is_disposing, const char *instance_name) { - GError *error = NULL; + GError *error = NULL; - nm_utils_error_set_cancelled (&error, is_disposing, instance_name); - return error; + nm_utils_error_set_cancelled(&error, is_disposing, instance_name); + return error; } -gboolean nm_utils_error_is_cancelled_or_disposing (GError *error); +gboolean nm_utils_error_is_cancelled_or_disposing(GError *error); static inline gboolean -nm_utils_error_is_cancelled (GError *error) +nm_utils_error_is_cancelled(GError *error) { - return error - && error->code == G_IO_ERROR_CANCELLED - && error->domain == G_IO_ERROR; + return error && error->code == G_IO_ERROR_CANCELLED && error->domain == G_IO_ERROR; } -gboolean nm_utils_error_is_notfound (GError *error); +gboolean nm_utils_error_is_notfound(GError *error); static inline void -nm_utils_error_set_literal (GError **error, int error_code, const char *literal) -{ - g_set_error_literal (error, NM_UTILS_ERROR, error_code, literal); -} - -#define nm_utils_error_set(error, error_code, ...) \ - G_STMT_START { \ - if (NM_NARG (__VA_ARGS__) == 1) { \ - g_set_error_literal ((error), NM_UTILS_ERROR, (error_code), _NM_UTILS_MACRO_FIRST (__VA_ARGS__)); \ - } else { \ - g_set_error ((error), NM_UTILS_ERROR, (error_code), __VA_ARGS__); \ - } \ - } G_STMT_END - -#define nm_utils_error_set_errno(error, errsv, fmt, ...) \ - G_STMT_START { \ - char _bstrerr[NM_STRERROR_BUFSIZE]; \ - \ - g_set_error ((error), \ - NM_UTILS_ERROR, \ - NM_UTILS_ERROR_UNKNOWN, \ - fmt, \ - ##__VA_ARGS__, \ - nm_strerror_native_r (({ \ - const int _errsv = (errsv); \ - \ - ( _errsv >= 0 \ - ? _errsv \ - : ( G_UNLIKELY (_errsv == G_MININT) \ - ? G_MAXINT \ - : -errsv)); \ - }), \ - _bstrerr, \ - sizeof (_bstrerr))); \ - } G_STMT_END - -#define nm_utils_error_new(error_code, ...) \ - ( (NM_NARG (__VA_ARGS__) == 1) \ - ? g_error_new_literal (NM_UTILS_ERROR, (error_code), _NM_UTILS_MACRO_FIRST (__VA_ARGS__)) \ - : g_error_new (NM_UTILS_ERROR, (error_code), __VA_ARGS__)) +nm_utils_error_set_literal(GError **error, int error_code, const char *literal) +{ + g_set_error_literal(error, NM_UTILS_ERROR, error_code, literal); +} + +#define nm_utils_error_set(error, error_code, ...) \ + G_STMT_START \ + { \ + if (NM_NARG(__VA_ARGS__) == 1) { \ + g_set_error_literal((error), \ + NM_UTILS_ERROR, \ + (error_code), \ + _NM_UTILS_MACRO_FIRST(__VA_ARGS__)); \ + } else { \ + g_set_error((error), NM_UTILS_ERROR, (error_code), __VA_ARGS__); \ + } \ + } \ + G_STMT_END + +#define nm_utils_error_set_errno(error, errsv, fmt, ...) \ + G_STMT_START \ + { \ + char _bstrerr[NM_STRERROR_BUFSIZE]; \ + \ + g_set_error((error), \ + NM_UTILS_ERROR, \ + NM_UTILS_ERROR_UNKNOWN, \ + fmt, \ + ##__VA_ARGS__, \ + nm_strerror_native_r( \ + ({ \ + const int _errsv = (errsv); \ + \ + (_errsv >= 0 ? _errsv \ + : (G_UNLIKELY(_errsv == G_MININT) ? G_MAXINT : -errsv)); \ + }), \ + _bstrerr, \ + sizeof(_bstrerr))); \ + } \ + G_STMT_END + +#define nm_utils_error_new(error_code, ...) \ + ((NM_NARG(__VA_ARGS__) == 1) \ + ? g_error_new_literal(NM_UTILS_ERROR, (error_code), _NM_UTILS_MACRO_FIRST(__VA_ARGS__)) \ + : g_error_new(NM_UTILS_ERROR, (error_code), __VA_ARGS__)) /*****************************************************************************/ -gboolean nm_g_object_set_property (GObject *object, - const char *property_name, - const GValue *value, - GError **error); - -gboolean nm_g_object_set_property_string (GObject *object, - const char *property_name, - const char *value, - GError **error); - -gboolean nm_g_object_set_property_string_static (GObject *object, - const char *property_name, - const char *value, - GError **error); +gboolean nm_g_object_set_property(GObject * object, + const char * property_name, + const GValue *value, + GError ** error); -gboolean nm_g_object_set_property_string_take (GObject *object, - const char *property_name, - char *value, - GError **error); +gboolean nm_g_object_set_property_string(GObject * object, + const char *property_name, + const char *value, + GError ** error); -gboolean nm_g_object_set_property_boolean (GObject *object, - const char *property_name, - gboolean value, - GError **error); +gboolean nm_g_object_set_property_string_static(GObject * object, + const char *property_name, + const char *value, + GError ** error); -gboolean nm_g_object_set_property_char (GObject *object, - const char *property_name, - gint8 value, - GError **error); +gboolean nm_g_object_set_property_string_take(GObject * object, + const char *property_name, + char * value, + GError ** error); -gboolean nm_g_object_set_property_uchar (GObject *object, - const char *property_name, - guint8 value, - GError **error); +gboolean nm_g_object_set_property_boolean(GObject * object, + const char *property_name, + gboolean value, + GError ** error); -gboolean nm_g_object_set_property_int (GObject *object, +gboolean nm_g_object_set_property_char(GObject * object, const char *property_name, - int value, - GError **error); + gint8 value, + GError ** error); -gboolean nm_g_object_set_property_int64 (GObject *object, - const char *property_name, - gint64 value, - GError **error); +gboolean nm_g_object_set_property_uchar(GObject * object, + const char *property_name, + guint8 value, + GError ** error); + +gboolean +nm_g_object_set_property_int(GObject *object, const char *property_name, int value, GError **error); -gboolean nm_g_object_set_property_uint (GObject *object, +gboolean nm_g_object_set_property_int64(GObject * object, const char *property_name, - guint value, - GError **error); + gint64 value, + GError ** error); -gboolean nm_g_object_set_property_uint64 (GObject *object, - const char *property_name, - guint64 value, - GError **error); +gboolean nm_g_object_set_property_uint(GObject * object, + const char *property_name, + guint value, + GError ** error); -gboolean nm_g_object_set_property_flags (GObject *object, +gboolean nm_g_object_set_property_uint64(GObject * object, const char *property_name, - GType gtype, - guint value, - GError **error); + guint64 value, + GError ** error); -gboolean nm_g_object_set_property_enum (GObject *object, +gboolean nm_g_object_set_property_flags(GObject * object, const char *property_name, - GType gtype, - int value, - GError **error); + GType gtype, + guint value, + GError ** error); -GParamSpec *nm_g_object_class_find_property_from_gtype (GType gtype, - const char *property_name); - -/*****************************************************************************/ +gboolean nm_g_object_set_property_enum(GObject * object, + const char *property_name, + GType gtype, + int value, + GError ** error); -#define _NM_G_PARAM_SPEC_CAST(param_spec, _value_type, _c_type) \ - ({ \ - const GParamSpec *const _param_spec = (param_spec); \ - \ - nm_assert ( !_param_spec \ - || _param_spec->value_type == (_value_type)); \ - ((const _c_type *) _param_spec); \ - }) +GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char *property_name); -#define NM_G_PARAM_SPEC_CAST_BOOLEAN(param_spec) _NM_G_PARAM_SPEC_CAST (param_spec, G_TYPE_BOOLEAN, GParamSpecBoolean) -#define NM_G_PARAM_SPEC_CAST_UINT(param_spec) _NM_G_PARAM_SPEC_CAST (param_spec, G_TYPE_UINT, GParamSpecUInt) -#define NM_G_PARAM_SPEC_CAST_UINT64(param_spec) _NM_G_PARAM_SPEC_CAST (param_spec, G_TYPE_UINT64, GParamSpecUInt64) +/*****************************************************************************/ -#define NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(param_spec) (NM_G_PARAM_SPEC_CAST_BOOLEAN (NM_ENSURE_NOT_NULL (param_spec))->default_value) -#define NM_G_PARAM_SPEC_GET_DEFAULT_UINT(param_spec) (NM_G_PARAM_SPEC_CAST_UINT (NM_ENSURE_NOT_NULL (param_spec))->default_value) -#define NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(param_spec) (NM_G_PARAM_SPEC_CAST_UINT64 (NM_ENSURE_NOT_NULL (param_spec))->default_value) +#define _NM_G_PARAM_SPEC_CAST(param_spec, _value_type, _c_type) \ + ({ \ + const GParamSpec *const _param_spec = (param_spec); \ + \ + nm_assert(!_param_spec || _param_spec->value_type == (_value_type)); \ + ((const _c_type *) _param_spec); \ + }) + +#define NM_G_PARAM_SPEC_CAST_BOOLEAN(param_spec) \ + _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_BOOLEAN, GParamSpecBoolean) +#define NM_G_PARAM_SPEC_CAST_UINT(param_spec) \ + _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT, GParamSpecUInt) +#define NM_G_PARAM_SPEC_CAST_UINT64(param_spec) \ + _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT64, GParamSpecUInt64) + +#define NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(param_spec) \ + (NM_G_PARAM_SPEC_CAST_BOOLEAN(NM_ENSURE_NOT_NULL(param_spec))->default_value) +#define NM_G_PARAM_SPEC_GET_DEFAULT_UINT(param_spec) \ + (NM_G_PARAM_SPEC_CAST_UINT(NM_ENSURE_NOT_NULL(param_spec))->default_value) +#define NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(param_spec) \ + (NM_G_PARAM_SPEC_CAST_UINT64(NM_ENSURE_NOT_NULL(param_spec))->default_value) /*****************************************************************************/ -GType nm_g_type_find_implementing_class_for_property (GType gtype, - const char *pname); +GType nm_g_type_find_implementing_class_for_property(GType gtype, const char *pname); /*****************************************************************************/ typedef enum { - NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0, - - /* This flag only has an effect during escaping. */ - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001, - - /* This flag only has an effect during escaping. */ - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002, - - /* This flag only has an effect during escaping to ensure we - * don't leak secrets in memory. Note that during unescape we - * know the maximum result size from the beginning, and no - * reallocation happens. Thus, unescape always avoids leaking - * secrets already. */ - NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET = 0x0004, - - /* This flag only has an effect during unescaping. It means - * that non-escaped whitespaces (g_ascii_isspace()) will be - * stripped from the front and end of the string. Note that - * this flag is only useful for gracefully accepting user input - * with spaces. With this flag, escape and unescape may no longer - * yield the original input. */ - NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES = 0x0008, + NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0, + + /* This flag only has an effect during escaping. */ + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001, + + /* This flag only has an effect during escaping. */ + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002, + + /* This flag only has an effect during escaping to ensure we + * don't leak secrets in memory. Note that during unescape we + * know the maximum result size from the beginning, and no + * reallocation happens. Thus, unescape always avoids leaking + * secrets already. */ + NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET = 0x0004, + + /* This flag only has an effect during unescaping. It means + * that non-escaped whitespaces (g_ascii_isspace()) will be + * stripped from the front and end of the string. Note that + * this flag is only useful for gracefully accepting user input + * with spaces. With this flag, escape and unescape may no longer + * yield the original input. */ + NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES = 0x0008, } NMUtilsStrUtf8SafeFlags; -const char *nm_utils_buf_utf8safe_escape (gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags, char **to_free); -char *nm_utils_buf_utf8safe_escape_cp (gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags); -const char *nm_utils_buf_utf8safe_escape_bytes (GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free); -gconstpointer nm_utils_buf_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, gsize *out_len, gpointer *to_free); +const char *nm_utils_buf_utf8safe_escape(gconstpointer buf, + gssize buflen, + NMUtilsStrUtf8SafeFlags flags, + char ** to_free); +char * +nm_utils_buf_utf8safe_escape_cp(gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags); +const char * +nm_utils_buf_utf8safe_escape_bytes(GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free); +gconstpointer nm_utils_buf_utf8safe_unescape(const char * str, + NMUtilsStrUtf8SafeFlags flags, + gsize * out_len, + gpointer * to_free); -const char *nm_utils_str_utf8safe_escape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free); -const char *nm_utils_str_utf8safe_unescape (const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free); +const char * +nm_utils_str_utf8safe_escape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free); +const char * +nm_utils_str_utf8safe_unescape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free); -char *nm_utils_str_utf8safe_escape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags); -char *nm_utils_str_utf8safe_unescape_cp (const char *str, NMUtilsStrUtf8SafeFlags flags); +char *nm_utils_str_utf8safe_escape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags); +char *nm_utils_str_utf8safe_unescape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags); -char *nm_utils_str_utf8safe_escape_take (char *str, NMUtilsStrUtf8SafeFlags flags); +char *nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags); + +GVariant *nm_g_variant_singleton_u_0(void); static inline void -nm_g_variant_unref_floating (GVariant *var) -{ - /* often a function wants to keep a reference to an input variant. - * It uses g_variant_ref_sink() to either increase the ref-count, - * or take ownership of a possibly floating reference. - * - * If the function doesn't actually want to do anything with the - * input variant, it still must make sure that a passed in floating - * reference is consumed. Hence, this helper which: - * - * - does nothing if @var is not floating - * - unrefs (consumes) @var if it is floating. */ - if (g_variant_is_floating (var)) - g_variant_unref (var); -} - -#define nm_g_variant_lookup(dictionary, ...) \ - ({ \ - GVariant *const _dictionary = (dictionary); \ - \ - ( _dictionary \ - && g_variant_lookup (_dictionary, __VA_ARGS__)); \ - }) +nm_g_variant_unref_floating(GVariant *var) +{ + /* often a function wants to keep a reference to an input variant. + * It uses g_variant_ref_sink() to either increase the ref-count, + * or take ownership of a possibly floating reference. + * + * If the function doesn't actually want to do anything with the + * input variant, it still must make sure that a passed in floating + * reference is consumed. Hence, this helper which: + * + * - does nothing if @var is not floating + * - unrefs (consumes) @var if it is floating. */ + if (g_variant_is_floating(var)) + g_variant_unref(var); +} + +#define nm_g_variant_lookup(dictionary, ...) \ + ({ \ + GVariant *const _dictionary = (dictionary); \ + \ + (_dictionary && g_variant_lookup(_dictionary, __VA_ARGS__)); \ + }) static inline GVariant * -nm_g_variant_lookup_value (GVariant *dictionary, - const char *key, - const GVariantType *expected_type) +nm_g_variant_lookup_value(GVariant *dictionary, const char *key, const GVariantType *expected_type) { - return dictionary - ? g_variant_lookup_value (dictionary, key, expected_type) - : NULL; + return dictionary ? g_variant_lookup_value(dictionary, key, expected_type) : NULL; } static inline gboolean -nm_g_variant_is_of_type (GVariant *value, - const GVariantType *type) +nm_g_variant_is_of_type(GVariant *value, const GVariantType *type) { - return value - && g_variant_is_of_type (value, type); + return value && g_variant_is_of_type(value, type); } static inline void -nm_g_variant_builder_add_sv (GVariantBuilder *builder, const char *key, GVariant *val) +nm_g_variant_builder_add_sv(GVariantBuilder *builder, const char *key, GVariant *val) { - g_variant_builder_add (builder, "{sv}", key, val); + g_variant_builder_add(builder, "{sv}", key, val); } static inline void -nm_g_variant_builder_add_sv_bytearray (GVariantBuilder *builder, const char *key, const guint8 *arr, gsize len) +nm_g_variant_builder_add_sv_bytearray(GVariantBuilder *builder, + const char * key, + const guint8 * arr, + gsize len) { - g_variant_builder_add (builder, "{sv}", key, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, arr, len, 1)); + g_variant_builder_add(builder, + "{sv}", + key, + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, arr, len, 1)); } static inline void -nm_g_variant_builder_add_sv_uint32 (GVariantBuilder *builder, const char *key, guint32 val) +nm_g_variant_builder_add_sv_uint32(GVariantBuilder *builder, const char *key, guint32 val) { - nm_g_variant_builder_add_sv (builder, key, g_variant_new_uint32 (val)); + nm_g_variant_builder_add_sv(builder, key, g_variant_new_uint32(val)); } static inline void -nm_g_variant_builder_add_sv_str (GVariantBuilder *builder, const char *key, const char *str) +nm_g_variant_builder_add_sv_str(GVariantBuilder *builder, const char *key, const char *str) { - nm_g_variant_builder_add_sv (builder, key, g_variant_new_string (str)); + nm_g_variant_builder_add_sv(builder, key, g_variant_new_string(str)); } static inline void -nm_g_source_destroy_and_unref (GSource *source) +nm_g_source_destroy_and_unref(GSource *source) { - g_source_destroy (source); - g_source_unref (source); + g_source_destroy(source); + g_source_unref(source); } -#define nm_clear_g_source_inst(ptr) (nm_clear_pointer ((ptr), nm_g_source_destroy_and_unref)) +#define nm_clear_g_source_inst(ptr) (nm_clear_pointer((ptr), nm_g_source_destroy_and_unref)) -NM_AUTO_DEFINE_FCN0 (GSource *, _nm_auto_destroy_and_unref_gsource, nm_g_source_destroy_and_unref); +NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_destroy_and_unref_gsource, nm_g_source_destroy_and_unref); #define nm_auto_destroy_and_unref_gsource nm_auto(_nm_auto_destroy_and_unref_gsource) -NM_AUTO_DEFINE_FCN0 (GMainContext *, _nm_auto_pop_gmaincontext, g_main_context_pop_thread_default) -#define nm_auto_pop_gmaincontext nm_auto (_nm_auto_pop_gmaincontext) +NM_AUTO_DEFINE_FCN0(GMainContext *, _nm_auto_pop_gmaincontext, g_main_context_pop_thread_default); +#define nm_auto_pop_gmaincontext nm_auto(_nm_auto_pop_gmaincontext) static inline gboolean -nm_source_func_unref_gobject (gpointer user_data) -{ - nm_assert (G_IS_OBJECT (user_data)); - g_object_unref (user_data); - return G_SOURCE_REMOVE; -} - -GSource *nm_g_idle_source_new (int priority, - GSourceFunc func, - gpointer user_data, - GDestroyNotify destroy_notify); - -GSource *nm_g_timeout_source_new (guint timeout_msec, - int priority, - GSourceFunc func, - gpointer user_data, - GDestroyNotify destroy_notify); -GSource *nm_g_unix_fd_source_new (int fd, - GIOCondition io_condition, - int priority, - gboolean (*source_func) (int fd, - GIOCondition condition, - gpointer user_data), - gpointer user_data, - GDestroyNotify destroy_notify); -GSource *nm_g_unix_signal_source_new (int signum, - int priority, - GSourceFunc handler, - gpointer user_data, - GDestroyNotify notify); +nm_source_func_unref_gobject(gpointer user_data) +{ + nm_assert(G_IS_OBJECT(user_data)); + g_object_unref(user_data); + return G_SOURCE_REMOVE; +} + +GSource *nm_g_idle_source_new(int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify); + +GSource *nm_g_timeout_source_new(guint timeout_msec, + int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify); + +GSource *nm_g_timeout_source_new_seconds(guint timeout_sec, + int priority, + GSourceFunc func, + gpointer user_data, + GDestroyNotify destroy_notify); + +GSource * + nm_g_unix_fd_source_new(int fd, + GIOCondition io_condition, + int priority, + gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data), + gpointer user_data, + GDestroyNotify destroy_notify); +GSource *nm_g_unix_signal_source_new(int signum, + int priority, + GSourceFunc handler, + gpointer user_data, + GDestroyNotify notify); static inline GSource * -nm_g_source_attach (GSource *source, - GMainContext *context) +nm_g_source_attach(GSource *source, GMainContext *context) { - g_source_attach (source, context); - return source; + g_source_attach(source, context); + return source; } -NM_AUTO_DEFINE_FCN0 (GMainContext *, _nm_auto_unref_gmaincontext, g_main_context_unref) -#define nm_auto_unref_gmaincontext nm_auto (_nm_auto_unref_gmaincontext) +NM_AUTO_DEFINE_FCN0(GMainContext *, _nm_auto_unref_gmaincontext, g_main_context_unref); +#define nm_auto_unref_gmaincontext nm_auto(_nm_auto_unref_gmaincontext) static inline GMainContext * -nm_g_main_context_push_thread_default (GMainContext *context) +nm_g_main_context_push_thread_default(GMainContext *context) { - /* This function is to work together with nm_auto_pop_gmaincontext. */ - if (G_UNLIKELY (!context)) - context = g_main_context_default (); - g_main_context_push_thread_default (context); - return context; + /* This function is to work together with nm_auto_pop_gmaincontext. */ + if (G_UNLIKELY(!context)) + context = g_main_context_default(); + g_main_context_push_thread_default(context); + return context; } static inline gboolean -nm_g_main_context_is_thread_default (GMainContext *context) +nm_g_main_context_is_thread_default(GMainContext *context) { - GMainContext *cur_context; + GMainContext *cur_context; - cur_context = g_main_context_get_thread_default (); - if (cur_context == context) - return TRUE; + cur_context = g_main_context_get_thread_default(); + if (cur_context == context) + return TRUE; - if (G_UNLIKELY (!cur_context)) - cur_context = g_main_context_default (); - else if (G_UNLIKELY (!context)) - context = g_main_context_default (); - else - return FALSE; + if (G_UNLIKELY(!cur_context)) + cur_context = g_main_context_default(); + else if (G_UNLIKELY(!context)) + context = g_main_context_default(); + else + return FALSE; - return (cur_context == context); + return (cur_context == context); } static inline GMainContext * -nm_g_main_context_push_thread_default_if_necessary (GMainContext *context) +nm_g_main_context_push_thread_default_if_necessary(GMainContext *context) { - GMainContext *cur_context; + GMainContext *cur_context; - cur_context = g_main_context_get_thread_default (); - if (cur_context == context) - return NULL; + cur_context = g_main_context_get_thread_default(); + if (cur_context == context) + return NULL; - if (G_UNLIKELY (!cur_context)) { - cur_context = g_main_context_default (); - if (cur_context == context) - return NULL; - } else if (G_UNLIKELY (!context)) { - context = g_main_context_default (); - if (cur_context == context) - return NULL; - } + if (G_UNLIKELY(!cur_context)) { + cur_context = g_main_context_default(); + if (cur_context == context) + return NULL; + } else if (G_UNLIKELY(!context)) { + context = g_main_context_default(); + if (cur_context == context) + return NULL; + } - g_main_context_push_thread_default (context); - return context; + g_main_context_push_thread_default(context); + return context; } /*****************************************************************************/ static inline int -nm_utf8_collate0 (const char *a, const char *b) +nm_utf8_collate0(const char *a, const char *b) { - if (!a) - return !b ? 0 : -1; - if (!b) - return 1; - return g_utf8_collate (a, b); + if (!a) + return !b ? 0 : -1; + if (!b) + return 1; + return g_utf8_collate(a, b); } -int nm_strcmp_with_data (gconstpointer a, gconstpointer b, gpointer user_data); -int nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data); -int nm_strcmp0_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data); -int nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data); -int nm_cmp_int2ptr_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data); +int nm_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data); +int nm_strcmp_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data); +int nm_strcmp0_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data); +int nm_strcmp_ascii_case_with_data(gconstpointer a, gconstpointer b, gpointer user_data); +int nm_cmp_uint32_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data); +int nm_cmp_int2ptr_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data); /*****************************************************************************/ typedef struct { - const char *name; + const char *name; } NMUtilsNamedEntry; typedef struct { - union { - NMUtilsNamedEntry named_entry; - const char *name; - }; - union { - const char *value_str; - gconstpointer value_ptr; - }; + union { + NMUtilsNamedEntry named_entry; + const char * name; + }; + union { + const char *value_str; + 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); - -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); -} - -gssize nm_utils_named_value_list_find (const NMUtilsNamedValue *arr, - gsize len, - const char *name, - gboolean sorted); - -gboolean nm_utils_named_value_list_is_sorted (const NMUtilsNamedValue *arr, - gsize len, - gboolean accept_duplicates, - GCompareDataFunc compare_func, - gpointer user_data); - -void nm_utils_named_value_list_sort (NMUtilsNamedValue *arr, - gsize len, - GCompareDataFunc compare_func, - gpointer user_data); +#define NM_UTILS_NAMED_VALUE_INIT(n, v) \ + { \ + .name = (n), .value_ptr = (v) \ + } + +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); + +#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, + const char * name, + gboolean sorted); + +gboolean nm_utils_named_value_list_is_sorted(const NMUtilsNamedValue *arr, + gsize len, + gboolean accept_duplicates, + GCompareDataFunc compare_func, + gpointer user_data); + +void nm_utils_named_value_list_sort(NMUtilsNamedValue *arr, + gsize len, + GCompareDataFunc compare_func, + gpointer user_data); /*****************************************************************************/ -gpointer *nm_utils_hash_keys_to_array (GHashTable *hash, - GCompareDataFunc compare_func, - gpointer user_data, - guint *out_len); +gpointer *nm_utils_hash_keys_to_array(GHashTable * hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint * out_len); -gpointer *nm_utils_hash_values_to_array (GHashTable *hash, - GCompareDataFunc compare_func, - gpointer user_data, - guint *out_len); +gpointer *nm_utils_hash_values_to_array(GHashTable * hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint * out_len); static inline const char ** -nm_utils_strdict_get_keys (const GHashTable *hash, - gboolean sorted, - guint *out_length) +nm_utils_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length) { - return (const char **) nm_utils_hash_keys_to_array ((GHashTable *) hash, - sorted ? nm_strcmp_p_with_data : NULL, - NULL, - out_length); + return (const char **) nm_utils_hash_keys_to_array((GHashTable *) hash, + sorted ? nm_strcmp_p_with_data : NULL, + NULL, + out_length); } -gboolean nm_utils_hashtable_same_keys (const GHashTable *a, - const GHashTable *b); +gboolean nm_utils_hashtable_equal(const GHashTable *a, + const GHashTable *b, + GCompareDataFunc cmp_values, + gpointer user_data); -char **nm_utils_strv_make_deep_copied (const char **strv); +static inline gboolean +nm_utils_hashtable_same_keys(const GHashTable *a, const GHashTable *b) +{ + return nm_utils_hashtable_equal(a, b, NULL, NULL); +} + +int nm_utils_hashtable_cmp(const GHashTable *a, + const GHashTable *b, + gboolean do_fast_precheck, + GCompareDataFunc cmp_keys, + GCompareDataFunc cmp_values, + gpointer user_data); + +char **nm_utils_strv_make_deep_copied(const char **strv); -char **nm_utils_strv_make_deep_copied_n (const char **strv, gsize len); +char **nm_utils_strv_make_deep_copied_n(const char **strv, gsize len); static inline char ** -nm_utils_strv_make_deep_copied_nonnull (const char **strv) +nm_utils_strv_make_deep_copied_nonnull(const char **strv) { - return nm_utils_strv_make_deep_copied (strv) ?: g_new0 (char *, 1); + return nm_utils_strv_make_deep_copied(strv) ?: g_new0(char *, 1); } -char **nm_utils_strv_dup (gpointer strv, - gssize len, - gboolean deep_copied); +char **_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied); + +#define nm_utils_strv_dup(strv, len, deep_copied) \ + _nm_utils_strv_dup(NM_CAST_STRV_CC(strv), (len), (deep_copied)) + +const char **_nm_utils_strv_dup_packed(const char *const *strv, gssize len); + +#define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed(NM_CAST_STRV_CC(strv), (len)) /*****************************************************************************/ -GSList *nm_utils_g_slist_find_str (const GSList *list, - const char *needle); +GSList *nm_utils_g_slist_find_str(const GSList *list, const char *needle); -int nm_utils_g_slist_strlist_cmp (const GSList *a, const GSList *b); +int nm_utils_g_slist_strlist_cmp(const GSList *a, const GSList *b); -char *nm_utils_g_slist_strlist_join (const GSList *a, const char *separator); +char *nm_utils_g_slist_strlist_join(const GSList *a, const char *separator); /*****************************************************************************/ static inline guint -nm_g_array_len (const GArray *arr) +nm_g_array_len(const GArray *arr) { - return arr ? arr->len : 0u; + return arr ? arr->len : 0u; } +#define nm_g_array_append_new(arr, type) \ + ({ \ + GArray *const _arr = (arr); \ + guint _len; \ + \ + nm_assert(_arr); \ + _len = _arr->len; \ + nm_assert(_len < G_MAXUINT); \ + g_array_set_size(_arr, _len + 1u); \ + &g_array_index(arr, type, _len); \ + }) + /*****************************************************************************/ static inline guint -nm_g_ptr_array_len (const GPtrArray *arr) +nm_g_ptr_array_len(const GPtrArray *arr) { - return arr ? arr->len : 0u; + return arr ? arr->len : 0u; } +static inline gpointer * +nm_g_ptr_array_pdata(const GPtrArray *arr) +{ + return arr ? arr->pdata : NULL; +} + +GPtrArray *_nm_g_ptr_array_copy(GPtrArray * array, + GCopyFunc func, + gpointer user_data, + GDestroyNotify element_free_func); + +/** + * nm_g_ptr_array_copy: + * @array: the #GPtrArray to clone. + * @func: the copy function. + * @user_data: the user data for the copy function + * @element_free_func: the free function of the elements. @array MUST have + * the same element_free_func. This argument is only used on older + * glib, that doesn't support g_ptr_array_copy(). + * + * This is a replacement for g_ptr_array_copy(), which is not available + * before glib 2.62. Since GPtrArray does not allow to access the internal + * element_free_func, we cannot add a compatibility implementation of g_ptr_array_copy() + * and the user must provide a suitable destroy function. + * + * Note that the @element_free_func MUST correspond to free function set in @array. + */ +#if GLIB_CHECK_VERSION(2, 62, 0) + #define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ + ({ \ + _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; \ + g_ptr_array_copy((array), (func), (user_data)); \ + G_GNUC_END_IGNORE_DEPRECATIONS; \ + }) +#else + #define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \ + _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func)) +#endif + /*****************************************************************************/ static inline guint -nm_g_hash_table_size (GHashTable *hash) +nm_g_hash_table_size(GHashTable *hash) { - return hash ? g_hash_table_size (hash) : 0u; + return hash ? g_hash_table_size(hash) : 0u; } static inline gpointer -nm_g_hash_table_lookup (GHashTable *hash, gconstpointer key) +nm_g_hash_table_lookup(GHashTable *hash, gconstpointer key) { - return hash ? g_hash_table_lookup (hash, key) : NULL; + return hash ? g_hash_table_lookup(hash, key) : NULL; } static inline gboolean -nm_g_hash_table_remove (GHashTable *hash, gconstpointer key) +nm_g_hash_table_contains(GHashTable *hash, gconstpointer key) { - return hash ? g_hash_table_remove (hash, key) : FALSE; + return hash ? g_hash_table_contains(hash, key) : FALSE; +} + +static inline gboolean +nm_g_hash_table_remove(GHashTable *hash, gconstpointer key) +{ + return hash ? g_hash_table_remove(hash, key) : FALSE; } /*****************************************************************************/ -gssize nm_utils_ptrarray_find_binary_search (gconstpointer *list, - gsize len, - gconstpointer needle, - GCompareDataFunc cmpfcn, - gpointer user_data, - gssize *out_idx_first, - gssize *out_idx_last); - -gssize nm_utils_array_find_binary_search (gconstpointer list, - gsize elem_size, - gsize len, - gconstpointer needle, - GCompareDataFunc cmpfcn, - gpointer user_data); +gssize nm_utils_ptrarray_find_binary_search(gconstpointer * list, + gsize len, + gconstpointer needle, + GCompareDataFunc cmpfcn, + gpointer user_data, + gssize * out_idx_first, + gssize * out_idx_last); + +gssize nm_utils_array_find_binary_search(gconstpointer list, + gsize elem_size, + gsize len, + gconstpointer needle, + GCompareDataFunc cmpfcn, + gpointer user_data); /*****************************************************************************/ -typedef gboolean (*NMUtilsHashTableEqualFunc) (gconstpointer a, - gconstpointer b); +typedef gboolean (*NMUtilsHashTableEqualFunc)(gconstpointer a, gconstpointer b); -gboolean nm_utils_hash_table_equal (const GHashTable *a, - const GHashTable *b, - gboolean treat_null_as_empty, - NMUtilsHashTableEqualFunc equal_func); +gboolean nm_utils_hash_table_equal(const GHashTable * a, + const GHashTable * b, + gboolean treat_null_as_empty, + NMUtilsHashTableEqualFunc equal_func); /*****************************************************************************/ -void _nm_utils_strv_sort (const char **strv, gssize len); -#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort (NM_CAST_STRV_MC (strv), len) +void _nm_utils_strv_sort(const char **strv, gssize len); +#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort(NM_CAST_STRV_MC(strv), len) -int _nm_utils_strv_cmp_n (const char *const*strv1, - gssize len1, - const char *const*strv2, - gssize len2); +int +_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2); static inline gboolean -_nm_utils_strv_equal (char **strv1, char **strv2) +_nm_utils_strv_equal(char **strv1, char **strv2) { - return _nm_utils_strv_cmp_n ((const char *const*) strv1, -1, - (const char *const*) strv2, -1) == 0; + return _nm_utils_strv_cmp_n((const char *const *) strv1, -1, (const char *const *) strv2, -1) + == 0; } /*****************************************************************************/ @@ -1627,460 +1644,616 @@ _nm_utils_strv_equal (char **strv1, char **strv2) #define NM_UTILS_NSEC_PER_MSEC ((gint64) 1000000) static inline gint64 -NM_UTILS_NSEC_TO_MSEC_CEIL (gint64 nsec) +NM_UTILS_NSEC_TO_MSEC_CEIL(gint64 nsec) { - return (nsec + (NM_UTILS_NSEC_PER_MSEC - 1)) / NM_UTILS_NSEC_PER_MSEC; + return (nsec + (NM_UTILS_NSEC_PER_MSEC - 1)) / NM_UTILS_NSEC_PER_MSEC; } /*****************************************************************************/ -int nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_nsec); -ssize_t nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll); -int nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll); +int nm_utils_fd_wait_for_event(int fd, int event, gint64 timeout_nsec); +ssize_t nm_utils_fd_read_loop(int fd, void *buf, size_t nbytes, bool do_poll); +int nm_utils_fd_read_loop_exact(int fd, void *buf, size_t nbytes, bool do_poll); /*****************************************************************************/ #define NM_DEFINE_GDBUS_ARG_INFO_FULL(name_, ...) \ - ((GDBusArgInfo *) (&((const GDBusArgInfo) { \ - .ref_count = -1, \ - .name = name_, \ - __VA_ARGS__ \ - }))) + ((GDBusArgInfo *) (&((const GDBusArgInfo){.ref_count = -1, .name = name_, __VA_ARGS__}))) #define NM_DEFINE_GDBUS_ARG_INFO(name_, a_signature) \ - NM_DEFINE_GDBUS_ARG_INFO_FULL ( \ - name_, \ - .signature = a_signature, \ - ) + NM_DEFINE_GDBUS_ARG_INFO_FULL(name_, .signature = a_signature, ) -#define NM_DEFINE_GDBUS_ARG_INFOS(...) \ - ((GDBusArgInfo **) ((const GDBusArgInfo *[]) { \ - __VA_ARGS__ \ - NULL, \ - })) +#define NM_DEFINE_GDBUS_ARG_INFOS(...) \ + ((GDBusArgInfo **) ((const GDBusArgInfo *[]){ \ + __VA_ARGS__ NULL, \ + })) #define NM_DEFINE_GDBUS_PROPERTY_INFO(name_, ...) \ - ((GDBusPropertyInfo *) (&((const GDBusPropertyInfo) { \ - .ref_count = -1, \ - .name = name_, \ - __VA_ARGS__ \ - }))) + ((GDBusPropertyInfo *) (&( \ + (const GDBusPropertyInfo){.ref_count = -1, .name = name_, __VA_ARGS__}))) #define NM_DEFINE_GDBUS_PROPERTY_INFO_READABLE(name_, m_signature) \ - NM_DEFINE_GDBUS_PROPERTY_INFO ( \ - name_, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, \ - ) - -#define NM_DEFINE_GDBUS_PROPERTY_INFOS(...) \ - ((GDBusPropertyInfo **) ((const GDBusPropertyInfo *[]) { \ - __VA_ARGS__ \ - NULL, \ - })) + NM_DEFINE_GDBUS_PROPERTY_INFO(name_, \ + .signature = m_signature, \ + .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, ) + +#define NM_DEFINE_GDBUS_PROPERTY_INFOS(...) \ + ((GDBusPropertyInfo **) ((const GDBusPropertyInfo *[]){ \ + __VA_ARGS__ NULL, \ + })) #define NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(name_, ...) \ - { \ - .ref_count = -1, \ - .name = name_, \ - __VA_ARGS__ \ - } + { \ + .ref_count = -1, .name = name_, __VA_ARGS__ \ + } #define NM_DEFINE_GDBUS_SIGNAL_INFO(name_, ...) \ - ((GDBusSignalInfo *) (&((const GDBusSignalInfo) NM_DEFINE_GDBUS_SIGNAL_INFO_INIT (name_, __VA_ARGS__)))) + ((GDBusSignalInfo *) (&( \ + (const GDBusSignalInfo) NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(name_, __VA_ARGS__)))) -#define NM_DEFINE_GDBUS_SIGNAL_INFOS(...) \ - ((GDBusSignalInfo **) ((const GDBusSignalInfo *[]) { \ - __VA_ARGS__ \ - NULL, \ - })) +#define NM_DEFINE_GDBUS_SIGNAL_INFOS(...) \ + ((GDBusSignalInfo **) ((const GDBusSignalInfo *[]){ \ + __VA_ARGS__ NULL, \ + })) #define NM_DEFINE_GDBUS_METHOD_INFO_INIT(name_, ...) \ - { \ - .ref_count = -1, \ - .name = name_, \ - __VA_ARGS__ \ - } + { \ + .ref_count = -1, .name = name_, __VA_ARGS__ \ + } #define NM_DEFINE_GDBUS_METHOD_INFO(name_, ...) \ - ((GDBusMethodInfo *) (&((const GDBusMethodInfo) NM_DEFINE_GDBUS_METHOD_INFO_INIT (name_, __VA_ARGS__)))) + ((GDBusMethodInfo *) (&( \ + (const GDBusMethodInfo) NM_DEFINE_GDBUS_METHOD_INFO_INIT(name_, __VA_ARGS__)))) -#define NM_DEFINE_GDBUS_METHOD_INFOS(...) \ - ((GDBusMethodInfo **) ((const GDBusMethodInfo *[]) { \ - __VA_ARGS__ \ - NULL, \ - })) +#define NM_DEFINE_GDBUS_METHOD_INFOS(...) \ + ((GDBusMethodInfo **) ((const GDBusMethodInfo *[]){ \ + __VA_ARGS__ NULL, \ + })) #define NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(name_, ...) \ - { \ - .ref_count = -1, \ - .name = name_, \ - __VA_ARGS__ \ - } + { \ + .ref_count = -1, .name = name_, __VA_ARGS__ \ + } #define NM_DEFINE_GDBUS_INTERFACE_INFO(name_, ...) \ - ((GDBusInterfaceInfo *) (&((const GDBusInterfaceInfo) NM_DEFINE_GDBUS_INTERFACE_INFO_INIT (name_, __VA_ARGS__)))) + ((GDBusInterfaceInfo *) (&( \ + (const GDBusInterfaceInfo) NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(name_, __VA_ARGS__)))) #define NM_DEFINE_GDBUS_INTERFACE_VTABLE(...) \ - ((GDBusInterfaceVTable *) (&((const GDBusInterfaceVTable) { \ - __VA_ARGS__ \ - }))) + ((GDBusInterfaceVTable *) (&((const GDBusInterfaceVTable){__VA_ARGS__}))) /*****************************************************************************/ -guint64 nm_utils_get_start_time_for_pid (pid_t pid, char *out_state, pid_t *out_ppid); +guint64 nm_utils_get_start_time_for_pid(pid_t pid, char *out_state, pid_t *out_ppid); static inline gboolean -nm_utils_process_state_is_dead (char pstate) +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). - */ - return NM_IN_SET (pstate, 'Z', 'x', 'X'); + /* "/proc/[pid]/stat" returns a state as the 3rd fields (see `man 5 proc`). + * Some of these states indicate the process is effectively dead (or a zombie). + */ + return NM_IN_SET(pstate, 'Z', 'x', 'X'); } /*****************************************************************************/ -gpointer _nm_utils_user_data_pack (int nargs, gconstpointer *args); +gpointer _nm_utils_user_data_pack(int nargs, gconstpointer *args); #define nm_utils_user_data_pack(...) \ - _nm_utils_user_data_pack(NM_NARG (__VA_ARGS__), (gconstpointer[]) { __VA_ARGS__ }) + _nm_utils_user_data_pack(NM_NARG(__VA_ARGS__), (gconstpointer[]){__VA_ARGS__}) -void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...); +void _nm_utils_user_data_unpack(gpointer user_data, int nargs, ...); #define nm_utils_user_data_unpack(user_data, ...) \ - _nm_utils_user_data_unpack(user_data, NM_NARG (__VA_ARGS__), __VA_ARGS__) + _nm_utils_user_data_unpack(user_data, NM_NARG(__VA_ARGS__), __VA_ARGS__) /*****************************************************************************/ -typedef void (*NMUtilsInvokeOnIdleCallback) (gpointer user_data, - GCancellable *cancellable); +typedef void (*NMUtilsInvokeOnIdleCallback)(gpointer user_data, GCancellable *cancellable); -void nm_utils_invoke_on_idle (GCancellable *cancellable, - NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data); +void nm_utils_invoke_on_idle(GCancellable * cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data); -void nm_utils_invoke_on_timeout (guint timeout_msec, - GCancellable *cancellable, - NMUtilsInvokeOnIdleCallback callback, - gpointer callback_user_data); +void nm_utils_invoke_on_timeout(guint timeout_msec, + GCancellable * cancellable, + NMUtilsInvokeOnIdleCallback callback, + gpointer callback_user_data); /*****************************************************************************/ -GSource *nm_utils_g_main_context_create_integrate_source (GMainContext *internal); +GSource *nm_utils_g_main_context_create_integrate_source(GMainContext *internal); /*****************************************************************************/ +static inline GPtrArray * +nm_strv_ptrarray_ensure(GPtrArray **p_arr) +{ + nm_assert(p_arr); + + if (G_UNLIKELY(!*p_arr)) + *p_arr = g_ptr_array_new_with_free_func(g_free); + + return *p_arr; +} + +static inline const char *const * +nm_strv_ptrarray_get_unsafe(GPtrArray *arr, guint *out_len) +{ + /* warning: the GPtrArray is not NULL terminated. So, it + * isn't really a strv array (sorry the misnomer). That's why + * the function is potentially "unsafe" and you must provide a + * out_len parameter. */ + if (!arr || arr->len == 0) { + *out_len = 0; + return NULL; + } + *out_len = arr->len; + return (const char *const *) arr->pdata; +} + +static inline GPtrArray * +nm_strv_ptrarray_clone(const GPtrArray *src, gboolean null_if_empty) +{ + if (!src || (null_if_empty && src->len == 0)) + return NULL; + return nm_g_ptr_array_copy((GPtrArray *) src, nm_copy_func_g_strdup, NULL, g_free); +} + static inline void -nm_strv_ptrarray_add_string_take (GPtrArray *cmd, - char *str) +nm_strv_ptrarray_add_string_take(GPtrArray *cmd, char *str) { - nm_assert (cmd); - nm_assert (str); + nm_assert(cmd); + nm_assert(str); - g_ptr_array_add (cmd, str); + g_ptr_array_add(cmd, str); } static inline void -nm_strv_ptrarray_add_string_dup (GPtrArray *cmd, - const char *str) +nm_strv_ptrarray_add_string_dup(GPtrArray *cmd, const char *str) { - nm_strv_ptrarray_add_string_take (cmd, - g_strdup (str)); + nm_strv_ptrarray_add_string_take(cmd, g_strdup(str)); } #define nm_strv_ptrarray_add_string_concat(cmd, ...) \ - nm_strv_ptrarray_add_string_take ((cmd), g_strconcat (__VA_ARGS__, NULL)) + nm_strv_ptrarray_add_string_take((cmd), g_strconcat(__VA_ARGS__, NULL)) #define nm_strv_ptrarray_add_string_printf(cmd, ...) \ - nm_strv_ptrarray_add_string_take ((cmd), g_strdup_printf (__VA_ARGS__)) + nm_strv_ptrarray_add_string_take((cmd), g_strdup_printf(__VA_ARGS__)) #define nm_strv_ptrarray_add_int(cmd, val) \ - nm_strv_ptrarray_add_string_take ((cmd), nm_strdup_int (val)) + nm_strv_ptrarray_add_string_take((cmd), nm_strdup_int(val)) static inline void -nm_strv_ptrarray_take_gstring (GPtrArray *cmd, - GString **gstr) +nm_strv_ptrarray_take_gstring(GPtrArray *cmd, GString **gstr) { - nm_assert (gstr && *gstr); + nm_assert(gstr && *gstr); + + nm_strv_ptrarray_add_string_take(cmd, g_string_free(g_steal_pointer(gstr), FALSE)); +} + +static inline gssize +nm_strv_ptrarray_find_first(const GPtrArray *strv, const char *str) +{ + if (!strv) + return -1; + return nm_utils_strv_find_first((char **) strv->pdata, strv->len, str); +} + +static inline gboolean +nm_strv_ptrarray_contains(const GPtrArray *strv, const char *str) +{ + return nm_strv_ptrarray_find_first(strv, str) >= 0; +} - nm_strv_ptrarray_add_string_take (cmd, - g_string_free (g_steal_pointer (gstr), - FALSE)); +static inline int +nm_strv_ptrarray_cmp(const GPtrArray *a, const GPtrArray *b) +{ + /* _nm_utils_strv_cmp_n() will treat NULL and empty arrays the same. + * That means, an empty strv array can both be represented by NULL + * and an array of length zero. + * If you need to distinguish between these case, do that yourself. */ + return _nm_utils_strv_cmp_n((const char *const *) nm_g_ptr_array_pdata(a), + nm_g_ptr_array_len(a), + (const char *const *) nm_g_ptr_array_pdata(b), + nm_g_ptr_array_len(b)); } /*****************************************************************************/ -int nm_utils_getpagesize (void); +int nm_utils_getpagesize(void); /*****************************************************************************/ -char *nm_utils_bin2hexstr_full (gconstpointer addr, - gsize length, - char delimiter, - gboolean upper_case, - char *out); +extern const char _nm_hexchar_table_lower[16]; +extern const char _nm_hexchar_table_upper[16]; -guint8 *nm_utils_hexstr2bin_full (const char *hexstr, - gboolean allow_0x_prefix, - gboolean delimiter_required, +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, + gboolean upper_case, + char * out); + +#define nm_utils_bin2hexstr_a(addr, length, delimiter, upper_case, str_to_free) \ + ({ \ + gconstpointer _addr = (addr); \ + gsize _length = (length); \ + char _delimiter = (delimiter); \ + char ** _str_to_free = (str_to_free); \ + char * _s; \ + gsize _s_len; \ + \ + nm_assert(_str_to_free); \ + \ + _s_len = _length == 0 ? 1u : (_delimiter == '\0' ? _length * 2u + 1u : _length * 3u); \ + if (_s_len < 100) \ + _s = g_alloca(_s_len); \ + else { \ + _s = g_malloc(_s_len); \ + *_str_to_free = _s; \ + } \ + nm_utils_bin2hexstr_full(_addr, _length, _delimiter, (upper_case), _s); \ + }) + +static inline const char * +nm_ether_addr_to_string(const NMEtherAddr *ether_addr, char sbuf[static(sizeof(NMEtherAddr) * 3)]) +{ + nm_assert(ether_addr); + nm_assert(sbuf); + + return nm_utils_bin2hexstr_full(ether_addr, sizeof(NMEtherAddr), ':', TRUE, sbuf); +} + +#define nm_ether_addr_to_string_a(ether_addr) \ + nm_ether_addr_to_string((ether_addr), g_alloca(sizeof(NMEtherAddr) * 3)) + +guint8 *nm_utils_hexstr2bin_full(const char *hexstr, + gboolean allow_0x_prefix, + gboolean delimiter_required, + gboolean hexdigit_pairs_required, + const char *delimiter_candidates, + gsize required_len, + guint8 * buffer, + gsize buffer_len, + gsize * out_len); + +#define nm_utils_hexstr2bin_buf(hexstr, \ + allow_0x_prefix, \ + delimiter_required, \ + delimiter_candidates, \ + buffer) \ + nm_utils_hexstr2bin_full((hexstr), \ + (allow_0x_prefix), \ + (delimiter_required), \ + FALSE, \ + (delimiter_candidates), \ + G_N_ELEMENTS(buffer), \ + (buffer), \ + G_N_ELEMENTS(buffer), \ + NULL) + +guint8 *nm_utils_hexstr2bin_alloc(const char *hexstr, + gboolean allow_0x_prefix, + gboolean delimiter_required, const char *delimiter_candidates, - gsize required_len, - guint8 *buffer, - gsize buffer_len, - gsize *out_len); + gsize required_len, + gsize * out_len); + +/** + * _nm_utils_hwaddr_aton: + * @asc: the ASCII representation of a hardware address + * @buffer: buffer to store the result into. Must have + * at least a size of @buffer_length. + * @buffer_length: the length of the input buffer @buffer. + * The result must fit into that buffer, otherwise + * the function fails and returns %NULL. + * @out_length: the output length in case of success. + * + * Parses @asc and converts it to binary form in @buffer. + * Bytes in @asc can be separated by colons (:), or hyphens (-), but not mixed. + * + * It is like nm_utils_hwaddr_aton(), but contrary to that it + * can parse addresses of any length. That is, you don't need + * to know the length before-hand. + * + * Return value: @buffer, or %NULL if @asc couldn't be parsed. + */ +static inline guint8 * +_nm_utils_hwaddr_aton(const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length) +{ + g_return_val_if_fail(asc, NULL); + g_return_val_if_fail(buffer, NULL); + g_return_val_if_fail(buffer_length > 0, NULL); + g_return_val_if_fail(out_length, NULL); -#define nm_utils_hexstr2bin_buf(hexstr, allow_0x_prefix, delimiter_required, delimiter_candidates, buffer) \ - nm_utils_hexstr2bin_full ((hexstr), (allow_0x_prefix), (delimiter_required), (delimiter_candidates), G_N_ELEMENTS (buffer), (buffer), G_N_ELEMENTS (buffer), NULL) + return nm_utils_hexstr2bin_full(asc, + FALSE, + TRUE, + FALSE, + ":-", + 0, + buffer, + buffer_length, + out_length); +} -guint8 *nm_utils_hexstr2bin_alloc (const char *hexstr, - gboolean allow_0x_prefix, - gboolean delimiter_required, - const char *delimiter_candidates, - gsize required_len, - gsize *out_len); +static inline const char * +_nm_utils_hwaddr_ntoa(gconstpointer addr, + gsize addr_len, + gboolean upper_case, + char * buf, + gsize buf_len) +{ + g_return_val_if_fail(addr, NULL); + g_return_val_if_fail(addr_len > 0, NULL); + g_return_val_if_fail(buf, NULL); + if (buf_len < addr_len * 3) + g_return_val_if_reached(NULL); + + return nm_utils_bin2hexstr_full(addr, addr_len, ':', upper_case, buf); +} /*****************************************************************************/ -#define _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name, \ - value_type, \ - value_type_result, \ - entry_cmd, \ - unknown_val_cmd, \ - get_operator, \ - ...) \ -value_type_result \ -fcn_name (const char *name) \ -{ \ - static const struct { \ - const char *name; \ - value_type value; \ - } LIST[] = { \ - __VA_ARGS__ \ - }; \ - \ - if (NM_MORE_ASSERT_ONCE (5)) { \ - int i; \ - \ - for (i = 0; i < G_N_ELEMENTS (LIST); i++) { \ - nm_assert (LIST[i].name); \ - if (i > 0) \ - nm_assert (strcmp (LIST[i - 1].name, LIST[i].name) < 0); \ - } \ - } \ - \ - { entry_cmd; } \ - \ - if (G_LIKELY (name)) { \ - G_STATIC_ASSERT (G_N_ELEMENTS (LIST) > 1); \ - G_STATIC_ASSERT (G_N_ELEMENTS (LIST) < G_MAXINT / 2 - 10); \ - int imin = 0; \ - int imax = (G_N_ELEMENTS (LIST) - 1); \ - int imid = (G_N_ELEMENTS (LIST) - 1) / 2; \ - \ - for (;;) { \ - const int cmp = strcmp (LIST[imid].name, name); \ - \ - if (G_UNLIKELY (cmp == 0)) \ - return get_operator (LIST[imid].value); \ - \ - if (cmp < 0) \ - imin = imid + 1; \ - else \ - imax = imid - 1; \ - \ - if (G_UNLIKELY (imin > imax)) \ - break; \ - \ - /* integer overflow cannot happen, because LIST is shorter than G_MAXINT/2. */ \ - imid = (imin + imax) / 2;\ - } \ - } \ - \ - { unknown_val_cmd; } \ -} - -#define NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE(fcn_name, \ - result_type, \ - entry_cmd, \ +#define _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name, \ + value_type, \ + value_type_result, \ + entry_cmd, \ + unknown_val_cmd, \ + get_operator, \ + ...) \ + value_type_result fcn_name(const char *name) \ + { \ + static const struct { \ + const char *name; \ + value_type value; \ + } LIST[] = {__VA_ARGS__}; \ + \ + if (NM_MORE_ASSERT_ONCE(5)) { \ + int i; \ + \ + for (i = 0; i < G_N_ELEMENTS(LIST); i++) { \ + nm_assert(LIST[i].name); \ + if (i > 0) \ + nm_assert(strcmp(LIST[i - 1].name, LIST[i].name) < 0); \ + } \ + } \ + \ + { \ + entry_cmd; \ + } \ + \ + if (G_LIKELY(name)) { \ + G_STATIC_ASSERT(G_N_ELEMENTS(LIST) > 1); \ + G_STATIC_ASSERT(G_N_ELEMENTS(LIST) < G_MAXINT / 2 - 10); \ + int imin = 0; \ + int imax = (G_N_ELEMENTS(LIST) - 1); \ + int imid = (G_N_ELEMENTS(LIST) - 1) / 2; \ + \ + for (;;) { \ + const int cmp = strcmp(LIST[imid].name, name); \ + \ + if (G_UNLIKELY(cmp == 0)) \ + return get_operator(LIST[imid].value); \ + \ + if (cmp < 0) \ + imin = imid + 1; \ + else \ + imax = imid - 1; \ + \ + if (G_UNLIKELY(imin > imax)) \ + break; \ + \ + /* integer overflow cannot happen, because LIST is shorter than G_MAXINT/2. */ \ + imid = (imin + imax) / 2; \ + } \ + } \ + \ + { \ + unknown_val_cmd; \ + } \ + } + +#define NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE(fcn_name, \ + result_type, \ + entry_cmd, \ unknown_val_cmd, \ - ...) \ - _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (fcn_name, \ - result_type, \ - const result_type *, \ - entry_cmd, \ - unknown_val_cmd, \ - &, \ - __VA_ARGS__) - -#define NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name, \ - result_type, \ - entry_cmd, \ + ...) \ + _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name, \ + result_type, \ + const result_type *, \ + entry_cmd, \ + unknown_val_cmd, \ + &, \ + __VA_ARGS__) + +#define NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name, \ + result_type, \ + entry_cmd, \ unknown_val_cmd, \ - ...) \ - _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE (fcn_name, \ - result_type, \ - result_type, \ - entry_cmd, \ - unknown_val_cmd, \ - , \ - __VA_ARGS__) + ...) \ + _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name, \ + result_type, \ + result_type, \ + entry_cmd, \ + unknown_val_cmd, \ + , \ + __VA_ARGS__) /*****************************************************************************/ static inline GTask * -nm_g_task_new (gpointer source_object, - GCancellable *cancellable, - gpointer source_tag, - GAsyncReadyCallback callback, - gpointer callback_data) +nm_g_task_new(gpointer source_object, + GCancellable * cancellable, + gpointer source_tag, + GAsyncReadyCallback callback, + gpointer callback_data) { - GTask *task; + GTask *task; - task = g_task_new (source_object, cancellable, callback, callback_data); - if (source_tag) - g_task_set_source_tag (task, source_tag); - return task; + task = g_task_new(source_object, cancellable, callback, callback_data); + if (source_tag) + g_task_set_source_tag(task, source_tag); + return task; } static inline gboolean -nm_g_task_is_valid (gpointer task, - gpointer source_object, - gpointer source_tag) +nm_g_task_is_valid(gpointer task, gpointer source_object, gpointer source_tag) { - return g_task_is_valid (task, source_object) - && g_task_get_source_tag (task) == source_tag; + return g_task_is_valid(task, source_object) && g_task_get_source_tag(task) == source_tag; } -guint nm_utils_parse_debug_string (const char *string, - const GDebugKey *keys, - guint nkeys); +guint nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, guint nkeys); /*****************************************************************************/ static inline gboolean -nm_utils_strdup_reset (char **dst, const char *src) +nm_utils_strdup_reset(char **dst, const char *src) { - nm_assert (dst); - - if (nm_streq0 (*dst, src)) - return FALSE; - g_free (*dst); - *dst = g_strdup (src); - return TRUE; -} + char *old; -void nm_indirect_g_free (gpointer arg); + nm_assert(dst); -/*****************************************************************************/ + if (nm_streq0(*dst, src)) + return FALSE; + old = *dst; + *dst = g_strdup(src); + g_free(old); + return TRUE; +} -/* 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); +void nm_indirect_g_free(gpointer arg); /*****************************************************************************/ typedef enum { - NMU_IFACE_ANY, - NMU_IFACE_KERNEL, - NMU_IFACE_OVS, - NMU_IFACE_OVS_AND_KERNEL, + NMU_IFACE_ANY, + NMU_IFACE_KERNEL, + NMU_IFACE_OVS, + NMU_IFACE_OVS_AND_KERNEL, } NMUtilsIfaceType; -gboolean nm_utils_ifname_valid_kernel (const char *name, GError **error); +gboolean nm_utils_ifname_valid_kernel(const char *name, GError **error); -gboolean nm_utils_ifname_valid (const char* name, - NMUtilsIfaceType type, - GError **error); +gboolean nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError **error); /*****************************************************************************/ static inline GArray * -nm_strvarray_ensure (GArray **p) +nm_strvarray_ensure(GArray **p) { - if (!*p) { - *p = g_array_new (TRUE, FALSE, sizeof (char *)); - g_array_set_clear_func (*p, nm_indirect_g_free); - } - return *p; + if (!*p) { + *p = g_array_new(TRUE, FALSE, sizeof(char *)); + g_array_set_clear_func(*p, nm_indirect_g_free); + } + return *p; } static inline void -nm_strvarray_add (GArray *array, const char *str) +nm_strvarray_add(GArray *array, const char *str) { - char *s; + char *s; - s = g_strdup (str); - g_array_append_val (array, s); + s = g_strdup(str); + g_array_append_val(array, s); } -static inline const char *const* -nm_strvarray_get_strv_non_empty (GArray *arr, guint *length) +static inline const char *const * +nm_strvarray_get_strv_non_empty(GArray *arr, guint *length) { - if (!arr || arr->len == 0) { - NM_SET_OUT (length, 0); - return NULL; - } + if (!arr || arr->len == 0) { + NM_SET_OUT(length, 0); + return NULL; + } - NM_SET_OUT (length, arr->len); - return &g_array_index (arr, const char *, 0); + NM_SET_OUT(length, arr->len); + return &g_array_index(arr, const char *, 0); } -static inline const char *const* -nm_strvarray_get_strv (GArray **arr, guint *length) +static inline const char *const * +nm_strvarray_get_strv(GArray **arr, guint *length) { - if (!*arr) { - NM_SET_OUT (length, 0); - return (const char *const*) arr; - } + if (!*arr) { + NM_SET_OUT(length, 0); + return (const char *const *) arr; + } - NM_SET_OUT (length, (*arr)->len); - return &g_array_index (*arr, const char *, 0); + NM_SET_OUT(length, (*arr)->len); + return &g_array_index(*arr, const char *, 0); } static inline void -nm_strvarray_set_strv (GArray **array, const char *const*strv) +nm_strvarray_set_strv(GArray **array, const char *const *strv) { - gs_unref_array GArray *array_old = NULL; + gs_unref_array GArray *array_old = NULL; + + array_old = g_steal_pointer(array); - array_old = g_steal_pointer (array); + if (!strv || !strv[0]) + return; + + nm_strvarray_ensure(array); + for (; strv[0]; strv++) + nm_strvarray_add(*array, strv[0]); +} + +static inline gboolean +nm_strvarray_remove_first(GArray *strv, const char *needle) +{ + guint i; - if (!strv || !strv[0]) - return; + nm_assert(needle); - nm_strvarray_ensure (array); - for (; strv[0]; strv++) - nm_strvarray_add (*array, strv[0]); + if (strv) { + for (i = 0; i < strv->len; i++) { + if (nm_streq(needle, g_array_index(strv, const char *, i))) { + g_array_remove_index(strv, i); + return TRUE; + } + } + } + return FALSE; } /*****************************************************************************/ -void _nm_utils_format_variant_attributes_full (GString *str, - const NMUtilsNamedValue *values, - guint num_values, - char attr_separator, - char key_value_separator); +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); + +/*****************************************************************************/ + +gboolean nm_utils_is_localhost(const char *name); + +gboolean nm_utils_is_specific_hostname(const char *name); -char *_nm_utils_format_variant_attributes (GHashTable *attributes, - char attr_separator, - char key_value_separator); +char * nm_utils_uid_to_name(uid_t uid); +gboolean nm_utils_name_to_uid(const char *name, uid_t *out_uid); #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index da082abe..062630a5 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NM_STR_BUF_H__ #define __NM_STR_BUF_H__ @@ -11,72 +11,65 @@ /* NMStrBuf is not unlike GString. The main difference is that it can use * nm_explicit_bzero() when growing the buffer. */ typedef struct _NMStrBuf { - - char *_priv_str; - - /* The unions only exist because we allow/encourage read-only access - * to the "len" and "allocated" fields, but modifying the fields is - * only allowed to the NMStrBuf implementation itself. */ - union { - /*const*/ gsize len; - gsize _priv_len; - }; - union { - /*const*/ gsize allocated; - gsize _priv_allocated; - }; - - bool _priv_do_bzero_mem; + char *_priv_str; + + /* The unions only exist because we allow/encourage read-only access + * to the "len" and "allocated" fields, but modifying the fields is + * only allowed to the NMStrBuf implementation itself. */ + union { + /*const*/ gsize len; + gsize _priv_len; + }; + union { + /*const*/ gsize allocated; + gsize _priv_allocated; + }; + + bool _priv_do_bzero_mem; } NMStrBuf; /*****************************************************************************/ static inline void -_nm_str_buf_assert (NMStrBuf *strbuf) +_nm_str_buf_assert(NMStrBuf *strbuf) { - nm_assert (strbuf); - nm_assert ((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0)); - nm_assert (strbuf->_priv_len <= strbuf->_priv_allocated); + nm_assert(strbuf); + nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0)); + nm_assert(strbuf->_priv_len <= strbuf->_priv_allocated); } static inline NMStrBuf -NM_STR_BUF_INIT (gsize allocated, gboolean do_bzero_mem) +NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem) { - NMStrBuf strbuf = { - ._priv_str = allocated ? g_malloc (allocated) : NULL, - ._priv_allocated = allocated, - ._priv_len = 0, - ._priv_do_bzero_mem = do_bzero_mem, - }; - - return strbuf; + NMStrBuf strbuf = { + ._priv_str = allocated ? g_malloc(allocated) : NULL, + ._priv_allocated = allocated, + ._priv_len = 0, + ._priv_do_bzero_mem = do_bzero_mem, + }; + + return strbuf; } static inline void -nm_str_buf_init (NMStrBuf *strbuf, - gsize len, - bool do_bzero_mem) +nm_str_buf_init(NMStrBuf *strbuf, gsize len, bool do_bzero_mem) { - nm_assert (strbuf); - *strbuf = NM_STR_BUF_INIT (len, do_bzero_mem); - _nm_str_buf_assert (strbuf); + nm_assert(strbuf); + *strbuf = NM_STR_BUF_INIT(len, do_bzero_mem); + _nm_str_buf_assert(strbuf); } -void _nm_str_buf_ensure_size (NMStrBuf *strbuf, - gsize new_size, - gboolean reserve_exact); +void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact); static inline void -nm_str_buf_maybe_expand (NMStrBuf *strbuf, - gsize reserve, - gboolean reserve_exact) +nm_str_buf_maybe_expand(NMStrBuf *strbuf, gsize reserve, gboolean reserve_exact) { - _nm_str_buf_assert (strbuf); - nm_assert (strbuf->_priv_len < G_MAXSIZE - reserve); + _nm_str_buf_assert(strbuf); + nm_assert(strbuf->_priv_len < G_MAXSIZE - reserve); - /* @reserve is the extra space that we require. */ - if (G_UNLIKELY (reserve > strbuf->_priv_allocated - strbuf->_priv_len)) - _nm_str_buf_ensure_size (strbuf, strbuf->_priv_len + reserve, reserve_exact); + /* @reserve is the extra space that we require. */ + if (G_UNLIKELY(reserve > strbuf->_priv_allocated - strbuf->_priv_len)) + _nm_str_buf_ensure_size(strbuf, strbuf->_priv_len + reserve, reserve_exact); } /*****************************************************************************/ @@ -85,9 +78,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 @@ -103,162 +96,229 @@ nm_str_buf_maybe_expand (NMStrBuf *strbuf, * pre-existing, grown buffer). */ static inline void -nm_str_buf_set_size (NMStrBuf *strbuf, - gsize new_len, - gboolean honor_do_bzero_mem, - gboolean reserve_exact) +nm_str_buf_set_size(NMStrBuf *strbuf, + gsize new_len, + gboolean honor_do_bzero_mem, + gboolean reserve_exact) { - _nm_str_buf_assert (strbuf); - - if (new_len < strbuf->_priv_len) { - if ( honor_do_bzero_mem - && strbuf->_priv_do_bzero_mem) { - /* we only clear the memory that we wrote to. */ - nm_explicit_bzero (&strbuf->_priv_str[new_len], strbuf->_priv_len - new_len); - } - } else if (new_len > strbuf->_priv_len) { - nm_str_buf_maybe_expand (strbuf, - new_len - strbuf->_priv_len + (reserve_exact ? 0u : 1u), - reserve_exact); - } else - return; - - strbuf->_priv_len = new_len; + _nm_str_buf_assert(strbuf); + + if (new_len < strbuf->_priv_len) { + if (honor_do_bzero_mem && strbuf->_priv_do_bzero_mem) { + /* we only clear the memory that we wrote to. */ + nm_explicit_bzero(&strbuf->_priv_str[new_len], strbuf->_priv_len - new_len); + } + } else if (new_len > strbuf->_priv_len) { + nm_str_buf_maybe_expand(strbuf, + new_len - strbuf->_priv_len + (reserve_exact ? 0u : 1u), + reserve_exact); + } else + return; + + strbuf->_priv_len = new_len; } /*****************************************************************************/ static inline void -nm_str_buf_erase (NMStrBuf *strbuf, - gsize pos, - gssize len, - gboolean honor_do_bzero_mem) +nm_str_buf_erase(NMStrBuf *strbuf, gsize pos, gssize len, gboolean honor_do_bzero_mem) { - gsize new_len; + gsize new_len; - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); - nm_assert (pos <= strbuf->_priv_len); + nm_assert(pos <= strbuf->_priv_len); - if (len == 0) - return; + if (len == 0) + return; - if (len < 0) { - /* truncate the string before pos */ - nm_assert (len == -1); - new_len = pos; - } else { - gsize l = len; + if (len < 0) { + /* truncate the string before pos */ + nm_assert(len == -1); + new_len = pos; + } else { + gsize l = len; - nm_assert (l <= strbuf->_priv_len - pos); + nm_assert(l <= strbuf->_priv_len - pos); - new_len = strbuf->_priv_len - l; - if (pos + l < strbuf->_priv_len) { - memmove (&strbuf->_priv_str[pos], - &strbuf->_priv_str[pos + l], - strbuf->_priv_len - (pos + l)); - } - } + new_len = strbuf->_priv_len - l; + if (pos + l < strbuf->_priv_len) { + memmove(&strbuf->_priv_str[pos], + &strbuf->_priv_str[pos + l], + strbuf->_priv_len - (pos + l)); + } + } - nm_assert (new_len <= strbuf->_priv_len); - nm_str_buf_set_size (strbuf, new_len, honor_do_bzero_mem, TRUE); + nm_assert(new_len <= strbuf->_priv_len); + nm_str_buf_set_size(strbuf, new_len, honor_do_bzero_mem, TRUE); } /*****************************************************************************/ static inline void -nm_str_buf_append_c_repeated (NMStrBuf *strbuf, - char ch, - guint len) +nm_str_buf_append_c_repeated(NMStrBuf *strbuf, char ch, guint len) +{ + if (len > 0) { + nm_str_buf_maybe_expand(strbuf, len + 1, FALSE); + do { + strbuf->_priv_str[strbuf->_priv_len++] = ch; + } while (--len > 0); + } +} + +static inline void +nm_str_buf_append_c(NMStrBuf *strbuf, char ch) { - if (len > 0) { - nm_str_buf_maybe_expand (strbuf, len + 1, FALSE); - do { - strbuf->_priv_str[strbuf->_priv_len++] = ch; - } while (--len > 0); - } + nm_str_buf_maybe_expand(strbuf, 2, FALSE); + strbuf->_priv_str[strbuf->_priv_len++] = ch; } static inline void -nm_str_buf_append_c (NMStrBuf *strbuf, - char ch) +nm_str_buf_append_c2(NMStrBuf *strbuf, char ch0, char ch1) { - nm_str_buf_maybe_expand (strbuf, 2, FALSE); - strbuf->_priv_str[strbuf->_priv_len++] = ch; + nm_str_buf_maybe_expand(strbuf, 3, FALSE); + strbuf->_priv_str[strbuf->_priv_len++] = ch0; + strbuf->_priv_str[strbuf->_priv_len++] = ch1; } static inline void -nm_str_buf_append_c2 (NMStrBuf *strbuf, - char ch0, - char ch1) +nm_str_buf_append_c4(NMStrBuf *strbuf, char ch0, char ch1, char ch2, char ch3) { - nm_str_buf_maybe_expand (strbuf, 3, FALSE); - strbuf->_priv_str[strbuf->_priv_len++] = ch0; - strbuf->_priv_str[strbuf->_priv_len++] = ch1; + nm_str_buf_maybe_expand(strbuf, 5, FALSE); + strbuf->_priv_str[strbuf->_priv_len++] = ch0; + strbuf->_priv_str[strbuf->_priv_len++] = ch1; + strbuf->_priv_str[strbuf->_priv_len++] = ch2; + strbuf->_priv_str[strbuf->_priv_len++] = ch3; } static inline void -nm_str_buf_append_c4 (NMStrBuf *strbuf, - char ch0, - char ch1, - char ch2, - char ch3) +nm_str_buf_append_c_hex(NMStrBuf *strbuf, char ch, gboolean upper_case) { - nm_str_buf_maybe_expand (strbuf, 5, FALSE); - strbuf->_priv_str[strbuf->_priv_len++] = ch0; - strbuf->_priv_str[strbuf->_priv_len++] = ch1; - strbuf->_priv_str[strbuf->_priv_len++] = ch2; - strbuf->_priv_str[strbuf->_priv_len++] = ch3; + 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) +nm_str_buf_append_len(NMStrBuf *strbuf, const char *str, gsize len) { - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); - if (len > 0) { - nm_str_buf_maybe_expand (strbuf, len + 1, FALSE); - memcpy (&strbuf->_priv_str[strbuf->_priv_len], str, len); - strbuf->_priv_len += len; - } + if (len > 0) { + nm_str_buf_maybe_expand(strbuf, len + 1, FALSE); + memcpy(&strbuf->_priv_str[strbuf->_priv_len], str, len); + strbuf->_priv_len += len; + } +} + +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) +nm_str_buf_append(NMStrBuf *strbuf, const char *str) { - nm_assert (str); + nm_assert(str); - nm_str_buf_append_len (strbuf, str, strlen (str)); + nm_str_buf_append_len(strbuf, str, strlen(str)); } -void nm_str_buf_append_printf (NMStrBuf *strbuf, - const char *format, - ...) _nm_printf (2, 3); +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); static inline void -nm_str_buf_ensure_trailing_c (NMStrBuf *strbuf, char ch) +nm_str_buf_ensure_trailing_c(NMStrBuf *strbuf, char ch) { - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); - if ( strbuf->_priv_len == 0 - || strbuf->_priv_str[strbuf->_priv_len - 1] != ch) - nm_str_buf_append_c (strbuf, ch); + if (strbuf->_priv_len == 0 || strbuf->_priv_str[strbuf->_priv_len - 1] != 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 -nm_str_buf_is_initalized (NMStrBuf *strbuf) +nm_str_buf_is_initalized(NMStrBuf *strbuf) { - nm_assert (strbuf); + nm_assert(strbuf); #if NM_MORE_ASSERTS - if (strbuf->_priv_str) - _nm_str_buf_assert (strbuf); + if (strbuf->_priv_str) + _nm_str_buf_assert(strbuf); #endif - return !!strbuf->_priv_str; + return !!strbuf->_priv_str; } /** @@ -282,23 +342,23 @@ nm_str_buf_is_initalized (NMStrBuf *strbuf) * If currently no buffer is allocated, this will return %NULL. */ static inline char * -nm_str_buf_get_str (NMStrBuf *strbuf) +nm_str_buf_get_str(NMStrBuf *strbuf) { - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); - if (!strbuf->_priv_str) - return NULL; + if (!strbuf->_priv_str) + return NULL; - nm_str_buf_maybe_expand (strbuf, 1, FALSE); - strbuf->_priv_str[strbuf->_priv_len] = '\0'; - return strbuf->_priv_str; + nm_str_buf_maybe_expand(strbuf, 1, FALSE); + strbuf->_priv_str[strbuf->_priv_len] = '\0'; + return strbuf->_priv_str; } static inline char * -nm_str_buf_get_str_unsafe (NMStrBuf *strbuf) +nm_str_buf_get_str_unsafe(NMStrBuf *strbuf) { - _nm_str_buf_assert (strbuf); - return strbuf->_priv_str; + _nm_str_buf_assert(strbuf); + return strbuf->_priv_str; } /** @@ -314,22 +374,38 @@ nm_str_buf_get_str_unsafe (NMStrBuf *strbuf) * Note that if no string is allocated yet (after nm_str_buf_init() with * length zero), this will return %NULL. */ static inline char * -nm_str_buf_finalize (NMStrBuf *strbuf, - gsize *out_len) +nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len) { - _nm_str_buf_assert (strbuf); + _nm_str_buf_assert(strbuf); + + NM_SET_OUT(out_len, strbuf->_priv_len); - NM_SET_OUT (out_len, strbuf->_priv_len); + if (!strbuf->_priv_str) + return NULL; - if (!strbuf->_priv_str) - return NULL; + nm_str_buf_maybe_expand(strbuf, 1, TRUE); + strbuf->_priv_str[strbuf->_priv_len] = '\0'; - nm_str_buf_maybe_expand (strbuf, 1, TRUE); - strbuf->_priv_str[strbuf->_priv_len] = '\0'; + /* the buffer is in invalid state afterwards, however, we clear it + * so far, that nm_auto_str_buf and nm_str_buf_destroy() is happy. */ + return g_steal_pointer(&strbuf->_priv_str); +} - /* the buffer is in invalid state afterwards, however, we clear it - * so far, that nm_auto_str_buf and nm_str_buf_destroy() is happy. */ - 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); } /** @@ -341,21 +417,21 @@ nm_str_buf_finalize (NMStrBuf *strbuf, * with nm_str_buf_init(). */ static inline void -nm_str_buf_destroy (NMStrBuf *strbuf) +nm_str_buf_destroy(NMStrBuf *strbuf) { - if (!strbuf->_priv_str) - return; - _nm_str_buf_assert (strbuf); - if (strbuf->_priv_do_bzero_mem) - nm_explicit_bzero (strbuf->_priv_str, strbuf->_priv_len); - g_free (strbuf->_priv_str); - - /* the buffer is in invalid state afterwards, however, we clear it - * so far, that nm_auto_str_buf is happy when calling - * nm_str_buf_destroy() again. */ - strbuf->_priv_str = NULL; + if (!strbuf->_priv_str) + return; + _nm_str_buf_assert(strbuf); + if (strbuf->_priv_do_bzero_mem) + nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len); + g_free(strbuf->_priv_str); + + /* the buffer is in invalid state afterwards, however, we clear it + * so far, that nm_auto_str_buf is happy when calling + * nm_str_buf_destroy() again. */ + strbuf->_priv_str = NULL; } -#define nm_auto_str_buf nm_auto (nm_str_buf_destroy) +#define nm_auto_str_buf nm_auto(nm_str_buf_destroy) #endif /* __NM_STR_BUF_H__ */ diff --git a/shared/nm-glib-aux/nm-time-utils.c b/shared/nm-glib-aux/nm-time-utils.c index 356ed1a5..511363c3 100644 --- a/shared/nm-glib-aux/nm-time-utils.c +++ b/shared/nm-glib-aux/nm-time-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -12,97 +12,94 @@ /*****************************************************************************/ typedef struct { - /* the offset to the native clock, in seconds. */ - gint64 offset_sec; - clockid_t clk_id; + /* the offset to the native clock, in seconds. */ + gint64 offset_sec; + clockid_t clk_id; } GlobalState; static const GlobalState *volatile p_global_state; static const GlobalState * -_t_init_global_state (void) +_t_init_global_state(void) { - static GlobalState global_state = { }; - static gsize init_once = 0; - const GlobalState *p; - clockid_t clk_id; - struct timespec tp; - gint64 offset_sec; - int r; - - clk_id = CLOCK_BOOTTIME; - r = clock_gettime (clk_id, &tp); - if (r == -1 && errno == EINVAL) { - clk_id = CLOCK_MONOTONIC; - r = clock_gettime (clk_id, &tp); - } - - /* The only failure we tolerate is that CLOCK_BOOTTIME is not supported. - * Other than that, we rely on kernel to not fail on this. */ - g_assert (r == 0); - g_assert (tp.tv_nsec >= 0 && tp.tv_nsec < NM_UTILS_NSEC_PER_SEC); - - /* Calculate an offset for the time stamp. - * - * We always want positive values, because then we can initialize - * a timestamp with 0 and be sure, that it will be less then any - * value nm_utils_get_monotonic_timestamp_*() might return. - * For this to be true also for nm_utils_get_monotonic_timestamp_sec() at - * early boot, we have to shift the timestamp to start counting at - * least from 1 second onward. - * - * Another advantage of shifting is, that this way we make use of the whole 31 bit - * range of signed int, before the time stamp for nm_utils_get_monotonic_timestamp_sec() - * wraps (~68 years). - **/ - offset_sec = (- ((gint64) tp.tv_sec)) + 1; - - if (!g_once_init_enter (&init_once)) { - /* there was a race. We expect the pointer to be fully initialized now. */ - p = g_atomic_pointer_get (&p_global_state); - g_assert (p); - return p; - } - - global_state.offset_sec = offset_sec; - global_state.clk_id = clk_id; - p = &global_state; - g_atomic_pointer_set (&p_global_state, p); - g_once_init_leave (&init_once, 1); - - _nm_utils_monotonic_timestamp_initialized (&tp, - p->offset_sec, - p->clk_id == CLOCK_BOOTTIME); - - return p; + static GlobalState global_state = {}; + static gsize init_once = 0; + const GlobalState *p; + clockid_t clk_id; + struct timespec tp; + gint64 offset_sec; + int r; + + clk_id = CLOCK_BOOTTIME; + r = clock_gettime(clk_id, &tp); + if (r == -1 && errno == EINVAL) { + clk_id = CLOCK_MONOTONIC; + r = clock_gettime(clk_id, &tp); + } + + /* The only failure we tolerate is that CLOCK_BOOTTIME is not supported. + * Other than that, we rely on kernel to not fail on this. */ + g_assert(r == 0); + g_assert(tp.tv_nsec >= 0 && tp.tv_nsec < NM_UTILS_NSEC_PER_SEC); + + /* Calculate an offset for the time stamp. + * + * We always want positive values, because then we can initialize + * a timestamp with 0 and be sure, that it will be less then any + * value nm_utils_get_monotonic_timestamp_*() might return. + * For this to be true also for nm_utils_get_monotonic_timestamp_sec() at + * early boot, we have to shift the timestamp to start counting at + * least from 1 second onward. + * + * Another advantage of shifting is, that this way we make use of the whole 31 bit + * range of signed int, before the time stamp for nm_utils_get_monotonic_timestamp_sec() + * wraps (~68 years). + **/ + offset_sec = (-((gint64) tp.tv_sec)) + 1; + + if (!g_once_init_enter(&init_once)) { + /* there was a race. We expect the pointer to be fully initialized now. */ + p = g_atomic_pointer_get(&p_global_state); + g_assert(p); + return p; + } + + global_state.offset_sec = offset_sec; + global_state.clk_id = clk_id; + p = &global_state; + g_atomic_pointer_set(&p_global_state, p); + g_once_init_leave(&init_once, 1); + + _nm_utils_monotonic_timestamp_initialized(&tp, p->offset_sec, p->clk_id == CLOCK_BOOTTIME); + + return p; } -#define _t_get_global_state() \ - ({ \ - const GlobalState *_p; \ - \ - _p = g_atomic_pointer_get (&p_global_state); \ - (G_LIKELY (_p) ? _p : _t_init_global_state ()); \ - }) - -#define _t_clock_gettime_eval(p, tp) \ - ({ \ - struct timespec *const _tp = (tp); \ - const GlobalState *const _p2 = (p); \ - int _r; \ - \ - nm_assert (_tp); \ - \ - _r = clock_gettime (_p2->clk_id, _tp); \ - \ - nm_assert (_r == 0); \ - nm_assert (_tp->tv_nsec >= 0 && _tp->tv_nsec < NM_UTILS_NSEC_PER_SEC); \ - \ - _p2; \ - }) - -#define _t_clock_gettime(tp) \ - _t_clock_gettime_eval (_t_get_global_state (), tp); +#define _t_get_global_state() \ + ({ \ + const GlobalState *_p; \ + \ + _p = g_atomic_pointer_get(&p_global_state); \ + (G_LIKELY(_p) ? _p : _t_init_global_state()); \ + }) + +#define _t_clock_gettime_eval(p, tp) \ + ({ \ + struct timespec *const _tp = (tp); \ + const GlobalState *const _p2 = (p); \ + int _r; \ + \ + nm_assert(_tp); \ + \ + _r = clock_gettime(_p2->clk_id, _tp); \ + \ + nm_assert(_r == 0); \ + nm_assert(_tp->tv_nsec >= 0 && _tp->tv_nsec < NM_UTILS_NSEC_PER_SEC); \ + \ + _p2; \ + }) + +#define _t_clock_gettime(tp) _t_clock_gettime_eval(_t_get_global_state(), tp); /*****************************************************************************/ @@ -119,19 +116,18 @@ _t_init_global_state (void) * timestamp but in different scales (nsec, usec, msec, sec). **/ gint64 -nm_utils_get_monotonic_timestamp_nsec (void) +nm_utils_get_monotonic_timestamp_nsec(void) { - const GlobalState *p; - struct timespec tp; + const GlobalState *p; + struct timespec tp; - p = _t_clock_gettime (&tp); + p = _t_clock_gettime(&tp); - /* Although the result will always be positive, we return a signed - * integer, which makes it easier to calculate time differences (when - * you want to subtract signed values). - **/ - return (((gint64) tp.tv_sec) + p->offset_sec) * NM_UTILS_NSEC_PER_SEC + - tp.tv_nsec; + /* Although the result will always be positive, we return a signed + * integer, which makes it easier to calculate time differences (when + * you want to subtract signed values). + **/ + return (((gint64) tp.tv_sec) + p->offset_sec) * NM_UTILS_NSEC_PER_SEC + tp.tv_nsec; } /** @@ -147,19 +143,19 @@ nm_utils_get_monotonic_timestamp_nsec (void) * timestamp but in different scales (nsec, usec, msec, sec). **/ gint64 -nm_utils_get_monotonic_timestamp_usec (void) +nm_utils_get_monotonic_timestamp_usec(void) { - const GlobalState *p; - struct timespec tp; + const GlobalState *p; + struct timespec tp; - p = _t_clock_gettime (&tp); + p = _t_clock_gettime(&tp); - /* Although the result will always be positive, we return a signed - * integer, which makes it easier to calculate time differences (when - * you want to subtract signed values). - **/ - return (((gint64) tp.tv_sec) + p->offset_sec) * ((gint64) G_USEC_PER_SEC) + - (tp.tv_nsec / (NM_UTILS_NSEC_PER_SEC/G_USEC_PER_SEC)); + /* Although the result will always be positive, we return a signed + * integer, which makes it easier to calculate time differences (when + * you want to subtract signed values). + **/ + return (((gint64) tp.tv_sec) + p->offset_sec) * ((gint64) G_USEC_PER_SEC) + + (tp.tv_nsec / (NM_UTILS_NSEC_PER_SEC / G_USEC_PER_SEC)); } /** @@ -175,19 +171,19 @@ nm_utils_get_monotonic_timestamp_usec (void) * timestamp but in different scales (nsec, usec, msec, sec). **/ gint64 -nm_utils_get_monotonic_timestamp_msec (void) +nm_utils_get_monotonic_timestamp_msec(void) { - const GlobalState *p; - struct timespec tp; + const GlobalState *p; + struct timespec tp; - p = _t_clock_gettime (&tp); + p = _t_clock_gettime(&tp); - /* Although the result will always be positive, we return a signed - * integer, which makes it easier to calculate time differences (when - * you want to subtract signed values). - **/ - return (((gint64) tp.tv_sec) + p->offset_sec) * ((gint64) 1000) + - (tp.tv_nsec / (NM_UTILS_NSEC_PER_SEC/1000)); + /* Although the result will always be positive, we return a signed + * integer, which makes it easier to calculate time differences (when + * you want to subtract signed values). + **/ + return (((gint64) tp.tv_sec) + p->offset_sec) * ((gint64) 1000) + + (tp.tv_nsec / (NM_UTILS_NSEC_PER_SEC / 1000)); } /** @@ -203,14 +199,14 @@ nm_utils_get_monotonic_timestamp_msec (void) * timestamp but in different scales (nsec, usec, msec, sec). **/ gint32 -nm_utils_get_monotonic_timestamp_sec (void) +nm_utils_get_monotonic_timestamp_sec(void) { - const GlobalState *p; - struct timespec tp; + const GlobalState *p; + struct timespec tp; - p = _t_clock_gettime (&tp); + p = _t_clock_gettime(&tp); - return (((gint64) tp.tv_sec) + p->offset_sec); + return (((gint64) tp.tv_sec) + p->offset_sec); } /** @@ -234,35 +230,35 @@ nm_utils_get_monotonic_timestamp_sec (void) * On older kernels that don't support CLOCK_BOOTTIME, the returned time is instead CLOCK_MONOTONIC. **/ gint64 -nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_nsec_per_tick) +nm_utils_monotonic_timestamp_as_boottime(gint64 timestamp, gint64 timestamp_nsec_per_tick) { - const GlobalState *p; - gint64 offset; + const GlobalState *p; + gint64 offset; - /* only support nsec-per-tick being a multiple of 10. */ - g_return_val_if_fail ( timestamp_nsec_per_tick == 1 - || (timestamp_nsec_per_tick > 0 && - timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC && - timestamp_nsec_per_tick % 10 == 0), - -1); + /* only support nsec-per-tick being a multiple of 10. */ + g_return_val_if_fail(timestamp_nsec_per_tick == 1 + || (timestamp_nsec_per_tick > 0 + && timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC + && timestamp_nsec_per_tick % 10 == 0), + -1); - /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful - * value (because he has no idea what these timestamps would be). That would be a bug. */ - nm_assert (g_atomic_pointer_get (&p_global_state)); + /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful + * value (because he has no idea what these timestamps would be). That would be a bug. */ + nm_assert(g_atomic_pointer_get(&p_global_state)); - p = _t_get_global_state (); + p = _t_get_global_state(); - nm_assert (p->offset_sec <= 0); + nm_assert(p->offset_sec <= 0); - /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ - offset = p->offset_sec * (NM_UTILS_NSEC_PER_SEC / timestamp_nsec_per_tick); + /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ + offset = p->offset_sec * (NM_UTILS_NSEC_PER_SEC / timestamp_nsec_per_tick); - nm_assert (offset <= 0 && offset > G_MININT64); + nm_assert(offset <= 0 && offset > G_MININT64); - /* check for overflow (note that offset is non-positive). */ - g_return_val_if_fail (timestamp < G_MAXINT64 + offset, G_MAXINT64); + /* check for overflow (note that offset is non-positive). */ + g_return_val_if_fail(timestamp < G_MAXINT64 + offset, G_MAXINT64); - return timestamp - offset; + return timestamp - offset; } /** @@ -284,49 +280,49 @@ nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_nse * This is the inverse of nm_utils_monotonic_timestamp_as_boottime(). */ gint64 -nm_utils_monotonic_timestamp_from_boottime (guint64 boottime, gint64 timestamp_nsec_per_tick) +nm_utils_monotonic_timestamp_from_boottime(guint64 boottime, gint64 timestamp_nsec_per_tick) { - const GlobalState *p; - gint64 offset; + const GlobalState *p; + gint64 offset; - /* only support nsec-per-tick being a multiple of 10. */ - g_return_val_if_fail ( timestamp_nsec_per_tick == 1 - || (timestamp_nsec_per_tick > 0 && - timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC && - timestamp_nsec_per_tick % 10 == 0), - -1); + /* only support nsec-per-tick being a multiple of 10. */ + g_return_val_if_fail(timestamp_nsec_per_tick == 1 + || (timestamp_nsec_per_tick > 0 + && timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC + && timestamp_nsec_per_tick % 10 == 0), + -1); - p = _t_get_global_state (); + p = _t_get_global_state(); - nm_assert (p->offset_sec <= 0); + nm_assert(p->offset_sec <= 0); - /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ - offset = p->offset_sec * (NM_UTILS_NSEC_PER_SEC / timestamp_nsec_per_tick); + /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */ + offset = p->offset_sec * (NM_UTILS_NSEC_PER_SEC / timestamp_nsec_per_tick); - nm_assert (offset <= 0 && offset > G_MININT64); + nm_assert(offset <= 0 && offset > G_MININT64); - /* check for overflow (note that offset is non-positive). */ - g_return_val_if_fail (boottime < G_MAXINT64, G_MAXINT64); + /* check for overflow (note that offset is non-positive). */ + g_return_val_if_fail(boottime < G_MAXINT64, G_MAXINT64); - return (gint64) boottime + offset; + return (gint64) boottime + offset; } gint64 -nm_utils_clock_gettime_nsec (clockid_t clockid) +nm_utils_clock_gettime_nsec(clockid_t clockid) { - struct timespec tp; + struct timespec tp; - if (clock_gettime (clockid, &tp) != 0) - return -NM_ERRNO_NATIVE (errno); - return nm_utils_timespec_to_nsec (&tp); + if (clock_gettime(clockid, &tp) != 0) + return -NM_ERRNO_NATIVE(errno); + return nm_utils_timespec_to_nsec(&tp); } gint64 -nm_utils_clock_gettime_msec (clockid_t clockid) +nm_utils_clock_gettime_msec(clockid_t clockid) { - struct timespec tp; + struct timespec tp; - if (clock_gettime (clockid, &tp) != 0) - return -NM_ERRNO_NATIVE (errno); - return nm_utils_timespec_to_msec (&tp); + if (clock_gettime(clockid, &tp) != 0) + return -NM_ERRNO_NATIVE(errno); + return nm_utils_timespec_to_msec(&tp); } diff --git a/shared/nm-glib-aux/nm-time-utils.h b/shared/nm-glib-aux/nm-time-utils.h index 190d9491..77aeae5b 100644 --- a/shared/nm-glib-aux/nm-time-utils.h +++ b/shared/nm-glib-aux/nm-time-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -9,42 +9,39 @@ #include <time.h> static inline gint64 -nm_utils_timespec_to_nsec (const struct timespec *ts) +nm_utils_timespec_to_nsec(const struct timespec *ts) { - return (((gint64) ts->tv_sec) * ((gint64) NM_UTILS_NSEC_PER_SEC)) - + ((gint64) ts->tv_nsec); + return (((gint64) ts->tv_sec) * ((gint64) NM_UTILS_NSEC_PER_SEC)) + ((gint64) ts->tv_nsec); } static inline gint64 -nm_utils_timespec_to_msec (const struct timespec *ts) +nm_utils_timespec_to_msec(const struct timespec *ts) { - return (((gint64) ts->tv_sec) * ((gint64) 1000)) - + (((gint64) ts->tv_nsec) / ((gint64) NM_UTILS_NSEC_PER_SEC / 1000)); + return (((gint64) ts->tv_sec) * ((gint64) 1000)) + + (((gint64) ts->tv_nsec) / ((gint64) NM_UTILS_NSEC_PER_SEC / 1000)); } -gint64 nm_utils_get_monotonic_timestamp_nsec (void); -gint64 nm_utils_get_monotonic_timestamp_usec (void); -gint64 nm_utils_get_monotonic_timestamp_msec (void); -gint32 nm_utils_get_monotonic_timestamp_sec (void); +gint64 nm_utils_get_monotonic_timestamp_nsec(void); +gint64 nm_utils_get_monotonic_timestamp_usec(void); +gint64 nm_utils_get_monotonic_timestamp_msec(void); +gint32 nm_utils_get_monotonic_timestamp_sec(void); -gint64 nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ticks_per_nsec); -gint64 nm_utils_monotonic_timestamp_from_boottime (guint64 boottime, gint64 timestamp_nsec_per_tick); +gint64 nm_utils_monotonic_timestamp_as_boottime(gint64 timestamp, gint64 timestamp_ticks_per_nsec); +gint64 nm_utils_monotonic_timestamp_from_boottime(guint64 boottime, gint64 timestamp_nsec_per_tick); static inline gint64 -nm_utils_get_monotonic_timestamp_nsec_cached (gint64 *cache_now) +nm_utils_get_monotonic_timestamp_nsec_cached(gint64 *cache_now) { - return (*cache_now) - ?: (*cache_now = nm_utils_get_monotonic_timestamp_nsec ()); + return (*cache_now) ?: (*cache_now = nm_utils_get_monotonic_timestamp_nsec()); } static inline gint64 -nm_utils_get_monotonic_timestamp_msec_cached (gint64 *cache_now) +nm_utils_get_monotonic_timestamp_msec_cached(gint64 *cache_now) { - return (*cache_now) - ?: (*cache_now = nm_utils_get_monotonic_timestamp_msec ()); + return (*cache_now) ?: (*cache_now = nm_utils_get_monotonic_timestamp_msec()); } -gint64 nm_utils_clock_gettime_nsec (clockid_t clockid); -gint64 nm_utils_clock_gettime_msec (clockid_t clockid); +gint64 nm_utils_clock_gettime_nsec(clockid_t clockid); +gint64 nm_utils_clock_gettime_msec(clockid_t clockid); #endif /* __NM_TIME_UTILS_H__ */ diff --git a/shared/nm-glib-aux/nm-value-type.h b/shared/nm-glib-aux/nm-value-type.h index 6fe6f072..c07f1104 100644 --- a/shared/nm-glib-aux/nm-value-type.h +++ b/shared/nm-glib-aux/nm-value-type.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2019 Red Hat, Inc. */ @@ -7,11 +7,11 @@ #define __NM_VALUE_TYPE_H__ typedef enum { - NM_VALUE_TYPE_UNSPEC = 1, - NM_VALUE_TYPE_BOOL = 2, - NM_VALUE_TYPE_INT32 = 3, - NM_VALUE_TYPE_INT = 4, - NM_VALUE_TYPE_STRING = 5, + NM_VALUE_TYPE_UNSPEC = 1, + NM_VALUE_TYPE_BOOL = 2, + NM_VALUE_TYPE_INT32 = 3, + NM_VALUE_TYPE_INT = 4, + NM_VALUE_TYPE_STRING = 5, } NMValueType; /*****************************************************************************/ @@ -19,176 +19,191 @@ typedef enum { #ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS typedef union { - bool v_bool; - gint32 v_int32; - int v_int; - const char *v_string; + bool v_bool; + gint32 v_int32; + int v_int; + const char *v_string; - /* for convenience, also let the union contain other pointer types. These are - * for NM_VALUE_TYPE_UNSPEC. */ - gconstpointer *v_ptr; - const GPtrArray *v_ptrarray; + /* for convenience, also let the union contain other pointer types. These are + * for NM_VALUE_TYPE_UNSPEC. */ + gconstpointer * v_ptr; + const GPtrArray *v_ptrarray; } NMValueTypUnion; -/* Set the NMValueTypUnion. You can also assign the member directly. + /* Set the NMValueTypUnion. You can also assign the member directly. * The only purpose of this is that it also returns a pointer to the * union. So, you can do * * ptr = NM_VALUE_TYP_UNION_SET (&value_typ_union_storage, v_bool, TRUE); */ -#define NM_VALUE_TYP_UNION_SET(_arg, _type, _val) \ - ({ \ - NMValueTypUnion *const _arg2 = (_arg); \ - \ - *_arg2 = (NMValueTypUnion) { \ - ._type = (_val), \ - }; \ - _arg2; \ - }) + #define NM_VALUE_TYP_UNION_SET(_arg, _type, _val) \ + ({ \ + NMValueTypUnion *const _arg2 = (_arg); \ + \ + *_arg2 = (NMValueTypUnion){ \ + ._type = (_val), \ + }; \ + _arg2; \ + }) typedef struct { - bool has; - NMValueTypUnion val; + bool has; + NMValueTypUnion val; } NMValueTypUnioMaybe; -#define NM_VALUE_TYP_UNIO_MAYBE_SET(_arg, _type, _val) \ - ({ \ - NMValueTypUnioMaybe *const _arg2 = (_arg); \ - \ - *_arg2 = (NMValueTypUnioMaybe) { \ - .has = TRUE, \ - .val._type = (_val), \ - }; \ - _arg2; \ - }) + #define NM_VALUE_TYP_UNIO_MAYBE_SET(_arg, _type, _val) \ + ({ \ + NMValueTypUnioMaybe *const _arg2 = (_arg); \ + \ + *_arg2 = (NMValueTypUnioMaybe){ \ + .has = TRUE, \ + .val._type = (_val), \ + }; \ + _arg2; \ + }) /*****************************************************************************/ static inline int -nm_value_type_cmp (NMValueType value_type, - gconstpointer p_a, - gconstpointer p_b) +nm_value_type_cmp(NMValueType value_type, gconstpointer p_a, gconstpointer p_b) { - switch (value_type) { - case NM_VALUE_TYPE_BOOL: NM_CMP_DIRECT (*((const bool *) p_a), *((const bool *) p_b)); return 0; - case NM_VALUE_TYPE_INT32: NM_CMP_DIRECT (*((const gint32 *) p_a), *((const gint32 *) p_b)); return 0; - case NM_VALUE_TYPE_INT: NM_CMP_DIRECT (*((const int *) p_a), *((const int *) p_b)); return 0; - case NM_VALUE_TYPE_STRING: return nm_strcmp0 (*((const char *const*) p_a), *((const char *const*) p_b)); - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); - return 0; + switch (value_type) { + case NM_VALUE_TYPE_BOOL: + NM_CMP_DIRECT(*((const bool *) p_a), *((const bool *) p_b)); + return 0; + case NM_VALUE_TYPE_INT32: + NM_CMP_DIRECT(*((const gint32 *) p_a), *((const gint32 *) p_b)); + return 0; + case NM_VALUE_TYPE_INT: + NM_CMP_DIRECT(*((const int *) p_a), *((const int *) p_b)); + return 0; + case NM_VALUE_TYPE_STRING: + return nm_strcmp0(*((const char *const *) p_a), *((const char *const *) p_b)); + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached(); + return 0; } static inline gboolean -nm_value_type_equal (NMValueType value_type, - gconstpointer p_a, - gconstpointer p_b) +nm_value_type_equal(NMValueType value_type, gconstpointer p_a, gconstpointer p_b) { - return nm_value_type_cmp (value_type, p_a, p_b) == 0; + return nm_value_type_cmp(value_type, p_a, p_b) == 0; } static inline void -nm_value_type_copy (NMValueType value_type, - gpointer dst, - gconstpointer src) +nm_value_type_copy(NMValueType value_type, gpointer dst, gconstpointer src) { - switch (value_type) { - case NM_VALUE_TYPE_BOOL: (*((bool *) dst) = *((const bool *) src)); return; - case NM_VALUE_TYPE_INT32: (*((gint32 *) dst) = *((const gint32 *) src)); return; - case NM_VALUE_TYPE_INT: (*((int *) dst) = *((const int *) src)); return; - case NM_VALUE_TYPE_STRING: - /* self assignment safe! */ - if (*((char **) dst) != *((const char *const*) src)) { - g_free (*((char **) dst)); - *((char **) dst) = g_strdup (*((const char *const*) src)); - } - return; - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); + switch (value_type) { + case NM_VALUE_TYPE_BOOL: + (*((bool *) dst) = *((const bool *) src)); + return; + case NM_VALUE_TYPE_INT32: + (*((gint32 *) dst) = *((const gint32 *) src)); + return; + case NM_VALUE_TYPE_INT: + (*((int *) dst) = *((const int *) src)); + return; + case NM_VALUE_TYPE_STRING: + /* self assignment safe! */ + if (*((char **) dst) != *((const char *const *) src)) { + g_free(*((char **) dst)); + *((char **) dst) = g_strdup(*((const char *const *) src)); + } + return; + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached(); } static inline void -nm_value_type_get_from_variant (NMValueType value_type, - gpointer dst, - GVariant *variant, - gboolean clone) +nm_value_type_get_from_variant(NMValueType value_type, + gpointer dst, + GVariant * variant, + gboolean clone) { - switch (value_type) { - case NM_VALUE_TYPE_BOOL: *((bool *) dst) = g_variant_get_boolean (variant); return; - case NM_VALUE_TYPE_INT32: *((gint32 *) dst) = g_variant_get_int32 (variant); return; - case NM_VALUE_TYPE_STRING: - if (clone) { - g_free (*((char **) dst)); - *((char **) dst) = g_variant_dup_string (variant, NULL); - } else { - /* we don't clone the string, nor free the previous value. */ - *((const char **) dst) = g_variant_get_string (variant, NULL); - } - return; - - case NM_VALUE_TYPE_INT: - /* "int" also does not have a define variant type, because it's not - * clear how many bits we would need. */ - - /* fall-through */ - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); + switch (value_type) { + case NM_VALUE_TYPE_BOOL: + *((bool *) dst) = g_variant_get_boolean(variant); + return; + case NM_VALUE_TYPE_INT32: + *((gint32 *) dst) = g_variant_get_int32(variant); + return; + case NM_VALUE_TYPE_STRING: + if (clone) { + g_free(*((char **) dst)); + *((char **) dst) = g_variant_dup_string(variant, NULL); + } else { + /* we don't clone the string, nor free the previous value. */ + *((const char **) dst) = g_variant_get_string(variant, NULL); + } + return; + + case NM_VALUE_TYPE_INT: + /* "int" also does not have a define variant type, because it's not + * clear how many bits we would need. */ + + /* fall-through */ + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached(); } static inline GVariant * -nm_value_type_to_variant (NMValueType value_type, - gconstpointer src) +nm_value_type_to_variant(NMValueType value_type, gconstpointer src) { - const char *v_string; - - switch (value_type) { - case NM_VALUE_TYPE_BOOL: return g_variant_new_boolean (*((const bool *) src)); - case NM_VALUE_TYPE_INT32: return g_variant_new_int32 (*((const gint32 *) src));; - case NM_VALUE_TYPE_STRING: - v_string = *((const char *const*) src); - return v_string ? g_variant_new_string (v_string) : NULL; - - case NM_VALUE_TYPE_INT: - /* "int" also does not have a define variant type, because it's not - * clear how many bits we would need. */ - - /* fall-through */ - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); - return NULL; + const char *v_string; + + switch (value_type) { + case NM_VALUE_TYPE_BOOL: + return g_variant_new_boolean(*((const bool *) src)); + case NM_VALUE_TYPE_INT32: + return g_variant_new_int32(*((const gint32 *) src)); + case NM_VALUE_TYPE_STRING: + v_string = *((const char *const *) src); + return v_string ? g_variant_new_string(v_string) : NULL; + + case NM_VALUE_TYPE_INT: + /* "int" also does not have a define variant type, because it's not + * clear how many bits we would need. */ + + /* fall-through */ + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached(); + return NULL; } static inline const GVariantType * -nm_value_type_get_variant_type (NMValueType value_type) +nm_value_type_get_variant_type(NMValueType value_type) { - switch (value_type) { - case NM_VALUE_TYPE_BOOL: return G_VARIANT_TYPE_BOOLEAN; - case NM_VALUE_TYPE_INT32: return G_VARIANT_TYPE_INT32; - case NM_VALUE_TYPE_STRING: return G_VARIANT_TYPE_STRING; - - case NM_VALUE_TYPE_INT: - /* "int" also does not have a define variant type, because it's not - * clear how many bits we would need. */ - - /* fall-through */ - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); - return NULL; + switch (value_type) { + case NM_VALUE_TYPE_BOOL: + return G_VARIANT_TYPE_BOOLEAN; + case NM_VALUE_TYPE_INT32: + return G_VARIANT_TYPE_INT32; + case NM_VALUE_TYPE_STRING: + return G_VARIANT_TYPE_STRING; + + case NM_VALUE_TYPE_INT: + /* "int" also does not have a define variant type, because it's not + * clear how many bits we would need. */ + + /* fall-through */ + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached(); + return NULL; } -/*****************************************************************************/ + /*****************************************************************************/ #endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */ -#endif /* __NM_VALUE_TYPE_H__ */ +#endif /* __NM_VALUE_TYPE_H__ */ diff --git a/shared/nm-glib-aux/tests/meson.build b/shared/nm-glib-aux/tests/meson.build index f6328db9..8136eff9 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 00000000..5331c015 --- /dev/null +++ b/shared/nm-glib-aux/tests/test-json-aux.c @@ -0,0 +1,167 @@ +/* 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 5c8bdf18..84e0a6f0 100644 --- a/shared/nm-glib-aux/tests/test-shared-general.c +++ b/shared/nm-glib-aux/tests/test-shared-general.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -17,781 +17,1255 @@ /*****************************************************************************/ +G_STATIC_ASSERT(NM_AF_UNSPEC == AF_UNSPEC); +G_STATIC_ASSERT(NM_AF_INET == AF_INET); +G_STATIC_ASSERT(NM_AF_INET6 == AF_INET6); + +G_STATIC_ASSERT(NM_AF_INET_SIZE == sizeof(in_addr_t)); +G_STATIC_ASSERT(NM_AF_INET_SIZE == sizeof(struct in_addr)); +G_STATIC_ASSERT(NM_AF_INET6_SIZE == sizeof(struct in6_addr)); + +G_STATIC_ASSERT(4 == _nm_alignof(in_addr_t)); +G_STATIC_ASSERT(4 == _nm_alignof(struct in_addr)); +G_STATIC_ASSERT(4 == _nm_alignof(struct in6_addr)); +G_STATIC_ASSERT(4 == _nm_alignof(NMIPAddr)); + +/*****************************************************************************/ + static void -test_gpid (void) +test_gpid(void) { - const int *int_ptr; - GPid pid = 42; - - /* We redefine G_PID_FORMAT, because it's only available since glib 2.53.5. - * - * Also, this is the format for GPid, which for glib is always a typedef - * for "int". Add a check for that here. - * - * G_PID_FORMAT is not about pid_t, which might be a smaller int, and which we would - * check with SIZEOF_PID_T. */ - G_STATIC_ASSERT (sizeof (GPid) == sizeof (int)); - - g_assert_cmpstr (""G_PID_FORMAT, ==, "i"); - - /* check that it's really "int". We will get a compiler warning, if that's not - * the case. */ - int_ptr = &pid; - g_assert_cmpint (*int_ptr, ==, 42); + const int *int_ptr; + GPid pid = 42; + + /* We redefine G_PID_FORMAT, because it's only available since glib 2.53.5. + * + * Also, this is the format for GPid, which for glib is always a typedef + * for "int". Add a check for that here. + * + * G_PID_FORMAT is not about pid_t, which might be a smaller int, and which we would + * check with SIZEOF_PID_T. */ + G_STATIC_ASSERT(sizeof(GPid) == sizeof(int)); + + g_assert_cmpstr("" G_PID_FORMAT, ==, "i"); + + /* check that it's really "int". We will get a compiler warning, if that's not + * the case. */ + int_ptr = &pid; + g_assert_cmpint(*int_ptr, ==, 42); } /*****************************************************************************/ static void -test_monotonic_timestamp (void) +test_monotonic_timestamp(void) { - g_assert (nm_utils_get_monotonic_timestamp_sec () > 0); + g_assert(nm_utils_get_monotonic_timestamp_sec() > 0); } /*****************************************************************************/ static void -test_nmhash (void) +test_nmhash(void) { - int rnd; + int rnd; - nm_utils_random_bytes (&rnd, sizeof (rnd)); + nm_utils_random_bytes(&rnd, sizeof(rnd)); - g_assert (nm_hash_val (555, 4) != 0); + g_assert(nm_hash_val(555, 4) != 0); } /*****************************************************************************/ static const char * -_make_strv_foo (void) +_make_strv_foo(void) { - return "foo"; + return "foo"; } -static const char *const*const _tst_make_strv_1 = NM_MAKE_STRV ("1", "2"); +static const char *const *const _tst_make_strv_1 = NM_MAKE_STRV("1", "2"); static void -test_make_strv (void) +test_make_strv(void) { - const char *const*v1a = NM_MAKE_STRV ("a"); - const char *const*v1b = NM_MAKE_STRV ("a", ); - const char *const*v2a = NM_MAKE_STRV ("a", "b"); - const char *const*v2b = NM_MAKE_STRV ("a", "b", ); - const char *const v3[] = { "a", "b", }; - const char *const*v4b = NM_MAKE_STRV ("a", _make_strv_foo (), ); - - g_assert (NM_PTRARRAY_LEN (v1a) == 1); - g_assert (NM_PTRARRAY_LEN (v1b) == 1); - g_assert (NM_PTRARRAY_LEN (v2a) == 2); - g_assert (NM_PTRARRAY_LEN (v2b) == 2); - - g_assert (NM_PTRARRAY_LEN (_tst_make_strv_1) == 2); - g_assert_cmpstr (_tst_make_strv_1[0], ==, "1"); - g_assert_cmpstr (_tst_make_strv_1[1], ==, "2"); - /* writing the static read-only variable leads to crash .*/ - //((char **) _tst_make_strv_1)[0] = NULL; - //((char **) _tst_make_strv_1)[2] = "c"; - - G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (v3) == 2); - - g_assert (NM_PTRARRAY_LEN (v4b) == 2); - - G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b" )) == 3); - G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (NM_MAKE_STRV ("a", "b", )) == 3); - - nm_strquote_a (300, ""); + const char *const *v1a = NM_MAKE_STRV("a"); + const char *const *v1b = NM_MAKE_STRV("a", ); + const char *const *v2a = NM_MAKE_STRV("a", "b"); + const char *const *v2b = NM_MAKE_STRV("a", "b", ); + const char *const v3[] = { + "a", + "b", + }; + const char *const *v4b = NM_MAKE_STRV("a", _make_strv_foo(), ); + + g_assert(NM_PTRARRAY_LEN(v1a) == 1); + g_assert(NM_PTRARRAY_LEN(v1b) == 1); + g_assert(NM_PTRARRAY_LEN(v2a) == 2); + g_assert(NM_PTRARRAY_LEN(v2b) == 2); + + g_assert(NM_PTRARRAY_LEN(_tst_make_strv_1) == 2); + g_assert_cmpstr(_tst_make_strv_1[0], ==, "1"); + g_assert_cmpstr(_tst_make_strv_1[1], ==, "2"); + /* writing the static read-only variable leads to crash .*/ + //((char **) _tst_make_strv_1)[0] = NULL; + //((char **) _tst_make_strv_1)[2] = "c"; + + G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(v3) == 2); + + g_assert(NM_PTRARRAY_LEN(v4b) == 2); + + G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(NM_MAKE_STRV("a", "b")) == 3); + G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(NM_MAKE_STRV("a", "b", )) == 3); + + nm_strquote_a(300, ""); } /*****************************************************************************/ typedef enum { - TEST_NM_STRDUP_ENUM_m1 = -1, - TEST_NM_STRDUP_ENUM_3 = 3, + TEST_NM_STRDUP_ENUM_m1 = -1, + TEST_NM_STRDUP_ENUM_3 = 3, } TestNMStrdupIntEnum; static void -test_nm_strdup_int (void) +test_nm_strdup_int(void) { -#define _NM_STRDUP_INT_TEST(num, str) \ - G_STMT_START { \ - gs_free char *_s1 = NULL; \ - \ - _s1 = nm_strdup_int ((num)); \ - \ - g_assert (_s1); \ - g_assert_cmpstr (_s1, ==, str); \ - } G_STMT_END - -#define _NM_STRDUP_INT_TEST_TYPED(type, num) \ - G_STMT_START { \ - type _num = ((type) num); \ - \ - _NM_STRDUP_INT_TEST (_num, G_STRINGIFY (num)); \ - } G_STMT_END - - _NM_STRDUP_INT_TEST_TYPED (char, 0); - _NM_STRDUP_INT_TEST_TYPED (char, 1); - _NM_STRDUP_INT_TEST_TYPED (guint8, 0); - _NM_STRDUP_INT_TEST_TYPED (gint8, 25); - _NM_STRDUP_INT_TEST_TYPED (char, 47); - _NM_STRDUP_INT_TEST_TYPED (short, 47); - _NM_STRDUP_INT_TEST_TYPED (int, 47); - _NM_STRDUP_INT_TEST_TYPED (long, 47); - _NM_STRDUP_INT_TEST_TYPED (unsigned char, 47); - _NM_STRDUP_INT_TEST_TYPED (unsigned short, 47); - _NM_STRDUP_INT_TEST_TYPED (unsigned, 47); - _NM_STRDUP_INT_TEST_TYPED (unsigned long, 47); - _NM_STRDUP_INT_TEST_TYPED (gint64, 9223372036854775807); - _NM_STRDUP_INT_TEST_TYPED (gint64, -9223372036854775807); - _NM_STRDUP_INT_TEST_TYPED (guint64, 0); - _NM_STRDUP_INT_TEST_TYPED (guint64, 9223372036854775807); - - _NM_STRDUP_INT_TEST (TEST_NM_STRDUP_ENUM_m1, "-1"); - _NM_STRDUP_INT_TEST (TEST_NM_STRDUP_ENUM_3, "3"); +#define _NM_STRDUP_INT_TEST(num, str) \ + G_STMT_START \ + { \ + gs_free char *_s1 = NULL; \ + \ + _s1 = nm_strdup_int((num)); \ + \ + g_assert(_s1); \ + g_assert_cmpstr(_s1, ==, str); \ + } \ + G_STMT_END + +#define _NM_STRDUP_INT_TEST_TYPED(type, num) \ + G_STMT_START \ + { \ + type _num = ((type) num); \ + \ + _NM_STRDUP_INT_TEST(_num, G_STRINGIFY(num)); \ + } \ + G_STMT_END + + _NM_STRDUP_INT_TEST_TYPED(char, 0); + _NM_STRDUP_INT_TEST_TYPED(char, 1); + _NM_STRDUP_INT_TEST_TYPED(guint8, 0); + _NM_STRDUP_INT_TEST_TYPED(gint8, 25); + _NM_STRDUP_INT_TEST_TYPED(char, 47); + _NM_STRDUP_INT_TEST_TYPED(short, 47); + _NM_STRDUP_INT_TEST_TYPED(int, 47); + _NM_STRDUP_INT_TEST_TYPED(long, 47); + _NM_STRDUP_INT_TEST_TYPED(unsigned char, 47); + _NM_STRDUP_INT_TEST_TYPED(unsigned short, 47); + _NM_STRDUP_INT_TEST_TYPED(unsigned, 47); + _NM_STRDUP_INT_TEST_TYPED(unsigned long, 47); + _NM_STRDUP_INT_TEST_TYPED(gint64, 9223372036854775807); + _NM_STRDUP_INT_TEST_TYPED(gint64, -9223372036854775807); + _NM_STRDUP_INT_TEST_TYPED(guint64, 0); + _NM_STRDUP_INT_TEST_TYPED(guint64, 9223372036854775807); + + _NM_STRDUP_INT_TEST(TEST_NM_STRDUP_ENUM_m1, "-1"); + _NM_STRDUP_INT_TEST(TEST_NM_STRDUP_ENUM_3, "3"); } /*****************************************************************************/ static void -test_nm_strndup_a (void) +test_nm_strndup_a(void) { - int run; - - for (run = 0; run < 20; run++) { - gs_free char *input = NULL; - char ch; - gsize i, l; - - input = g_strnfill (nmtst_get_rand_uint32 () % 20, 'x'); - - for (i = 0; input[i]; i++) { - while ((ch = ((char) nmtst_get_rand_uint32 ())) == '\0') { - /* repeat. */ - } - input[i] = ch; - } - - { - gs_free char *dup_free = NULL; - const char *dup; - - l = strlen (input) + 1; - dup = nm_strndup_a (10, input, l - 1, &dup_free); - g_assert_cmpstr (dup, ==, input); - if (strlen (dup) < 10) - g_assert (!dup_free); - else - g_assert (dup == dup_free); - } - - { - gs_free char *dup_free = NULL; - const char *dup; - - l = nmtst_get_rand_uint32 () % 23; - dup = nm_strndup_a (10, input, l, &dup_free); - g_assert (strncmp (dup, input, l) == 0); - g_assert (strlen (dup) <= l); - if (l < 10) - g_assert (!dup_free); - else - g_assert (dup == dup_free); - if (strlen (input) < l) - g_assert (nm_utils_memeqzero (&dup[strlen (input)], l - strlen (input))); - } - } + int run; + + for (run = 0; run < 20; run++) { + gs_free char *input = NULL; + char ch; + gsize i, l; + + input = g_strnfill(nmtst_get_rand_uint32() % 20, 'x'); + + for (i = 0; input[i]; i++) { + while ((ch = ((char) nmtst_get_rand_uint32())) == '\0') { + /* repeat. */ + } + input[i] = ch; + } + + { + gs_free char *dup_free = NULL; + const char * dup; + + l = strlen(input) + 1; + dup = nm_strndup_a(10, input, l - 1, &dup_free); + g_assert_cmpstr(dup, ==, input); + if (strlen(dup) < 10) + g_assert(!dup_free); + else + g_assert(dup == dup_free); + } + + { + gs_free char *dup_free = NULL; + const char * dup; + + l = nmtst_get_rand_uint32() % 23; + dup = nm_strndup_a(10, input, l, &dup_free); + g_assert(strncmp(dup, input, l) == 0); + g_assert(strlen(dup) <= l); + if (l < 10) + g_assert(!dup_free); + else + g_assert(dup == dup_free); + if (strlen(input) < l) + g_assert(nm_utils_memeqzero(&dup[strlen(input)], l - strlen(input))); + } + } } /*****************************************************************************/ static void -test_nm_ip4_addr_is_localhost (void) +test_nm_ip4_addr_is_localhost(void) { - g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.0.0.0"))); - g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.0.0.1"))); - g_assert ( nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("127.5.0.1"))); - g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("126.5.0.1"))); - g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("128.5.0.1"))); - g_assert (!nm_ip4_addr_is_localhost (nmtst_inet4_from_string ("129.5.0.1"))); + g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.0.0.0"))); + g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.0.0.1"))); + g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.5.0.1"))); + g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("126.5.0.1"))); + g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("128.5.0.1"))); + g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("129.5.0.1"))); } /*****************************************************************************/ static void -test_unaligned (void) +test_unaligned(void) { - int shift; + int shift; - for (shift = 0; shift <= 32; shift++) { - guint8 buf[100] = { }; - guint8 val = 0; + for (shift = 0; shift <= 32; shift++) { + guint8 buf[100] = {}; + guint8 val = 0; - while (val == 0) - val = nmtst_get_rand_uint32 () % 256; + while (val == 0) + val = nmtst_get_rand_uint32() % 256; - buf[shift] = val; + buf[shift] = val; - g_assert_cmpint (unaligned_read_le64 (&buf[shift]), ==, (guint64) val); - g_assert_cmpint (unaligned_read_be64 (&buf[shift]), ==, ((guint64) val) << 56); - g_assert_cmpint (unaligned_read_ne64 (&buf[shift]), !=, 0); + g_assert_cmpint(unaligned_read_le64(&buf[shift]), ==, (guint64) val); + g_assert_cmpint(unaligned_read_be64(&buf[shift]), ==, ((guint64) val) << 56); + g_assert_cmpint(unaligned_read_ne64(&buf[shift]), !=, 0); - g_assert_cmpint (unaligned_read_le32 (&buf[shift]), ==, (guint32) val); - g_assert_cmpint (unaligned_read_be32 (&buf[shift]), ==, ((guint32) val) << 24); - g_assert_cmpint (unaligned_read_ne32 (&buf[shift]), !=, 0); + g_assert_cmpint(unaligned_read_le32(&buf[shift]), ==, (guint32) val); + g_assert_cmpint(unaligned_read_be32(&buf[shift]), ==, ((guint32) val) << 24); + g_assert_cmpint(unaligned_read_ne32(&buf[shift]), !=, 0); - g_assert_cmpint (unaligned_read_le16 (&buf[shift]), ==, (guint16) val); - g_assert_cmpint (unaligned_read_be16 (&buf[shift]), ==, ((guint16) val) << 8); - g_assert_cmpint (unaligned_read_ne16 (&buf[shift]), !=, 0); - } + g_assert_cmpint(unaligned_read_le16(&buf[shift]), ==, (guint16) val); + g_assert_cmpint(unaligned_read_be16(&buf[shift]), ==, ((guint16) val) << 8); + g_assert_cmpint(unaligned_read_ne16(&buf[shift]), !=, 0); + } } /*****************************************************************************/ static void -_strv_cmp_fuzz_input (const char *const*in, - gssize l, - const char ***out_strv_free_shallow, - char ***out_strv_free_deep, - const char *const* *out_s1, - const char *const* *out_s2) +_strv_cmp_fuzz_input(const char *const * in, + gssize l, + const char *** out_strv_free_shallow, + char *** out_strv_free_deep, + const char *const **out_s1, + const char *const **out_s2) { - const char **strv; - gsize i; - - /* Fuzz the input argument. It will return two output arrays that are semantically - * equal the input. */ - - if (nmtst_get_rand_bool ()) { - char **ss; - - if (l < 0) - ss = g_strdupv ((char **) in); - else if (l == 0) { - ss = nmtst_get_rand_bool () - ? NULL - : g_new0 (char *, 1); - } else { - ss = nm_memdup (in, sizeof (const char *) * l); - for (i = 0; i < (gsize) l; i++) - ss[i] = g_strdup (ss[i]); - } - strv = (const char **) ss; - *out_strv_free_deep = ss; - } else { - if (l < 0) { - strv = in - ? nm_memdup (in, sizeof (const char *) * (NM_PTRARRAY_LEN (in) + 1)) - : NULL; - } else if (l == 0) { - strv = nmtst_get_rand_bool () - ? NULL - : g_new0 (const char *, 1); - } else - strv = nm_memdup (in, sizeof (const char *) * l); - *out_strv_free_shallow = strv; - } - - *out_s1 = in; - *out_s2 = strv; - - if (nmtst_get_rand_bool ()) { - /* randomly swap the original and the clone. That means, out_s1 is either - * the input argument (as-is) or the sementically equal clone. */ - NM_SWAP (*out_s1, *out_s2); - } - if (nmtst_get_rand_bool ()) { - /* randomly make s1 and s2 the same. This is for testing that - * comparing two identical pointers yields the same result. */ - *out_s2 = *out_s1; - } + const char **strv; + gsize i; + + /* Fuzz the input argument. It will return two output arrays that are semantically + * equal the input. */ + + if (nmtst_get_rand_bool()) { + char **ss; + + if (l < 0) + ss = g_strdupv((char **) in); + else if (l == 0) { + ss = nmtst_get_rand_bool() ? NULL : g_new0(char *, 1); + } else { + ss = nm_memdup(in, sizeof(const char *) * l); + for (i = 0; i < (gsize) l; i++) + ss[i] = g_strdup(ss[i]); + } + strv = (const char **) ss; + *out_strv_free_deep = ss; + } else { + if (l < 0) { + strv = in ? nm_memdup(in, sizeof(const char *) * (NM_PTRARRAY_LEN(in) + 1)) : NULL; + } else if (l == 0) { + strv = nmtst_get_rand_bool() ? NULL : g_new0(const char *, 1); + } else + strv = nm_memdup(in, sizeof(const char *) * l); + *out_strv_free_shallow = strv; + } + + *out_s1 = in; + *out_s2 = strv; + + if (nmtst_get_rand_bool()) { + /* randomly swap the original and the clone. That means, out_s1 is either + * the input argument (as-is) or the sementically equal clone. */ + NM_SWAP(out_s1, out_s2); + } + if (nmtst_get_rand_bool()) { + /* randomly make s1 and s2 the same. This is for testing that + * comparing two identical pointers yields the same result. */ + *out_s2 = *out_s1; + } } static void -_strv_cmp_free_deep (char **strv, - gssize len) +_strv_cmp_free_deep(char **strv, gssize len) { - gssize i; - - if (strv) { - if (len < 0) - g_strfreev (strv); - else { - for (i = 0; i < len; i++) - g_free (strv[i]); - g_free (strv); - } - } + gssize i; + + if (strv) { + if (len < 0) + g_strfreev(strv); + else { + for (i = 0; i < len; i++) + g_free(strv[i]); + g_free(strv); + } + } } static void -test_strv_cmp (void) +test_strv_cmp(void) { - const char *const strv0[1] = { }; - const char *const strv1[2] = { "", }; - -#define _STRV_CMP(a1, l1, a2, l2, equal) \ - G_STMT_START { \ - gssize _l1 = (l1); \ - gssize _l2 = (l2); \ - const char *const*_a1; \ - const char *const*_a2; \ - const char *const*_a1x; \ - const char *const*_a2x; \ - char **_a1_free_deep = NULL; \ - char **_a2_free_deep = NULL; \ - gs_free const char **_a1_free_shallow = NULL; \ - gs_free const char **_a2_free_shallow = NULL; \ - int _c1, _c2; \ - \ - _strv_cmp_fuzz_input ((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x); \ - _strv_cmp_fuzz_input ((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x); \ - \ - _c1 = _nm_utils_strv_cmp_n (_a1, _l1, _a2, _l2); \ - _c2 = _nm_utils_strv_cmp_n (_a2, _l2, _a1, _l1); \ - if (equal) { \ - g_assert_cmpint (_c1, ==, 0); \ - g_assert_cmpint (_c2, ==, 0); \ - } else { \ - g_assert_cmpint (_c1, ==, -1); \ - g_assert_cmpint (_c2, ==, 1); \ - } \ - \ - /* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x). - * Either way, the arrays must compare equal to their semantically equal alternative. */ \ - g_assert_cmpint (_nm_utils_strv_cmp_n (_a1, _l1, _a1x, _l1), ==, 0); \ - g_assert_cmpint (_nm_utils_strv_cmp_n (_a2, _l2, _a2x, _l2), ==, 0); \ - \ - _strv_cmp_free_deep (_a1_free_deep, _l1); \ - _strv_cmp_free_deep (_a2_free_deep, _l2); \ - } G_STMT_END - - _STRV_CMP (NULL, -1, NULL, -1, TRUE); - - _STRV_CMP (NULL, -1, NULL, 0, FALSE); - _STRV_CMP (NULL, -1, strv0, 0, FALSE); - _STRV_CMP (NULL, -1, strv0, -1, FALSE); - - _STRV_CMP (NULL, 0, NULL, 0, TRUE); - _STRV_CMP (NULL, 0, strv0, 0, TRUE); - _STRV_CMP (NULL, 0, strv0, -1, TRUE); - _STRV_CMP (strv0, 0, strv0, 0, TRUE); - _STRV_CMP (strv0, 0, strv0, -1, TRUE); - _STRV_CMP (strv0, -1, strv0, -1, TRUE); - - _STRV_CMP (NULL, 0, strv1, -1, FALSE); - _STRV_CMP (NULL, 0, strv1, 1, FALSE); - _STRV_CMP (strv0, 0, strv1, -1, FALSE); - _STRV_CMP (strv0, 0, strv1, 1, FALSE); - _STRV_CMP (strv0, -1, strv1, -1, FALSE); - _STRV_CMP (strv0, -1, strv1, 1, FALSE); - - _STRV_CMP (strv1, -1, strv1, 1, TRUE); - _STRV_CMP (strv1, 1, strv1, 1, TRUE); + const char *const strv0[1] = {}; + const char *const strv1[2] = { + "", + }; + +#define _STRV_CMP(a1, l1, a2, l2, equal) \ + G_STMT_START \ + { \ + gssize _l1 = (l1); \ + gssize _l2 = (l2); \ + const char *const * _a1; \ + const char *const * _a2; \ + const char *const * _a1x; \ + const char *const * _a2x; \ + char ** _a1_free_deep = NULL; \ + char ** _a2_free_deep = NULL; \ + gs_free const char **_a1_free_shallow = NULL; \ + gs_free const char **_a2_free_shallow = NULL; \ + int _c1, _c2; \ + \ + _strv_cmp_fuzz_input((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x); \ + _strv_cmp_fuzz_input((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x); \ + \ + _c1 = _nm_utils_strv_cmp_n(_a1, _l1, _a2, _l2); \ + _c2 = _nm_utils_strv_cmp_n(_a2, _l2, _a1, _l1); \ + if (equal) { \ + g_assert_cmpint(_c1, ==, 0); \ + g_assert_cmpint(_c2, ==, 0); \ + } else { \ + g_assert_cmpint(_c1, ==, -1); \ + g_assert_cmpint(_c2, ==, 1); \ + } \ + \ + /* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x). + * Either way, the arrays must compare equal to their semantically equal alternative. */ \ + g_assert_cmpint(_nm_utils_strv_cmp_n(_a1, _l1, _a1x, _l1), ==, 0); \ + g_assert_cmpint(_nm_utils_strv_cmp_n(_a2, _l2, _a2x, _l2), ==, 0); \ + \ + _strv_cmp_free_deep(_a1_free_deep, _l1); \ + _strv_cmp_free_deep(_a2_free_deep, _l2); \ + } \ + G_STMT_END + + _STRV_CMP(NULL, -1, NULL, -1, TRUE); + + _STRV_CMP(NULL, -1, NULL, 0, FALSE); + _STRV_CMP(NULL, -1, strv0, 0, FALSE); + _STRV_CMP(NULL, -1, strv0, -1, FALSE); + + _STRV_CMP(NULL, 0, NULL, 0, TRUE); + _STRV_CMP(NULL, 0, strv0, 0, TRUE); + _STRV_CMP(NULL, 0, strv0, -1, TRUE); + _STRV_CMP(strv0, 0, strv0, 0, TRUE); + _STRV_CMP(strv0, 0, strv0, -1, TRUE); + _STRV_CMP(strv0, -1, strv0, -1, TRUE); + + _STRV_CMP(NULL, 0, strv1, -1, FALSE); + _STRV_CMP(NULL, 0, strv1, 1, FALSE); + _STRV_CMP(strv0, 0, strv1, -1, FALSE); + _STRV_CMP(strv0, 0, strv1, 1, FALSE); + _STRV_CMP(strv0, -1, strv1, -1, FALSE); + _STRV_CMP(strv0, -1, strv1, 1, FALSE); + + _STRV_CMP(strv1, -1, strv1, 1, TRUE); + _STRV_CMP(strv1, 1, strv1, 1, TRUE); } /*****************************************************************************/ static void -_do_strstrip_avoid_copy (const char *str) +_do_strstrip_avoid_copy(const char *str) { - gs_free char *str1 = g_strdup (str); - gs_free char *str2 = g_strdup (str); - gs_free char *str3 = NULL; - gs_free char *str4 = NULL; - const char *s3; - const char *s4; - - if (str1) - g_strstrip (str1); - - nm_strstrip (str2); - - g_assert_cmpstr (str1, ==, str2); - - s3 = nm_strstrip_avoid_copy (str, &str3); - g_assert_cmpstr (str1, ==, s3); - - s4 = nm_strstrip_avoid_copy_a (10, str, &str4); - g_assert_cmpstr (str1, ==, s4); - g_assert (!str == !s4); - g_assert (!s4 || strlen (s4) <= strlen (str)); - if (s4 && s4 == &str[strlen (str) - strlen (s4)]) { - g_assert (!str4); - g_assert (s3 == s4); - } else if (s4 && strlen (s4) >= 10) { - g_assert (str4); - g_assert (s4 == str4); - } else - g_assert (!str4); - - if (!nm_streq0 (str1, str)) - _do_strstrip_avoid_copy (str1); + gs_free char *str1 = g_strdup(str); + gs_free char *str2 = g_strdup(str); + gs_free char *str3 = NULL; + gs_free char *str4 = NULL; + const char * s3; + const char * s4; + + if (str1) + g_strstrip(str1); + + nm_strstrip(str2); + + g_assert_cmpstr(str1, ==, str2); + + s3 = nm_strstrip_avoid_copy(str, &str3); + g_assert_cmpstr(str1, ==, s3); + + s4 = nm_strstrip_avoid_copy_a(10, str, &str4); + g_assert_cmpstr(str1, ==, s4); + g_assert(!str == !s4); + g_assert(!s4 || strlen(s4) <= strlen(str)); + if (s4 && s4 == &str[strlen(str) - strlen(s4)]) { + g_assert(!str4); + g_assert(s3 == s4); + } else if (s4 && strlen(s4) >= 10) { + g_assert(str4); + g_assert(s4 == str4); + } else + g_assert(!str4); + + if (!nm_streq0(str1, str)) + _do_strstrip_avoid_copy(str1); } static void -test_strstrip_avoid_copy (void) +test_strstrip_avoid_copy(void) { - _do_strstrip_avoid_copy (NULL); - _do_strstrip_avoid_copy (""); - _do_strstrip_avoid_copy (" "); - _do_strstrip_avoid_copy (" a "); - _do_strstrip_avoid_copy (" 012345678 "); - _do_strstrip_avoid_copy (" 0123456789 "); - _do_strstrip_avoid_copy (" 01234567890 "); - _do_strstrip_avoid_copy (" 012345678901 "); + _do_strstrip_avoid_copy(NULL); + _do_strstrip_avoid_copy(""); + _do_strstrip_avoid_copy(" "); + _do_strstrip_avoid_copy(" a "); + _do_strstrip_avoid_copy(" 012345678 "); + _do_strstrip_avoid_copy(" 0123456789 "); + _do_strstrip_avoid_copy(" 01234567890 "); + _do_strstrip_avoid_copy(" 012345678901 "); } /*****************************************************************************/ static void -test_nm_utils_bin2hexstr (void) +test_nm_utils_bin2hexstr(void) { - int n_run; - - for (n_run = 0; n_run < 100; n_run++) { - guint8 buf[100]; - guint8 buf2[G_N_ELEMENTS (buf) + 1]; - gsize len = nmtst_get_rand_uint32 () % (G_N_ELEMENTS (buf) + 1); - char strbuf1[G_N_ELEMENTS (buf) * 3]; - gboolean allocate = nmtst_get_rand_bool (); - char delimiter = nmtst_get_rand_bool () ? ':' : '\0'; - gboolean upper_case = nmtst_get_rand_bool (); - gsize expected_strlen; - char *str_hex; - gsize required_len; - gboolean outlen_set; - gsize outlen; - guint8 *bin2; - - nmtst_rand_buf (NULL, buf, len); - - if (len == 0) - expected_strlen = 0; - else if (delimiter != '\0') - expected_strlen = (len * 3u) - 1; - else - expected_strlen = len * 2u; - - g_assert_cmpint (expected_strlen, <, G_N_ELEMENTS (strbuf1)); - - str_hex = nm_utils_bin2hexstr_full (buf, len, delimiter, upper_case, !allocate ? strbuf1 : NULL); - - g_assert (str_hex); - if (!allocate) - g_assert (str_hex == strbuf1); - g_assert_cmpint (strlen (str_hex), ==, expected_strlen); - - g_assert (NM_STRCHAR_ALL (str_hex, ch, (ch >= '0' && ch <= '9') - || ch == delimiter - || ( upper_case - ? (ch >= 'A' && ch <= 'F') - : (ch >= 'a' && ch <= 'f')))); - - required_len = nmtst_get_rand_bool () ? len : 0u; - - outlen_set = required_len == 0 || nmtst_get_rand_bool (); - - memset (buf2, 0, sizeof (buf2)); - - bin2 = nm_utils_hexstr2bin_full (str_hex, - nmtst_get_rand_bool (), - delimiter != '\0' && nmtst_get_rand_bool (), - delimiter != '\0' - ? nmtst_rand_select ((const char *) ":", ":-") - : nmtst_rand_select ((const char *) ":", ":-", "", NULL), - required_len, - buf2, - len, - outlen_set ? &outlen : NULL); - if (len > 0) { - g_assert (bin2); - g_assert (bin2 == buf2); - } else - g_assert (!bin2); - - if (outlen_set) - g_assert_cmpint (outlen, ==, len); - - g_assert_cmpmem (buf, len, buf2, len); - - g_assert (buf2[len] == '\0'); - - if (allocate) - g_free (str_hex); - } + int n_run; + + for (n_run = 0; n_run < 500; n_run++) { + guint8 buf[100]; + guint8 buf2[G_N_ELEMENTS(buf) + 1]; + gsize len = nmtst_get_rand_uint32() % (G_N_ELEMENTS(buf) + 1); + char strbuf1[G_N_ELEMENTS(buf) * 3]; + gboolean allocate = nmtst_get_rand_bool(); + char delimiter = nmtst_get_rand_bool() ? ':' : '\0'; + gboolean upper_case = nmtst_get_rand_bool(); + gboolean hexdigit_pairs_mangled; + gsize expected_strlen; + char * str_hex; + gsize required_len; + gboolean outlen_set; + gsize outlen; + guint8 * bin2; + guint i, j; + + nmtst_rand_buf(NULL, buf, len); + + if (len == 0) + expected_strlen = 0; + else if (delimiter != '\0') + expected_strlen = (len * 3u) - 1; + else + expected_strlen = len * 2u; + + g_assert_cmpint(expected_strlen, <, G_N_ELEMENTS(strbuf1)); + + str_hex = + nm_utils_bin2hexstr_full(buf, len, delimiter, upper_case, !allocate ? strbuf1 : NULL); + + g_assert(str_hex); + if (!allocate) + g_assert(str_hex == strbuf1); + g_assert_cmpint(strlen(str_hex), ==, expected_strlen); + + g_assert(NM_STRCHAR_ALL( + str_hex, + ch, + (ch >= '0' && ch <= '9') || ch == delimiter + || (upper_case ? (ch >= 'A' && ch <= 'F') : (ch >= 'a' && ch <= 'f')))); + + hexdigit_pairs_mangled = FALSE; + if (delimiter && len > 1 && nmtst_get_rand_bool()) { + /* randomly convert "0?" sequences to single digits, so we can get hexdigit_pairs_required + * parameter. */ + g_assert(strlen(str_hex) >= 5); + g_assert(str_hex[2] == delimiter); + i = 0; + j = 0; + for (;;) { + g_assert(g_ascii_isxdigit(str_hex[i])); + g_assert(g_ascii_isxdigit(str_hex[i + 1])); + g_assert(NM_IN_SET(str_hex[i + 2], delimiter, '\0')); + if (str_hex[i] == '0' && nmtst_get_rand_bool()) { + i++; + str_hex[j++] = str_hex[i++]; + hexdigit_pairs_mangled = TRUE; + } else { + str_hex[j++] = str_hex[i++]; + str_hex[j++] = str_hex[i++]; + } + if (str_hex[i] == '\0') { + str_hex[j] = '\0'; + break; + } + g_assert(str_hex[i] == delimiter); + str_hex[j++] = str_hex[i++]; + } + } + + required_len = nmtst_get_rand_bool() ? len : 0u; + + outlen_set = required_len == 0 || nmtst_get_rand_bool(); + + memset(buf2, 0, sizeof(buf2)); + + bin2 = nm_utils_hexstr2bin_full(str_hex, + nmtst_get_rand_bool(), + delimiter != '\0' && nmtst_get_rand_bool(), + !hexdigit_pairs_mangled && nmtst_get_rand_bool(), + delimiter != '\0' + ? nmtst_rand_select((const char *) ":", ":-") + : nmtst_rand_select((const char *) ":", ":-", "", NULL), + required_len, + buf2, + len, + outlen_set ? &outlen : NULL); + if (len > 0) { + g_assert(bin2); + g_assert(bin2 == buf2); + } else + g_assert(!bin2); + + if (outlen_set) + g_assert_cmpint(outlen, ==, len); + + g_assert_cmpmem(buf, len, buf2, len); + + g_assert(buf2[len] == '\0'); + + if (hexdigit_pairs_mangled) { + /* we mangled the hexstr to contain single digits. Trying to parse with + * hexdigit_pairs_required must now fail. */ + bin2 = nm_utils_hexstr2bin_full( + str_hex, + nmtst_get_rand_bool(), + delimiter != '\0' && nmtst_get_rand_bool(), + TRUE, + delimiter != '\0' ? nmtst_rand_select((const char *) ":", ":-") + : nmtst_rand_select((const char *) ":", ":-", "", NULL), + required_len, + buf2, + len, + outlen_set ? &outlen : NULL); + g_assert(!bin2); + } + + if (allocate) + g_free(str_hex); + } } /*****************************************************************************/ static void -test_nm_ref_string (void) +test_nm_ref_string(void) { - nm_auto_ref_string NMRefString *s1 = NULL; - NMRefString *s2; + nm_auto_ref_string NMRefString *s1 = NULL; + NMRefString * s2; - s1 = nm_ref_string_new ("hallo"); - g_assert (s1); - g_assert_cmpstr (s1->str, ==, "hallo"); - g_assert_cmpint (s1->len, ==, strlen ("hallo")); + s1 = nm_ref_string_new("hallo"); + g_assert(s1); + g_assert_cmpstr(s1->str, ==, "hallo"); + g_assert_cmpint(s1->len, ==, strlen("hallo")); - s2 = nm_ref_string_new ("hallo"); - g_assert (s2 == s1); - nm_ref_string_unref (s2); + s2 = nm_ref_string_new("hallo"); + g_assert(s2 == s1); + nm_ref_string_unref(s2); - s2 = nm_ref_string_new (NULL); - g_assert (!s2); - nm_ref_string_unref (s2); + s2 = nm_ref_string_new(NULL); + g_assert(!s2); + nm_ref_string_unref(s2); #define STR_WITH_NUL "hallo\0test\0" - s2 = nm_ref_string_new_len (STR_WITH_NUL, NM_STRLEN (STR_WITH_NUL)); - g_assert (s2); - g_assert_cmpstr (s2->str, ==, "hallo"); - g_assert_cmpint (s2->len, ==, NM_STRLEN (STR_WITH_NUL)); - g_assert_cmpint (s2->len, >, strlen (s2->str)); - g_assert_cmpmem (s2->str, s2->len, STR_WITH_NUL, NM_STRLEN (STR_WITH_NUL)); - g_assert (s2->str[s2->len] == '\0'); - nm_ref_string_unref (s2); + s2 = nm_ref_string_new_len(STR_WITH_NUL, NM_STRLEN(STR_WITH_NUL)); + g_assert(s2); + g_assert_cmpstr(s2->str, ==, "hallo"); + g_assert_cmpint(s2->len, ==, NM_STRLEN(STR_WITH_NUL)); + g_assert_cmpint(s2->len, >, strlen(s2->str)); + g_assert_cmpmem(s2->str, s2->len, STR_WITH_NUL, NM_STRLEN(STR_WITH_NUL)); + g_assert(s2->str[s2->len] == '\0'); + nm_ref_string_unref(s2); +} + +/*****************************************************************************/ + +static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _do_string_table_lookup, + int, + { ; }, + { return -1; }, + {"0", 0}, + {"1", 1}, + {"2", 2}, + {"3", 3}, ) + + static void test_string_table_lookup(void) +{ + const char *const args[] = { + NULL, + "0", + "1", + "2", + "3", + "x", + }; + int i; + + for (i = 0; i < G_N_ELEMENTS(args); i++) { + const char *needle = args[i]; + const int val2 = _nm_utils_ascii_str_to_int64(needle, 10, 0, 100, -1); + int val; + + val = _do_string_table_lookup(needle); + g_assert_cmpint(val, ==, val2); + } +} + +/*****************************************************************************/ + +static void +test_nm_utils_get_next_realloc_size(void) +{ + static const struct { + gsize requested; + gsize reserved_true; + gsize reserved_false; + } test_data[] = { + {0, 8, 8}, + {1, 8, 8}, + {8, 8, 8}, + {9, 16, 16}, + {16, 16, 16}, + {17, 32, 32}, + {32, 32, 32}, + {33, 40, 40}, + {40, 40, 40}, + {41, 104, 104}, + {104, 104, 104}, + {105, 232, 232}, + {232, 232, 232}, + {233, 488, 488}, + {488, 488, 488}, + {489, 1000, 1000}, + {1000, 1000, 1000}, + {1001, 2024, 2024}, + {2024, 2024, 2024}, + {2025, 4072, 4072}, + {4072, 4072, 4072}, + {4073, 8168, 8168}, + {8168, 8168, 8168}, + {8169, 12264, 16360}, + {12263, 12264, 16360}, + {12264, 12264, 16360}, + {12265, 16360, 16360}, + {16360, 16360, 16360}, + {16361, 20456, 32744}, + {20456, 20456, 32744}, + {20457, 24552, 32744}, + {24552, 24552, 32744}, + {24553, 28648, 32744}, + {28648, 28648, 32744}, + {28649, 32744, 32744}, + {32744, 32744, 32744}, + {32745, 36840, 65512}, + {36840, 36840, 65512}, + {G_MAXSIZE - 0x1000u, G_MAXSIZE, G_MAXSIZE}, + {G_MAXSIZE - 25u, G_MAXSIZE, G_MAXSIZE}, + {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}, + }; + guint i; + + G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_104 == 104u); + G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 == 1000u); + + for (i = 0; i < G_N_ELEMENTS(test_data) + 5000u; i++) { + gsize requested0; + + if (i < G_N_ELEMENTS(test_data)) + requested0 = test_data[i].requested; + else { + /* find some interesting random values for testing. */ + switch (nmtst_get_rand_uint32() % 5) { + case 0: + requested0 = nmtst_get_rand_size(); + break; + case 1: + /* values close to G_MAXSIZE. */ + requested0 = G_MAXSIZE - (nmtst_get_rand_uint32() % 12000u); + break; + case 2: + /* values around G_MAXSIZE/2. */ + requested0 = (G_MAXSIZE / 2u) + 6000u - (nmtst_get_rand_uint32() % 12000u); + break; + case 3: + /* values around powers of 2. */ + requested0 = (((gsize) 1) << (nmtst_get_rand_uint32() % (sizeof(gsize) * 8u))) + + 6000u - (nmtst_get_rand_uint32() % 12000u); + break; + case 4: + /* values around 4k borders. */ + requested0 = (nmtst_get_rand_size() & ~((gsize) 0xFFFu)) + 30u + - (nmtst_get_rand_uint32() % 60u); + break; + default: + g_assert_not_reached(); + } + } + + { + const gsize requested = requested0; + const gsize reserved_true = nm_utils_get_next_realloc_size(TRUE, requested); + const gsize reserved_false = nm_utils_get_next_realloc_size(FALSE, requested); + + g_assert_cmpuint(reserved_true, >, 0); + g_assert_cmpuint(reserved_false, >, 0); + g_assert_cmpuint(reserved_true, >=, requested); + g_assert_cmpuint(reserved_false, >=, requested); + g_assert_cmpuint(reserved_false, >=, reserved_true); + + if (i < G_N_ELEMENTS(test_data)) { + g_assert_cmpuint(reserved_true, ==, test_data[i].reserved_true); + g_assert_cmpuint(reserved_false, ==, test_data[i].reserved_false); + } + + /* reserved_false is generally the next power of two - 24. */ + if (reserved_false == G_MAXSIZE) + g_assert_cmpuint(requested, >, G_MAXSIZE / 2u - 24u); + else { + g_assert_cmpuint(reserved_false, <=, G_MAXSIZE - 24u); + if (reserved_false >= 40) { + const gsize _pow2 = reserved_false + 24u; + + /* reserved_false must always be a power of two minus 24. */ + g_assert_cmpuint(_pow2, >=, 64u); + g_assert_cmpuint(_pow2, >, requested); + g_assert(nm_utils_is_power_of_two(_pow2)); + + /* but _pow2/2 must also be smaller than what we requested. */ + g_assert_cmpuint(_pow2 / 2u - 24u, <, requested); + } else { + /* smaller values are hard-coded. */ + } + } + + /* reserved_true is generally the next 4k border - 24. */ + if (reserved_true == G_MAXSIZE) + g_assert_cmpuint(requested, >, G_MAXSIZE - 0x1000u - 24u); + else { + g_assert_cmpuint(reserved_true, <=, G_MAXSIZE - 24u); + if (reserved_true > 8168u) { + const gsize page_border = reserved_true + 24u; + + /* reserved_true must always be aligned to 4k (minus 24). */ + g_assert_cmpuint(page_border % 0x1000u, ==, 0); + if (requested > 0x1000u - 24u) { + /* page_border not be more than 4k above requested. */ + g_assert_cmpuint(page_border, >=, 0x1000u - 24u); + g_assert_cmpuint(page_border - 0x1000u - 24u, <, requested); + } + } else { + /* for smaller sizes, reserved_true and reserved_false are the same. */ + g_assert_cmpuint(reserved_true, ==, reserved_false); + } + } + } + } } /*****************************************************************************/ -static -NM_UTILS_STRING_TABLE_LOOKUP_DEFINE ( - _do_string_table_lookup, - int, - { ; }, - { return -1; }, - { "0", 0 }, - { "1", 1 }, - { "2", 2 }, - { "3", 3 }, -) +static void +test_nm_str_buf(void) +{ + guint i_run; + + for (i_run = 0; TRUE; i_run++) { + nm_auto_str_buf NMStrBuf strbuf = {}; + nm_auto_free_gstring GString *gstr = NULL; + int i, j, k; + int c; + + nm_str_buf_init(&strbuf, nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool()); + + if (i_run < 1000) { + c = nmtst_get_rand_word_length(NULL); + for (i = 0; i < c; i++) + nm_str_buf_append_c(&strbuf, '0' + (i % 10)); + gstr = g_string_new(nm_str_buf_get_str(&strbuf)); + j = nmtst_get_rand_uint32() % (strbuf.len + 1); + k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1; + + nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool()); + g_string_erase(gstr, j, k); + g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf)); + } else + return; + } +} + +/*****************************************************************************/ static void -test_string_table_lookup (void) +test_nm_utils_parse_next_line(void) { - const char *const args[] = { NULL, "0", "1", "2", "3", "x", }; - int i; + 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); + } +} - for (i = 0; i < G_N_ELEMENTS (args); i++) { - const char *needle = args[i]; - const int val2 = _nm_utils_ascii_str_to_int64 (needle, 10, 0, 100, -1); - int val; +/*****************************************************************************/ - val = _do_string_table_lookup (needle); - g_assert_cmpint (val, ==, val2); - } +static void +test_in_strset_ascii_case(void) +{ + const char *x; + + x = NULL; + g_assert(NM_IN_STRSET_ASCII_CASE(x, NULL)); + g_assert(NM_IN_STRSET_ASCII_CASE(x, NULL, "b")); + g_assert(!NM_IN_STRSET_ASCII_CASE(x, "b")); + + x = "b"; + g_assert(NM_IN_STRSET(x, "b")); + g_assert(NM_IN_STRSET_ASCII_CASE(x, "b")); + g_assert(!NM_IN_STRSET(x, "B")); + g_assert(NM_IN_STRSET_ASCII_CASE(x, "B")); } /*****************************************************************************/ static void -test_nm_utils_get_next_realloc_size (void) +test_is_specific_hostname(void) { - static const struct { - gsize requested; - gsize reserved_true; - gsize reserved_false; - } test_data[] = { - { 0, 8, 8 }, - { 1, 8, 8 }, - { 8, 8, 8 }, - { 9, 16, 16 }, - { 16, 16, 16 }, - { 17, 32, 32 }, - { 32, 32, 32 }, - { 33, 40, 40 }, - { 40, 40, 40 }, - { 41, 104, 104 }, - { 104, 104, 104 }, - { 105, 232, 232 }, - { 232, 232, 232 }, - { 233, 488, 488 }, - { 488, 488, 488 }, - { 489, 1000, 1000 }, - { 1000, 1000, 1000 }, - { 1001, 2024, 2024 }, - { 2024, 2024, 2024 }, - { 2025, 4072, 4072 }, - { 4072, 4072, 4072 }, - { 4073, 8168, 8168 }, - { 8168, 8168, 8168 }, - { 8169, 12264, 16360 }, - { 12263, 12264, 16360 }, - { 12264, 12264, 16360 }, - { 12265, 16360, 16360 }, - { 16360, 16360, 16360 }, - { 16361, 20456, 32744 }, - { 20456, 20456, 32744 }, - { 20457, 24552, 32744 }, - { 24552, 24552, 32744 }, - { 24553, 28648, 32744 }, - { 28648, 28648, 32744 }, - { 28649, 32744, 32744 }, - { 32744, 32744, 32744 }, - { 32745, 36840, 65512 }, - { 36840, 36840, 65512 }, - { G_MAXSIZE - 0x1000u, G_MAXSIZE, G_MAXSIZE }, - { G_MAXSIZE - 25u, G_MAXSIZE, G_MAXSIZE }, - { 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_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 }, - }; - guint i; - - G_STATIC_ASSERT_EXPR (NM_UTILS_GET_NEXT_REALLOC_SIZE_104 == 104u); - G_STATIC_ASSERT_EXPR (NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 == 1000u); - - for (i = 0; i < G_N_ELEMENTS (test_data) + 5000u; i++) { - gsize requested0; - - if (i < G_N_ELEMENTS (test_data)) - requested0 = test_data[i].requested; - else { - /* find some interesting random values for testing. */ - switch (nmtst_get_rand_uint32 () % 5) { - case 0: - requested0 = nmtst_get_rand_size (); - break; - case 1: - /* values close to G_MAXSIZE. */ - requested0 = G_MAXSIZE - (nmtst_get_rand_uint32 () % 12000u); - break; - case 2: - /* values around G_MAXSIZE/2. */ - requested0 = (G_MAXSIZE / 2u) + 6000u - (nmtst_get_rand_uint32 () % 12000u); - break; - case 3: - /* values around powers of 2. */ - requested0 = (((gsize) 1) << (nmtst_get_rand_uint32 () % (sizeof (gsize) * 8u))) + 6000u - (nmtst_get_rand_uint32 () % 12000u); - break; - case 4: - /* values around 4k borders. */ - requested0 = (nmtst_get_rand_size () & ~((gsize) 0xFFFu)) + 30u - (nmtst_get_rand_uint32 () % 60u); - break; - default: g_assert_not_reached (); - } - } - - { - const gsize requested = requested0; - const gsize reserved_true = nm_utils_get_next_realloc_size (TRUE, requested); - const gsize reserved_false = nm_utils_get_next_realloc_size (FALSE, requested); - - g_assert_cmpuint (reserved_true, >, 0); - g_assert_cmpuint (reserved_false, >, 0); - g_assert_cmpuint (reserved_true, >=, requested); - g_assert_cmpuint (reserved_false, >=, requested); - g_assert_cmpuint (reserved_false, >=, reserved_true); - - if (i < G_N_ELEMENTS (test_data)) { - g_assert_cmpuint (reserved_true, ==, test_data[i].reserved_true); - g_assert_cmpuint (reserved_false, ==, test_data[i].reserved_false); - } - - /* reserved_false is generally the next power of two - 24. */ - if (reserved_false == G_MAXSIZE) - g_assert_cmpuint (requested, >, G_MAXSIZE / 2u - 24u); - else { - g_assert_cmpuint (reserved_false, <=, G_MAXSIZE - 24u); - if (reserved_false >= 40) { - const gsize _pow2 = reserved_false + 24u; - - /* reserved_false must always be a power of two minus 24. */ - g_assert_cmpuint (_pow2, >=, 64u); - g_assert_cmpuint (_pow2, >, requested); - g_assert (nm_utils_is_power_of_two (_pow2)); - - /* but _pow2/2 must also be smaller than what we requested. */ - g_assert_cmpuint (_pow2 / 2u - 24u, <, requested); - } else { - /* smaller values are hard-coded. */ - } - } - - /* reserved_true is generally the next 4k border - 24. */ - if (reserved_true == G_MAXSIZE) - g_assert_cmpuint (requested, >, G_MAXSIZE - 0x1000u - 24u); - else { - g_assert_cmpuint (reserved_true, <=, G_MAXSIZE - 24u); - if (reserved_true > 8168u) { - const gsize page_border = reserved_true + 24u; - - /* reserved_true must always be aligned to 4k (minus 24). */ - g_assert_cmpuint (page_border % 0x1000u, ==, 0); - if (requested > 0x1000u - 24u) { - /* page_border not be more than 4k above requested. */ - g_assert_cmpuint (page_border, >=, 0x1000u - 24u); - g_assert_cmpuint (page_border - 0x1000u - 24u, <, requested); - } - } else { - /* for smaller sizes, reserved_true and reserved_false are the same. */ - g_assert_cmpuint (reserved_true, ==, reserved_false); - } - } - - } - } + g_assert(!nm_utils_is_specific_hostname(NULL)); + g_assert(!nm_utils_is_specific_hostname("")); + g_assert(!nm_utils_is_specific_hostname("(none)")); + g_assert(nm_utils_is_specific_hostname("(NONE)")); + + g_assert(!nm_utils_is_specific_hostname("localhost")); + g_assert(!nm_utils_is_specific_hostname("lOcalHost")); + g_assert(!nm_utils_is_specific_hostname("LOCALHOST")); + + g_assert(!nm_utils_is_specific_hostname("LOCALHOST.localdomain")); + + g_assert(nm_utils_is_specific_hostname("xlocalhost")); + g_assert(nm_utils_is_specific_hostname("lOcalHxost")); + g_assert(nm_utils_is_specific_hostname("LOCALxHOST")); + + g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOST")); + g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOsT6.")); + g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOsT6.localdomain6")); + g_assert(!nm_utils_is_specific_hostname(".LOCALHOsT6.localdomain6")); + g_assert(!nm_utils_is_specific_hostname("LOCALHOsT6.localdomain6")); + g_assert(!nm_utils_is_specific_hostname("LOCALHOsT6.localdomain6.")); + g_assert(nm_utils_is_specific_hostname("LOCALHOsT6.localdomain.")); + + g_assert(nm_utils_is_specific_hostname(" ")); } /*****************************************************************************/ static void -test_nm_str_buf (void) +test_strv_dup_packed(void) { - guint i_run; - - for (i_run = 0; TRUE; i_run++) { - nm_auto_str_buf NMStrBuf strbuf = { }; - nm_auto_free_gstring GString *gstr = NULL; - int i, j, k; - int c; - - nm_str_buf_init (&strbuf, - nmtst_get_rand_uint32 () % 200u + 1u, - nmtst_get_rand_bool ()); - - if (i_run < 1000) { - c = nmtst_get_rand_word_length (NULL); - for (i = 0; i < c; i++) - nm_str_buf_append_c (&strbuf, '0' + (i % 10)); - gstr = g_string_new (nm_str_buf_get_str (&strbuf)); - j = nmtst_get_rand_uint32 () % (strbuf.len + 1); - k = nmtst_get_rand_uint32 () % (strbuf.len - j + 2) - 1; - - nm_str_buf_erase (&strbuf, j, k, nmtst_get_rand_bool ()); - g_string_erase (gstr, j, k); - g_assert_cmpstr (gstr->str, ==, nm_str_buf_get_str (&strbuf)); - } else - return; - } + gs_unref_ptrarray GPtrArray *src = NULL; + int i_run; + + src = g_ptr_array_new_with_free_func(g_free); + + for (i_run = 0; i_run < 500; i_run++) { + const int strv_len = nmtst_get_rand_word_length(NULL); + gs_free const char **strv_cpy = NULL; + const char *const * strv_src; + int i, j; + + g_ptr_array_set_size(src, 0); + for (i = 0; i < strv_len; i++) { + const int word_len = nmtst_get_rand_word_length(NULL); + NMStrBuf sbuf = NM_STR_BUF_INIT(0, nmtst_get_rand_bool()); + + for (j = 0; j < word_len; j++) + nm_str_buf_append_c(&sbuf, 'a' + (nmtst_get_rand_uint32() % 20)); + + g_ptr_array_add(src, nm_str_buf_finalize(&sbuf, NULL) ?: g_new0(char, 1)); + } + g_ptr_array_add(src, NULL); + + strv_src = (const char *const *) src->pdata; + g_assert(strv_src); + g_assert(NM_PTRARRAY_LEN(strv_src) == strv_len); + + strv_cpy = + nm_utils_strv_dup_packed(strv_src, + nmtst_get_rand_bool() ? (gssize) strv_len : (gssize) -1); + if (strv_len == 0) + g_assert(!strv_cpy); + else + g_assert(strv_cpy); + g_assert(NM_PTRARRAY_LEN(strv_cpy) == strv_len); + if (strv_cpy) + g_assert(_nm_utils_strv_equal((char **) strv_cpy, (char **) strv_src)); + } +} + +/*****************************************************************************/ + +static int +_hash_func_cmp_direct(gconstpointer a, gconstpointer b, gpointer user_data) +{ + NM_CMP_DIRECT(GPOINTER_TO_INT(a), GPOINTER_TO_INT(b)); + return 0; +} + +static void +test_utils_hashtable_cmp(void) +{ + static struct { + int val_i; + const char *val_s; + } vals[] = { + { + 0, + "0", + }, + { + 1, + "1", + }, + { + 2, + "2", + }, + { + 3, + "3", + }, + { + 4, + "4", + }, + { + 5, + "5", + }, + { + 6, + "6", + }, + { + 7, + "7", + }, + { + 8, + "8", + }, + { + 9, + "9", + }, + { + 0, + "a", + }, + { + 1, + "a", + }, + { + 2, + "a", + }, + { + 3, + "a", + }, + { + 4, + "a", + }, + { + 5, + "a", + }, + { + 0, + "0", + }, + { + 0, + "1", + }, + { + 0, + "2", + }, + { + 0, + "3", + }, + { + 0, + "4", + }, + { + 0, + "5", + }, + }; + guint test_run; + int is_num_key; + + for (test_run = 0; test_run < 30; test_run++) { + for (is_num_key = 0; is_num_key < 2; is_num_key++) { + GHashFunc func_key_hash = is_num_key ? nm_direct_hash : nm_str_hash; + GEqualFunc func_key_equal = is_num_key ? g_direct_equal : g_str_equal; + GCompareDataFunc func_key_cmp = + is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data; + GCompareDataFunc func_val_cmp = + !is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data; + gs_unref_hashtable GHashTable *h1 = NULL; + gs_unref_hashtable GHashTable *h2 = NULL; + gboolean has_same_keys; + guint i, n; + + h1 = g_hash_table_new(func_key_hash, func_key_equal); + h2 = g_hash_table_new(func_key_hash, func_key_equal); + + n = nmtst_get_rand_word_length(NULL); + for (i = 0; i < n; i++) { + typeof(vals[0]) *v = &vals[nmtst_get_rand_uint32() % G_N_ELEMENTS(vals)]; + gconstpointer v_key = is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s; + gconstpointer v_val = !is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s; + + g_hash_table_insert(h1, (gpointer) v_key, (gpointer) v_val); + g_hash_table_insert(h2, (gpointer) v_key, (gpointer) v_val); + } + + g_assert(nm_utils_hashtable_same_keys(h1, h2)); + g_assert(nm_utils_hashtable_equal(h1, h2, NULL, NULL)); + g_assert(nm_utils_hashtable_equal(h1, h2, func_val_cmp, NULL)); + g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0); + g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0); + g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) == 0); + g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) == 0); + + n = nmtst_get_rand_word_length(NULL) + 1; + has_same_keys = TRUE; + for (i = 0; i < n; i++) { +again: +{ + typeof(vals[0]) *v = &vals[nmtst_get_rand_uint32() % G_N_ELEMENTS(vals)]; + gconstpointer v_key = is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s; + gconstpointer v_val = !is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s; + gpointer v_key2; + gpointer v_val2; + + if (g_hash_table_lookup_extended(h1, v_key, &v_key2, &v_val2)) { + g_assert(func_key_cmp(v_key, v_key2, NULL) == 0); + if (func_val_cmp(v_val, v_val2, NULL) == 0) + goto again; + } else + has_same_keys = FALSE; + + g_hash_table_insert(h2, (gpointer) v_key, (gpointer) v_val); +} + } + + if (has_same_keys) { + g_assert(nm_utils_hashtable_same_keys(h1, h2)); + g_assert(nm_utils_hashtable_equal(h1, h2, NULL, NULL)); + g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0); + g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0); + } else { + g_assert(!nm_utils_hashtable_same_keys(h1, h2)); + g_assert(!nm_utils_hashtable_equal(h1, h2, NULL, NULL)); + g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) != 0); + g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) != 0); + } + g_assert(!nm_utils_hashtable_equal(h1, h2, func_val_cmp, NULL)); + g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) != 0); + g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) != 0); + } + } } /*****************************************************************************/ -NMTST_DEFINE (); +NMTST_DEFINE(); -int main (int argc, char **argv) +int +main(int argc, char **argv) { - nmtst_init (&argc, &argv, TRUE); - - g_test_add_func ("/general/test_gpid", test_gpid); - g_test_add_func ("/general/test_monotonic_timestamp", test_monotonic_timestamp); - g_test_add_func ("/general/test_nmhash", test_nmhash); - g_test_add_func ("/general/test_nm_make_strv", test_make_strv); - g_test_add_func ("/general/test_nm_strdup_int", test_nm_strdup_int); - g_test_add_func ("/general/test_nm_strndup_a", test_nm_strndup_a); - g_test_add_func ("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost); - g_test_add_func ("/general/test_unaligned", test_unaligned); - g_test_add_func ("/general/test_strv_cmp", test_strv_cmp); - g_test_add_func ("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy); - g_test_add_func ("/general/test_nm_utils_bin2hexstr", test_nm_utils_bin2hexstr); - g_test_add_func ("/general/test_nm_ref_string", test_nm_ref_string); - 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); - - return g_test_run (); + nmtst_init(&argc, &argv, TRUE); + + g_test_add_func("/general/test_gpid", test_gpid); + g_test_add_func("/general/test_monotonic_timestamp", test_monotonic_timestamp); + g_test_add_func("/general/test_nmhash", test_nmhash); + g_test_add_func("/general/test_nm_make_strv", test_make_strv); + g_test_add_func("/general/test_nm_strdup_int", test_nm_strdup_int); + g_test_add_func("/general/test_nm_strndup_a", test_nm_strndup_a); + g_test_add_func("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost); + g_test_add_func("/general/test_unaligned", test_unaligned); + g_test_add_func("/general/test_strv_cmp", test_strv_cmp); + g_test_add_func("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy); + g_test_add_func("/general/test_nm_utils_bin2hexstr", test_nm_utils_bin2hexstr); + g_test_add_func("/general/test_nm_ref_string", test_nm_ref_string); + 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); + g_test_add_func("/general/test_in_strset_ascii_case", test_in_strset_ascii_case); + g_test_add_func("/general/test_is_specific_hostname", test_is_specific_hostname); + g_test_add_func("/general/test_strv_dup_packed", test_strv_dup_packed); + g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp); + + return g_test_run(); } diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index cf6309b1..51b90e6f 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 - 2018 Red Hat, Inc. */ @@ -60,93 +60,83 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { -#define _D(_scheme_type, ...) \ - [(_scheme_type)] = { \ - .scheme_type = (_scheme_type), \ - __VA_ARGS__ \ - } - - _D (NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN), - - _D (NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, - .setting_key = NM_SETTING_802_1X_CA_CERT, - .scheme_func = nm_setting_802_1x_get_ca_cert_scheme, - .format_func = NULL, - .path_func = nm_setting_802_1x_get_ca_cert_path, - .blob_func = nm_setting_802_1x_get_ca_cert_blob, - .uri_func = nm_setting_802_1x_get_ca_cert_uri, - .passwd_func = nm_setting_802_1x_get_ca_cert_password, - .pwflag_func = nm_setting_802_1x_get_ca_cert_password_flags, - .set_cert_func = nm_setting_802_1x_set_ca_cert, - .file_suffix = "ca-cert", - ), - - _D (NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, - .setting_key = NM_SETTING_802_1X_PHASE2_CA_CERT, - .scheme_func = nm_setting_802_1x_get_phase2_ca_cert_scheme, - .format_func = NULL, - .path_func = nm_setting_802_1x_get_phase2_ca_cert_path, - .blob_func = nm_setting_802_1x_get_phase2_ca_cert_blob, - .uri_func = nm_setting_802_1x_get_phase2_ca_cert_uri, - .passwd_func = nm_setting_802_1x_get_phase2_ca_cert_password, - .pwflag_func = nm_setting_802_1x_get_phase2_ca_cert_password_flags, - .set_cert_func = nm_setting_802_1x_set_phase2_ca_cert, - .file_suffix = "inner-ca-cert", - ), - - _D (NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, - .setting_key = NM_SETTING_802_1X_CLIENT_CERT, - .scheme_func = nm_setting_802_1x_get_client_cert_scheme, - .format_func = NULL, - .path_func = nm_setting_802_1x_get_client_cert_path, - .blob_func = nm_setting_802_1x_get_client_cert_blob, - .uri_func = nm_setting_802_1x_get_client_cert_uri, - .passwd_func = nm_setting_802_1x_get_client_cert_password, - .pwflag_func = nm_setting_802_1x_get_client_cert_password_flags, - .set_cert_func = nm_setting_802_1x_set_client_cert, - .file_suffix = "client-cert", - ), - - _D (NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, - .setting_key = NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - .scheme_func = nm_setting_802_1x_get_phase2_client_cert_scheme, - .format_func = NULL, - .path_func = nm_setting_802_1x_get_phase2_client_cert_path, - .blob_func = nm_setting_802_1x_get_phase2_client_cert_blob, - .uri_func = nm_setting_802_1x_get_phase2_client_cert_uri, - .passwd_func = nm_setting_802_1x_get_phase2_client_cert_password, - .pwflag_func = nm_setting_802_1x_get_phase2_client_cert_password_flags, - .set_cert_func = nm_setting_802_1x_set_phase2_client_cert, - .file_suffix = "inner-client-cert", - ), - - _D (NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, - .setting_key = NM_SETTING_802_1X_PRIVATE_KEY, - .scheme_func = nm_setting_802_1x_get_private_key_scheme, - .format_func = nm_setting_802_1x_get_private_key_format, - .path_func = nm_setting_802_1x_get_private_key_path, - .blob_func = nm_setting_802_1x_get_private_key_blob, - .uri_func = nm_setting_802_1x_get_private_key_uri, - .passwd_func = nm_setting_802_1x_get_private_key_password, - .pwflag_func = nm_setting_802_1x_get_private_key_password_flags, - .set_private_key_func = nm_setting_802_1x_set_private_key, - .file_suffix = "private-key", - .is_secret = TRUE, - ), - - _D (NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, - .setting_key = NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - .scheme_func = nm_setting_802_1x_get_phase2_private_key_scheme, - .format_func = nm_setting_802_1x_get_phase2_private_key_format, - .path_func = nm_setting_802_1x_get_phase2_private_key_path, - .blob_func = nm_setting_802_1x_get_phase2_private_key_blob, - .uri_func = nm_setting_802_1x_get_phase2_private_key_uri, - .passwd_func = nm_setting_802_1x_get_phase2_private_key_password, - .pwflag_func = nm_setting_802_1x_get_phase2_private_key_password_flags, - .set_private_key_func = nm_setting_802_1x_set_phase2_private_key, - .file_suffix = "inner-private-key", - .is_secret = TRUE, - ), +#define _D(_scheme_type, ...) [(_scheme_type)] = {.scheme_type = (_scheme_type), __VA_ARGS__} + + _D(NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, + .setting_key = NM_SETTING_802_1X_CA_CERT, + .scheme_func = nm_setting_802_1x_get_ca_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_ca_cert_path, + .blob_func = nm_setting_802_1x_get_ca_cert_blob, + .uri_func = nm_setting_802_1x_get_ca_cert_uri, + .passwd_func = nm_setting_802_1x_get_ca_cert_password, + .pwflag_func = nm_setting_802_1x_get_ca_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_ca_cert, + .file_suffix = "ca-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, + .setting_key = NM_SETTING_802_1X_PHASE2_CA_CERT, + .scheme_func = nm_setting_802_1x_get_phase2_ca_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_phase2_ca_cert_path, + .blob_func = nm_setting_802_1x_get_phase2_ca_cert_blob, + .uri_func = nm_setting_802_1x_get_phase2_ca_cert_uri, + .passwd_func = nm_setting_802_1x_get_phase2_ca_cert_password, + .pwflag_func = nm_setting_802_1x_get_phase2_ca_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_phase2_ca_cert, + .file_suffix = "inner-ca-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, + .setting_key = NM_SETTING_802_1X_CLIENT_CERT, + .scheme_func = nm_setting_802_1x_get_client_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_client_cert_path, + .blob_func = nm_setting_802_1x_get_client_cert_blob, + .uri_func = nm_setting_802_1x_get_client_cert_uri, + .passwd_func = nm_setting_802_1x_get_client_cert_password, + .pwflag_func = nm_setting_802_1x_get_client_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_client_cert, + .file_suffix = "client-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, + .setting_key = NM_SETTING_802_1X_PHASE2_CLIENT_CERT, + .scheme_func = nm_setting_802_1x_get_phase2_client_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_phase2_client_cert_path, + .blob_func = nm_setting_802_1x_get_phase2_client_cert_blob, + .uri_func = nm_setting_802_1x_get_phase2_client_cert_uri, + .passwd_func = nm_setting_802_1x_get_phase2_client_cert_password, + .pwflag_func = nm_setting_802_1x_get_phase2_client_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_phase2_client_cert, + .file_suffix = "inner-client-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, + .setting_key = NM_SETTING_802_1X_PRIVATE_KEY, + .scheme_func = nm_setting_802_1x_get_private_key_scheme, + .format_func = nm_setting_802_1x_get_private_key_format, + .path_func = nm_setting_802_1x_get_private_key_path, + .blob_func = nm_setting_802_1x_get_private_key_blob, + .uri_func = nm_setting_802_1x_get_private_key_uri, + .passwd_func = nm_setting_802_1x_get_private_key_password, + .pwflag_func = nm_setting_802_1x_get_private_key_password_flags, + .set_private_key_func = nm_setting_802_1x_set_private_key, + .file_suffix = "private-key", + .is_secret = TRUE, ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, + .setting_key = NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, + .scheme_func = nm_setting_802_1x_get_phase2_private_key_scheme, + .format_func = nm_setting_802_1x_get_phase2_private_key_format, + .path_func = nm_setting_802_1x_get_phase2_private_key_path, + .blob_func = nm_setting_802_1x_get_phase2_private_key_blob, + .uri_func = nm_setting_802_1x_get_phase2_private_key_uri, + .passwd_func = nm_setting_802_1x_get_phase2_private_key_password, + .pwflag_func = nm_setting_802_1x_get_phase2_private_key_password_flags, + .set_private_key_func = nm_setting_802_1x_set_phase2_private_key, + .file_suffix = "inner-private-key", + .is_secret = TRUE, ), #undef _D }; @@ -154,395 +144,448 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { /*****************************************************************************/ const NMMetaSettingInfo nm_meta_setting_infos[] = { - [NM_META_SETTING_TYPE_6LOWPAN] = { - .meta_type = NM_META_SETTING_TYPE_6LOWPAN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_6LOWPAN_SETTING_NAME, - .get_setting_gtype = nm_setting_6lowpan_get_type, - }, - [NM_META_SETTING_TYPE_802_1X] = { - .meta_type = NM_META_SETTING_TYPE_802_1X, - .setting_priority = NM_SETTING_PRIORITY_HW_AUX, - .setting_name = NM_SETTING_802_1X_SETTING_NAME, - .get_setting_gtype = nm_setting_802_1x_get_type, - }, - [NM_META_SETTING_TYPE_ADSL] = { - .meta_type = NM_META_SETTING_TYPE_ADSL, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_ADSL_SETTING_NAME, - .get_setting_gtype = nm_setting_adsl_get_type, - }, - [NM_META_SETTING_TYPE_BLUETOOTH] = { - .meta_type = NM_META_SETTING_TYPE_BLUETOOTH, - .setting_priority = NM_SETTING_PRIORITY_HW_NON_BASE, - .setting_name = NM_SETTING_BLUETOOTH_SETTING_NAME, - .get_setting_gtype = nm_setting_bluetooth_get_type, - }, - [NM_META_SETTING_TYPE_BOND] = { - .meta_type = NM_META_SETTING_TYPE_BOND, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_BOND_SETTING_NAME, - .get_setting_gtype = nm_setting_bond_get_type, - }, - [NM_META_SETTING_TYPE_BRIDGE] = { - .meta_type = NM_META_SETTING_TYPE_BRIDGE, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_BRIDGE_SETTING_NAME, - .get_setting_gtype = nm_setting_bridge_get_type, - }, - [NM_META_SETTING_TYPE_BRIDGE_PORT] = { - .meta_type = NM_META_SETTING_TYPE_BRIDGE_PORT, - .setting_priority = NM_SETTING_PRIORITY_AUX, - .setting_name = NM_SETTING_BRIDGE_PORT_SETTING_NAME, - .get_setting_gtype = nm_setting_bridge_port_get_type, - }, - [NM_META_SETTING_TYPE_CDMA] = { - .meta_type = NM_META_SETTING_TYPE_CDMA, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_CDMA_SETTING_NAME, - .get_setting_gtype = nm_setting_cdma_get_type, - }, - [NM_META_SETTING_TYPE_CONNECTION] = { - .meta_type = NM_META_SETTING_TYPE_CONNECTION, - .setting_priority = NM_SETTING_PRIORITY_CONNECTION, - .setting_name = NM_SETTING_CONNECTION_SETTING_NAME, - .get_setting_gtype = nm_setting_connection_get_type, - }, - [NM_META_SETTING_TYPE_DCB] = { - .meta_type = NM_META_SETTING_TYPE_DCB, - .setting_priority = NM_SETTING_PRIORITY_HW_AUX, - .setting_name = NM_SETTING_DCB_SETTING_NAME, - .get_setting_gtype = nm_setting_dcb_get_type, - }, - [NM_META_SETTING_TYPE_DUMMY] = { - .meta_type = NM_META_SETTING_TYPE_DUMMY, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_DUMMY_SETTING_NAME, - .get_setting_gtype = nm_setting_dummy_get_type, - }, - [NM_META_SETTING_TYPE_ETHTOOL] = { - .meta_type = NM_META_SETTING_TYPE_ETHTOOL, - .setting_priority = NM_SETTING_PRIORITY_AUX, - .setting_name = NM_SETTING_ETHTOOL_SETTING_NAME, - .get_setting_gtype = nm_setting_ethtool_get_type, - }, - [NM_META_SETTING_TYPE_GENERIC] = { - .meta_type = NM_META_SETTING_TYPE_GENERIC, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_GENERIC_SETTING_NAME, - .get_setting_gtype = nm_setting_generic_get_type, - }, - [NM_META_SETTING_TYPE_GSM] = { - .meta_type = NM_META_SETTING_TYPE_GSM, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_GSM_SETTING_NAME, - .get_setting_gtype = nm_setting_gsm_get_type, - }, - [NM_META_SETTING_TYPE_INFINIBAND] = { - .meta_type = NM_META_SETTING_TYPE_INFINIBAND, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_INFINIBAND_SETTING_NAME, - .get_setting_gtype = nm_setting_infiniband_get_type, - }, - [NM_META_SETTING_TYPE_IP4_CONFIG] = { - .meta_type = NM_META_SETTING_TYPE_IP4_CONFIG, - .setting_priority = NM_SETTING_PRIORITY_IP, - .setting_name = NM_SETTING_IP4_CONFIG_SETTING_NAME, - .get_setting_gtype = nm_setting_ip4_config_get_type, - }, - [NM_META_SETTING_TYPE_IP6_CONFIG] = { - .meta_type = NM_META_SETTING_TYPE_IP6_CONFIG, - .setting_priority = NM_SETTING_PRIORITY_IP, - .setting_name = NM_SETTING_IP6_CONFIG_SETTING_NAME, - .get_setting_gtype = nm_setting_ip6_config_get_type, - }, - [NM_META_SETTING_TYPE_IP_TUNNEL] = { - .meta_type = NM_META_SETTING_TYPE_IP_TUNNEL, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME, - .get_setting_gtype = nm_setting_ip_tunnel_get_type, - }, - [NM_META_SETTING_TYPE_MACSEC] = { - .meta_type = NM_META_SETTING_TYPE_MACSEC, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_MACSEC_SETTING_NAME, - .get_setting_gtype = nm_setting_macsec_get_type, - }, - [NM_META_SETTING_TYPE_MACVLAN] = { - .meta_type = NM_META_SETTING_TYPE_MACVLAN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_MACVLAN_SETTING_NAME, - .get_setting_gtype = nm_setting_macvlan_get_type, - }, - [NM_META_SETTING_TYPE_MATCH] = { - .meta_type = NM_META_SETTING_TYPE_MATCH, - .setting_priority = NM_SETTING_PRIORITY_AUX, - .setting_name = NM_SETTING_MATCH_SETTING_NAME, - .get_setting_gtype = nm_setting_match_get_type, - }, - [NM_META_SETTING_TYPE_OLPC_MESH] = { - .meta_type = NM_META_SETTING_TYPE_OLPC_MESH, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_OLPC_MESH_SETTING_NAME, - .get_setting_gtype = nm_setting_olpc_mesh_get_type, - }, - [NM_META_SETTING_TYPE_OVS_BRIDGE] = { - .meta_type = NM_META_SETTING_TYPE_OVS_BRIDGE, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_OVS_BRIDGE_SETTING_NAME, - .get_setting_gtype = nm_setting_ovs_bridge_get_type, - }, - [NM_META_SETTING_TYPE_OVS_DPDK] = { - .meta_type = NM_META_SETTING_TYPE_OVS_DPDK, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, - .get_setting_gtype = nm_setting_ovs_dpdk_get_type, - }, - [NM_META_SETTING_TYPE_OVS_INTERFACE] = { - .meta_type = NM_META_SETTING_TYPE_OVS_INTERFACE, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_OVS_INTERFACE_SETTING_NAME, - .get_setting_gtype = nm_setting_ovs_interface_get_type, - }, - [NM_META_SETTING_TYPE_OVS_PATCH] = { - .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, - .get_setting_gtype = nm_setting_ovs_patch_get_type, - }, - [NM_META_SETTING_TYPE_OVS_PORT] = { - .meta_type = NM_META_SETTING_TYPE_OVS_PORT, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_OVS_PORT_SETTING_NAME, - .get_setting_gtype = nm_setting_ovs_port_get_type, - }, - [NM_META_SETTING_TYPE_PPPOE] = { - .meta_type = NM_META_SETTING_TYPE_PPPOE, - .setting_priority = NM_SETTING_PRIORITY_AUX, - .setting_name = NM_SETTING_PPPOE_SETTING_NAME, - .get_setting_gtype = nm_setting_pppoe_get_type, - }, - [NM_META_SETTING_TYPE_PPP] = { - .meta_type = NM_META_SETTING_TYPE_PPP, - .setting_priority = NM_SETTING_PRIORITY_AUX, - .setting_name = NM_SETTING_PPP_SETTING_NAME, - .get_setting_gtype = nm_setting_ppp_get_type, - }, - [NM_META_SETTING_TYPE_PROXY] = { - .meta_type = NM_META_SETTING_TYPE_PROXY, - .setting_priority = NM_SETTING_PRIORITY_IP, - .setting_name = NM_SETTING_PROXY_SETTING_NAME, - .get_setting_gtype = nm_setting_proxy_get_type, - }, - [NM_META_SETTING_TYPE_SERIAL] = { - .meta_type = NM_META_SETTING_TYPE_SERIAL, - .setting_priority = NM_SETTING_PRIORITY_HW_AUX, - .setting_name = NM_SETTING_SERIAL_SETTING_NAME, - .get_setting_gtype = nm_setting_serial_get_type, - }, - [NM_META_SETTING_TYPE_SRIOV] = { - .meta_type = NM_META_SETTING_TYPE_SRIOV, - .setting_priority = NM_SETTING_PRIORITY_HW_AUX, - .setting_name = NM_SETTING_SRIOV_SETTING_NAME, - .get_setting_gtype = nm_setting_sriov_get_type, - }, - [NM_META_SETTING_TYPE_TC_CONFIG] = { - .meta_type = NM_META_SETTING_TYPE_TC_CONFIG, - .setting_priority = NM_SETTING_PRIORITY_IP, - .setting_name = NM_SETTING_TC_CONFIG_SETTING_NAME, - .get_setting_gtype = nm_setting_tc_config_get_type, - }, - [NM_META_SETTING_TYPE_TEAM] = { - .meta_type = NM_META_SETTING_TYPE_TEAM, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_TEAM_SETTING_NAME, - .get_setting_gtype = nm_setting_team_get_type, - }, - [NM_META_SETTING_TYPE_TEAM_PORT] = { - .meta_type = NM_META_SETTING_TYPE_TEAM_PORT, - .setting_priority = NM_SETTING_PRIORITY_AUX, - .setting_name = NM_SETTING_TEAM_PORT_SETTING_NAME, - .get_setting_gtype = nm_setting_team_port_get_type, - }, - [NM_META_SETTING_TYPE_TUN] = { - .meta_type = NM_META_SETTING_TYPE_TUN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_TUN_SETTING_NAME, - .get_setting_gtype = nm_setting_tun_get_type, - }, - [NM_META_SETTING_TYPE_USER] = { - .meta_type = NM_META_SETTING_TYPE_USER, - .setting_priority = NM_SETTING_PRIORITY_USER, - .setting_name = NM_SETTING_USER_SETTING_NAME, - .get_setting_gtype = nm_setting_user_get_type, - }, - [NM_META_SETTING_TYPE_VLAN] = { - .meta_type = NM_META_SETTING_TYPE_VLAN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_VLAN_SETTING_NAME, - .get_setting_gtype = nm_setting_vlan_get_type, - }, - [NM_META_SETTING_TYPE_VPN] = { - .meta_type = NM_META_SETTING_TYPE_VPN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_VPN_SETTING_NAME, - .get_setting_gtype = nm_setting_vpn_get_type, - }, - [NM_META_SETTING_TYPE_VRF] = { - .meta_type = NM_META_SETTING_TYPE_VRF, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_VRF_SETTING_NAME, - .get_setting_gtype = nm_setting_vrf_get_type, - }, - [NM_META_SETTING_TYPE_VXLAN] = { - .meta_type = NM_META_SETTING_TYPE_VXLAN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_VXLAN_SETTING_NAME, - .get_setting_gtype = nm_setting_vxlan_get_type, - }, - [NM_META_SETTING_TYPE_WIFI_P2P] = { - .meta_type = NM_META_SETTING_TYPE_WIFI_P2P, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_WIFI_P2P_SETTING_NAME, - .get_setting_gtype = nm_setting_wifi_p2p_get_type, - }, - [NM_META_SETTING_TYPE_WIMAX] = { - .meta_type = NM_META_SETTING_TYPE_WIMAX, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_WIMAX_SETTING_NAME, - .get_setting_gtype = nm_setting_wimax_get_type, - }, - [NM_META_SETTING_TYPE_WIRED] = { - .meta_type = NM_META_SETTING_TYPE_WIRED, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_WIRED_SETTING_NAME, - .get_setting_gtype = nm_setting_wired_get_type, - }, - [NM_META_SETTING_TYPE_WIREGUARD] = { - .meta_type = NM_META_SETTING_TYPE_WIREGUARD, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_WIREGUARD_SETTING_NAME, - .get_setting_gtype = nm_setting_wireguard_get_type, - }, - [NM_META_SETTING_TYPE_WIRELESS] = { - .meta_type = NM_META_SETTING_TYPE_WIRELESS, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_WIRELESS_SETTING_NAME, - .get_setting_gtype = nm_setting_wireless_get_type, - }, - [NM_META_SETTING_TYPE_WIRELESS_SECURITY] = { - .meta_type = NM_META_SETTING_TYPE_WIRELESS_SECURITY, - .setting_priority = NM_SETTING_PRIORITY_HW_AUX, - .setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - .get_setting_gtype = nm_setting_wireless_security_get_type, - }, - [NM_META_SETTING_TYPE_WPAN] = { - .meta_type = NM_META_SETTING_TYPE_WPAN, - .setting_priority = NM_SETTING_PRIORITY_HW_BASE, - .setting_name = NM_SETTING_WPAN_SETTING_NAME, - .get_setting_gtype = nm_setting_wpan_get_type, - }, - - [NM_META_SETTING_TYPE_UNKNOWN] = { - .meta_type = NM_META_SETTING_TYPE_UNKNOWN, - }, + [NM_META_SETTING_TYPE_6LOWPAN] = + { + .meta_type = NM_META_SETTING_TYPE_6LOWPAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_6LOWPAN_SETTING_NAME, + .get_setting_gtype = nm_setting_6lowpan_get_type, + }, + [NM_META_SETTING_TYPE_802_1X] = + { + .meta_type = NM_META_SETTING_TYPE_802_1X, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_802_1X_SETTING_NAME, + .get_setting_gtype = nm_setting_802_1x_get_type, + }, + [NM_META_SETTING_TYPE_ADSL] = + { + .meta_type = NM_META_SETTING_TYPE_ADSL, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_ADSL_SETTING_NAME, + .get_setting_gtype = nm_setting_adsl_get_type, + }, + [NM_META_SETTING_TYPE_BLUETOOTH] = + { + .meta_type = NM_META_SETTING_TYPE_BLUETOOTH, + .setting_priority = NM_SETTING_PRIORITY_HW_NON_BASE, + .setting_name = NM_SETTING_BLUETOOTH_SETTING_NAME, + .get_setting_gtype = nm_setting_bluetooth_get_type, + }, + [NM_META_SETTING_TYPE_BOND] = + { + .meta_type = NM_META_SETTING_TYPE_BOND, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_BOND_SETTING_NAME, + .get_setting_gtype = nm_setting_bond_get_type, + }, + [NM_META_SETTING_TYPE_BRIDGE] = + { + .meta_type = NM_META_SETTING_TYPE_BRIDGE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_BRIDGE_SETTING_NAME, + .get_setting_gtype = nm_setting_bridge_get_type, + }, + [NM_META_SETTING_TYPE_BRIDGE_PORT] = + { + .meta_type = NM_META_SETTING_TYPE_BRIDGE_PORT, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_BRIDGE_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_bridge_port_get_type, + }, + [NM_META_SETTING_TYPE_CDMA] = + { + .meta_type = NM_META_SETTING_TYPE_CDMA, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_CDMA_SETTING_NAME, + .get_setting_gtype = nm_setting_cdma_get_type, + }, + [NM_META_SETTING_TYPE_CONNECTION] = + { + .meta_type = NM_META_SETTING_TYPE_CONNECTION, + .setting_priority = NM_SETTING_PRIORITY_CONNECTION, + .setting_name = NM_SETTING_CONNECTION_SETTING_NAME, + .get_setting_gtype = nm_setting_connection_get_type, + }, + [NM_META_SETTING_TYPE_DCB] = + { + .meta_type = NM_META_SETTING_TYPE_DCB, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_DCB_SETTING_NAME, + .get_setting_gtype = nm_setting_dcb_get_type, + }, + [NM_META_SETTING_TYPE_DUMMY] = + { + .meta_type = NM_META_SETTING_TYPE_DUMMY, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_DUMMY_SETTING_NAME, + .get_setting_gtype = nm_setting_dummy_get_type, + }, + [NM_META_SETTING_TYPE_ETHTOOL] = + { + .meta_type = NM_META_SETTING_TYPE_ETHTOOL, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_ETHTOOL_SETTING_NAME, + .get_setting_gtype = nm_setting_ethtool_get_type, + }, + [NM_META_SETTING_TYPE_GENERIC] = + { + .meta_type = NM_META_SETTING_TYPE_GENERIC, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_GENERIC_SETTING_NAME, + .get_setting_gtype = nm_setting_generic_get_type, + }, + [NM_META_SETTING_TYPE_GSM] = + { + .meta_type = NM_META_SETTING_TYPE_GSM, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_GSM_SETTING_NAME, + .get_setting_gtype = nm_setting_gsm_get_type, + }, + [NM_META_SETTING_TYPE_INFINIBAND] = + { + .meta_type = NM_META_SETTING_TYPE_INFINIBAND, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_INFINIBAND_SETTING_NAME, + .get_setting_gtype = nm_setting_infiniband_get_type, + }, + [NM_META_SETTING_TYPE_IP4_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_IP4_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_IP4_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_ip4_config_get_type, + }, + [NM_META_SETTING_TYPE_IP6_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_IP6_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_IP6_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_ip6_config_get_type, + }, + [NM_META_SETTING_TYPE_IP_TUNNEL] = + { + .meta_type = NM_META_SETTING_TYPE_IP_TUNNEL, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME, + .get_setting_gtype = nm_setting_ip_tunnel_get_type, + }, + [NM_META_SETTING_TYPE_MACSEC] = + { + .meta_type = NM_META_SETTING_TYPE_MACSEC, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_MACSEC_SETTING_NAME, + .get_setting_gtype = nm_setting_macsec_get_type, + }, + [NM_META_SETTING_TYPE_MACVLAN] = + { + .meta_type = NM_META_SETTING_TYPE_MACVLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_MACVLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_macvlan_get_type, + }, + [NM_META_SETTING_TYPE_MATCH] = + { + .meta_type = NM_META_SETTING_TYPE_MATCH, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_MATCH_SETTING_NAME, + .get_setting_gtype = nm_setting_match_get_type, + }, + [NM_META_SETTING_TYPE_OLPC_MESH] = + { + .meta_type = NM_META_SETTING_TYPE_OLPC_MESH, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OLPC_MESH_SETTING_NAME, + .get_setting_gtype = nm_setting_olpc_mesh_get_type, + }, + [NM_META_SETTING_TYPE_OVS_BRIDGE] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_BRIDGE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_BRIDGE_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_bridge_get_type, + }, + [NM_META_SETTING_TYPE_OVS_DPDK] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_DPDK, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_dpdk_get_type, + }, + [NM_META_SETTING_TYPE_OVS_INTERFACE] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_INTERFACE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_INTERFACE_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_interface_get_type, + }, + [NM_META_SETTING_TYPE_OVS_PATCH] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_patch_get_type, + }, + [NM_META_SETTING_TYPE_OVS_PORT] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_PORT, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_port_get_type, + }, + [NM_META_SETTING_TYPE_PPPOE] = + { + .meta_type = NM_META_SETTING_TYPE_PPPOE, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_PPPOE_SETTING_NAME, + .get_setting_gtype = nm_setting_pppoe_get_type, + }, + [NM_META_SETTING_TYPE_PPP] = + { + .meta_type = NM_META_SETTING_TYPE_PPP, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_PPP_SETTING_NAME, + .get_setting_gtype = nm_setting_ppp_get_type, + }, + [NM_META_SETTING_TYPE_PROXY] = + { + .meta_type = NM_META_SETTING_TYPE_PROXY, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_PROXY_SETTING_NAME, + .get_setting_gtype = nm_setting_proxy_get_type, + }, + [NM_META_SETTING_TYPE_SERIAL] = + { + .meta_type = NM_META_SETTING_TYPE_SERIAL, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_SERIAL_SETTING_NAME, + .get_setting_gtype = nm_setting_serial_get_type, + }, + [NM_META_SETTING_TYPE_SRIOV] = + { + .meta_type = NM_META_SETTING_TYPE_SRIOV, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_SRIOV_SETTING_NAME, + .get_setting_gtype = nm_setting_sriov_get_type, + }, + [NM_META_SETTING_TYPE_TC_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_TC_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_TC_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_tc_config_get_type, + }, + [NM_META_SETTING_TYPE_TEAM] = + { + .meta_type = NM_META_SETTING_TYPE_TEAM, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_TEAM_SETTING_NAME, + .get_setting_gtype = nm_setting_team_get_type, + }, + [NM_META_SETTING_TYPE_TEAM_PORT] = + { + .meta_type = NM_META_SETTING_TYPE_TEAM_PORT, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_TEAM_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_team_port_get_type, + }, + [NM_META_SETTING_TYPE_TUN] = + { + .meta_type = NM_META_SETTING_TYPE_TUN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_TUN_SETTING_NAME, + .get_setting_gtype = nm_setting_tun_get_type, + }, + [NM_META_SETTING_TYPE_USER] = + { + .meta_type = NM_META_SETTING_TYPE_USER, + .setting_priority = NM_SETTING_PRIORITY_USER, + .setting_name = NM_SETTING_USER_SETTING_NAME, + .get_setting_gtype = nm_setting_user_get_type, + }, + [NM_META_SETTING_TYPE_VLAN] = + { + .meta_type = NM_META_SETTING_TYPE_VLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_vlan_get_type, + }, + [NM_META_SETTING_TYPE_VPN] = + { + .meta_type = NM_META_SETTING_TYPE_VPN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VPN_SETTING_NAME, + .get_setting_gtype = nm_setting_vpn_get_type, + }, + [NM_META_SETTING_TYPE_VRF] = + { + .meta_type = NM_META_SETTING_TYPE_VRF, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VRF_SETTING_NAME, + .get_setting_gtype = nm_setting_vrf_get_type, + }, + [NM_META_SETTING_TYPE_VXLAN] = + { + .meta_type = NM_META_SETTING_TYPE_VXLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VXLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_vxlan_get_type, + }, + [NM_META_SETTING_TYPE_WIFI_P2P] = + { + .meta_type = NM_META_SETTING_TYPE_WIFI_P2P, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIFI_P2P_SETTING_NAME, + .get_setting_gtype = nm_setting_wifi_p2p_get_type, + }, + [NM_META_SETTING_TYPE_WIMAX] = + { + .meta_type = NM_META_SETTING_TYPE_WIMAX, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIMAX_SETTING_NAME, + .get_setting_gtype = nm_setting_wimax_get_type, + }, + [NM_META_SETTING_TYPE_WIRED] = + { + .meta_type = NM_META_SETTING_TYPE_WIRED, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIRED_SETTING_NAME, + .get_setting_gtype = nm_setting_wired_get_type, + }, + [NM_META_SETTING_TYPE_WIREGUARD] = + { + .meta_type = NM_META_SETTING_TYPE_WIREGUARD, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIREGUARD_SETTING_NAME, + .get_setting_gtype = nm_setting_wireguard_get_type, + }, + [NM_META_SETTING_TYPE_WIRELESS] = + { + .meta_type = NM_META_SETTING_TYPE_WIRELESS, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIRELESS_SETTING_NAME, + .get_setting_gtype = nm_setting_wireless_get_type, + }, + [NM_META_SETTING_TYPE_WIRELESS_SECURITY] = + { + .meta_type = NM_META_SETTING_TYPE_WIRELESS_SECURITY, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + .get_setting_gtype = nm_setting_wireless_security_get_type, + }, + [NM_META_SETTING_TYPE_WPAN] = + { + .meta_type = NM_META_SETTING_TYPE_WPAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WPAN_SETTING_NAME, + .get_setting_gtype = nm_setting_wpan_get_type, + }, + + [NM_META_SETTING_TYPE_UNKNOWN] = + { + .meta_type = NM_META_SETTING_TYPE_UNKNOWN, + }, }; const NMMetaSettingInfo * -nm_meta_setting_infos_by_name (const char *name) +nm_meta_setting_infos_by_name(const char *name) { - gssize idx; + gssize idx; #if NM_MORE_ASSERTS > 10 - { - guint i, j; - - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { - const NMMetaSettingInfo *setting_info = &nm_meta_setting_infos[i]; - - nm_assert (setting_info->meta_type == (NMMetaSettingType) i); - nm_assert (setting_info->setting_name); - nm_assert (setting_info->setting_name[0]); - nm_assert (setting_info->get_setting_gtype); - nm_assert (setting_info->setting_priority != NM_SETTING_PRIORITY_INVALID); - if ( i > 0 - && strcmp (nm_meta_setting_infos[i - 1].setting_name, setting_info->setting_name) >= 0) { - g_error ("nm_meta_setting_infos[%u, \"%s\"] is wrongly sorted before nm_meta_setting_infos[%u, \"%s\"]. Rearange NMMetaSettingType enum", - i - 1, nm_meta_setting_infos[i - 1].setting_name, - i, setting_info->setting_name); - } - for (j = 0; j < i; j++) { - const NMMetaSettingInfo *s = &nm_meta_setting_infos[j]; - - nm_assert (setting_info->get_setting_gtype != s->get_setting_gtype); - } - } - } + { + guint i, j; + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfo *setting_info = &nm_meta_setting_infos[i]; + + nm_assert(setting_info->meta_type == (NMMetaSettingType) i); + nm_assert(setting_info->setting_name); + nm_assert(setting_info->setting_name[0]); + nm_assert(setting_info->get_setting_gtype); + nm_assert(setting_info->setting_priority != NM_SETTING_PRIORITY_INVALID); + if (i > 0 + && strcmp(nm_meta_setting_infos[i - 1].setting_name, setting_info->setting_name) + >= 0) { + g_error("nm_meta_setting_infos[%u, \"%s\"] is wrongly sorted before " + "nm_meta_setting_infos[%u, \"%s\"]. Rearange NMMetaSettingType enum", + i - 1, + nm_meta_setting_infos[i - 1].setting_name, + i, + setting_info->setting_name); + } + for (j = 0; j < i; j++) { + const NMMetaSettingInfo *s = &nm_meta_setting_infos[j]; + + nm_assert(setting_info->get_setting_gtype != s->get_setting_gtype); + } + } + } #endif - G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMMetaSettingInfo, setting_name) == 0); - idx = nm_utils_array_find_binary_search (nm_meta_setting_infos, - sizeof (NMMetaSettingInfo), - _NM_META_SETTING_TYPE_NUM, - &name, - nm_strcmp_p_with_data, - NULL); + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMMetaSettingInfo, setting_name) == 0); + idx = nm_utils_array_find_binary_search(nm_meta_setting_infos, + sizeof(NMMetaSettingInfo), + _NM_META_SETTING_TYPE_NUM, + &name, + nm_strcmp_p_with_data, + NULL); - return idx >= 0 ? &nm_meta_setting_infos[idx] : NULL; + return idx >= 0 ? &nm_meta_setting_infos[idx] : NULL; } const NMMetaSettingInfo * -nm_meta_setting_infos_by_gtype (GType gtype) +nm_meta_setting_infos_by_gtype(GType gtype) { -#if ((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) - nm_auto_unref_gtypeclass GTypeClass *gtypeclass_unref = NULL; - GTypeClass *gtypeclass; - NMSettingClass *klass; +#if ((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + nm_auto_unref_gtypeclass GTypeClass *gtypeclass_unref = NULL; + GTypeClass * gtypeclass; + NMSettingClass * klass; - if (!g_type_is_a (gtype, NM_TYPE_SETTING)) - goto out_none; + if (!g_type_is_a(gtype, NM_TYPE_SETTING)) + goto out_none; - gtypeclass = g_type_class_peek (gtype); - if (!gtypeclass) - gtypeclass = gtypeclass_unref = g_type_class_ref (gtype); + gtypeclass = g_type_class_peek(gtype); + if (!gtypeclass) + gtypeclass = gtypeclass_unref = g_type_class_ref(gtype); - nm_assert (NM_IS_SETTING_CLASS (gtypeclass)); + nm_assert(NM_IS_SETTING_CLASS(gtypeclass)); - klass = (NMSettingClass *) gtypeclass; + klass = (NMSettingClass *) gtypeclass; - if (!klass->setting_info) - goto out_none; + if (!klass->setting_info) + goto out_none; - nm_assert (klass->setting_info->get_setting_gtype); - nm_assert (klass->setting_info->get_setting_gtype () == gtype); + nm_assert(klass->setting_info->get_setting_gtype); + nm_assert(klass->setting_info->get_setting_gtype() == gtype); - return klass->setting_info; + return klass->setting_info; out_none: -#if NM_MORE_ASSERTS > 10 - { - int i; - - /* this might hint to a bug, but it would be expected for NM_TYPE_SETTING - * and NM_TYPE_SETTING_IP_CONFIG. - * - * Assert that we didn't lookup for a gtype, which we would expect to find. - * An assertion failure here, hints to a bug in nm_setting_*_class_init(). - */ - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) - nm_assert (nm_meta_setting_infos[i].get_setting_gtype () != gtype); - } -#endif - return NULL; + #if NM_MORE_ASSERTS > 10 +{ + int i; + + /* this might hint to a bug, but it would be expected for NM_TYPE_SETTING + * and NM_TYPE_SETTING_IP_CONFIG. + * + * Assert that we didn't lookup for a gtype, which we would expect to find. + * An assertion failure here, hints to a bug in nm_setting_*_class_init(). + */ + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) + nm_assert(nm_meta_setting_infos[i].get_setting_gtype() != gtype); +} + #endif + return NULL; #else - guint i; + guint i; - for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { - if (nm_meta_setting_infos[i].get_setting_gtype () == gtype) - return &nm_meta_setting_infos[i]; - } - return NULL; + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + if (nm_meta_setting_infos[i].get_setting_gtype() == gtype) + return &nm_meta_setting_infos[i]; + } + return NULL; #endif } diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 8b0c7d35..dadf2f72 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 - 2018 Red Hat, Inc. */ @@ -39,119 +39,120 @@ * 10: NMSettingUser */ typedef enum { /*< skip >*/ - NM_SETTING_PRIORITY_INVALID = 0, - NM_SETTING_PRIORITY_CONNECTION = 1, - NM_SETTING_PRIORITY_HW_BASE = 2, - NM_SETTING_PRIORITY_HW_NON_BASE = 3, - NM_SETTING_PRIORITY_HW_AUX = 4, - NM_SETTING_PRIORITY_AUX = 5, - NM_SETTING_PRIORITY_IP = 6, - NM_SETTING_PRIORITY_USER = 10, + NM_SETTING_PRIORITY_INVALID = 0, + NM_SETTING_PRIORITY_CONNECTION = 1, + NM_SETTING_PRIORITY_HW_BASE = 2, + NM_SETTING_PRIORITY_HW_NON_BASE = 3, + NM_SETTING_PRIORITY_HW_AUX = 4, + NM_SETTING_PRIORITY_AUX = 5, + NM_SETTING_PRIORITY_IP = 6, + NM_SETTING_PRIORITY_USER = 10, } NMSettingPriority; /*****************************************************************************/ typedef enum { - NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, - NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, - NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, - NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, - NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, - NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, + NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, - NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN, + NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN, - _NM_SETTING_802_1X_SCHEME_TYPE_NUM = NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN, + _NM_SETTING_802_1X_SCHEME_TYPE_NUM = NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN, } NMSetting8021xSchemeType; typedef struct { - const char *setting_key; - NMSetting8021xCKScheme (*scheme_func) (NMSetting8021x *setting); - NMSetting8021xCKFormat (*format_func) (NMSetting8021x *setting); - const char * (*path_func) (NMSetting8021x *setting); - GBytes * (*blob_func) (NMSetting8021x *setting); - const char * (*uri_func) (NMSetting8021x *setting); - const char * (*passwd_func) (NMSetting8021x *setting); - NMSettingSecretFlags (*pwflag_func) (NMSetting8021x *setting); - gboolean (*set_cert_func) (NMSetting8021x *setting, - const char *value, - NMSetting8021xCKScheme scheme, - NMSetting8021xCKFormat *out_format, - GError **error); - gboolean (*set_private_key_func) (NMSetting8021x *setting, - const char *value, - const char *password, - NMSetting8021xCKScheme scheme, - NMSetting8021xCKFormat *out_format, - GError **error); - const char *file_suffix; - NMSetting8021xSchemeType scheme_type; - bool is_secret:1; + const char *setting_key; + NMSetting8021xCKScheme (*scheme_func)(NMSetting8021x *setting); + NMSetting8021xCKFormat (*format_func)(NMSetting8021x *setting); + const char *(*path_func)(NMSetting8021x *setting); + GBytes *(*blob_func)(NMSetting8021x *setting); + const char *(*uri_func)(NMSetting8021x *setting); + const char *(*passwd_func)(NMSetting8021x *setting); + NMSettingSecretFlags (*pwflag_func)(NMSetting8021x *setting); + gboolean (*set_cert_func)(NMSetting8021x * setting, + const char * value, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError ** error); + gboolean (*set_private_key_func)(NMSetting8021x * setting, + const char * value, + const char * password, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError ** error); + const char * file_suffix; + NMSetting8021xSchemeType scheme_type; + bool is_secret : 1; } NMSetting8021xSchemeVtable; -extern const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[_NM_SETTING_802_1X_SCHEME_TYPE_NUM + 1]; +extern const NMSetting8021xSchemeVtable + nm_setting_8021x_scheme_vtable[_NM_SETTING_802_1X_SCHEME_TYPE_NUM + 1]; /*****************************************************************************/ typedef enum { - /* the enum (and their numeric values) are internal API. Do not assign - * any meaning the numeric values, because they already have one: - * - * they are sorted in a way, that corresponds to the asciibetical sort - * order of the corresponding setting-name. */ - - NM_META_SETTING_TYPE_6LOWPAN, - NM_META_SETTING_TYPE_OLPC_MESH, - NM_META_SETTING_TYPE_WIRELESS, - NM_META_SETTING_TYPE_WIRELESS_SECURITY, - NM_META_SETTING_TYPE_802_1X, - NM_META_SETTING_TYPE_WIRED, - NM_META_SETTING_TYPE_ADSL, - NM_META_SETTING_TYPE_BLUETOOTH, - NM_META_SETTING_TYPE_BOND, - NM_META_SETTING_TYPE_BRIDGE, - NM_META_SETTING_TYPE_BRIDGE_PORT, - NM_META_SETTING_TYPE_CDMA, - NM_META_SETTING_TYPE_CONNECTION, - NM_META_SETTING_TYPE_DCB, - NM_META_SETTING_TYPE_DUMMY, - NM_META_SETTING_TYPE_ETHTOOL, - NM_META_SETTING_TYPE_GENERIC, - NM_META_SETTING_TYPE_GSM, - NM_META_SETTING_TYPE_INFINIBAND, - NM_META_SETTING_TYPE_IP_TUNNEL, - NM_META_SETTING_TYPE_IP4_CONFIG, - NM_META_SETTING_TYPE_IP6_CONFIG, - NM_META_SETTING_TYPE_MACSEC, - NM_META_SETTING_TYPE_MACVLAN, - NM_META_SETTING_TYPE_MATCH, - NM_META_SETTING_TYPE_OVS_BRIDGE, - NM_META_SETTING_TYPE_OVS_DPDK, - NM_META_SETTING_TYPE_OVS_INTERFACE, - NM_META_SETTING_TYPE_OVS_PATCH, - NM_META_SETTING_TYPE_OVS_PORT, - NM_META_SETTING_TYPE_PPP, - NM_META_SETTING_TYPE_PPPOE, - NM_META_SETTING_TYPE_PROXY, - NM_META_SETTING_TYPE_SERIAL, - NM_META_SETTING_TYPE_SRIOV, - NM_META_SETTING_TYPE_TC_CONFIG, - NM_META_SETTING_TYPE_TEAM, - NM_META_SETTING_TYPE_TEAM_PORT, - NM_META_SETTING_TYPE_TUN, - NM_META_SETTING_TYPE_USER, - NM_META_SETTING_TYPE_VLAN, - NM_META_SETTING_TYPE_VPN, - NM_META_SETTING_TYPE_VRF, - NM_META_SETTING_TYPE_VXLAN, - NM_META_SETTING_TYPE_WIFI_P2P, - NM_META_SETTING_TYPE_WIMAX, - NM_META_SETTING_TYPE_WIREGUARD, - NM_META_SETTING_TYPE_WPAN, - - NM_META_SETTING_TYPE_UNKNOWN, - - _NM_META_SETTING_TYPE_NUM = NM_META_SETTING_TYPE_UNKNOWN, + /* the enum (and their numeric values) are internal API. Do not assign + * any meaning the numeric values, because they already have one: + * + * they are sorted in a way, that corresponds to the asciibetical sort + * order of the corresponding setting-name. */ + + NM_META_SETTING_TYPE_6LOWPAN, + NM_META_SETTING_TYPE_OLPC_MESH, + NM_META_SETTING_TYPE_WIRELESS, + NM_META_SETTING_TYPE_WIRELESS_SECURITY, + NM_META_SETTING_TYPE_802_1X, + NM_META_SETTING_TYPE_WIRED, + NM_META_SETTING_TYPE_ADSL, + NM_META_SETTING_TYPE_BLUETOOTH, + NM_META_SETTING_TYPE_BOND, + NM_META_SETTING_TYPE_BRIDGE, + NM_META_SETTING_TYPE_BRIDGE_PORT, + NM_META_SETTING_TYPE_CDMA, + NM_META_SETTING_TYPE_CONNECTION, + NM_META_SETTING_TYPE_DCB, + NM_META_SETTING_TYPE_DUMMY, + NM_META_SETTING_TYPE_ETHTOOL, + NM_META_SETTING_TYPE_GENERIC, + NM_META_SETTING_TYPE_GSM, + NM_META_SETTING_TYPE_INFINIBAND, + NM_META_SETTING_TYPE_IP_TUNNEL, + NM_META_SETTING_TYPE_IP4_CONFIG, + NM_META_SETTING_TYPE_IP6_CONFIG, + NM_META_SETTING_TYPE_MACSEC, + NM_META_SETTING_TYPE_MACVLAN, + NM_META_SETTING_TYPE_MATCH, + NM_META_SETTING_TYPE_OVS_BRIDGE, + NM_META_SETTING_TYPE_OVS_DPDK, + NM_META_SETTING_TYPE_OVS_INTERFACE, + NM_META_SETTING_TYPE_OVS_PATCH, + NM_META_SETTING_TYPE_OVS_PORT, + NM_META_SETTING_TYPE_PPP, + NM_META_SETTING_TYPE_PPPOE, + NM_META_SETTING_TYPE_PROXY, + NM_META_SETTING_TYPE_SERIAL, + NM_META_SETTING_TYPE_SRIOV, + NM_META_SETTING_TYPE_TC_CONFIG, + NM_META_SETTING_TYPE_TEAM, + NM_META_SETTING_TYPE_TEAM_PORT, + NM_META_SETTING_TYPE_TUN, + NM_META_SETTING_TYPE_USER, + NM_META_SETTING_TYPE_VLAN, + NM_META_SETTING_TYPE_VPN, + NM_META_SETTING_TYPE_VRF, + NM_META_SETTING_TYPE_VXLAN, + NM_META_SETTING_TYPE_WIFI_P2P, + NM_META_SETTING_TYPE_WIMAX, + NM_META_SETTING_TYPE_WIREGUARD, + NM_META_SETTING_TYPE_WPAN, + + NM_META_SETTING_TYPE_UNKNOWN, + + _NM_META_SETTING_TYPE_NUM = NM_META_SETTING_TYPE_UNKNOWN, } NMMetaSettingType; /* this header is statically linked with both libnm-core.la and libnmc.la. @@ -166,16 +167,16 @@ typedef enum { * * This define helps to ensure that we don't accidentally use the pointer * in different contexts. */ -#if ((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) -#define _NMMetaSettingInfoXX _NMMetaSettingInfo +#if ((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + #define _NMMetaSettingInfoXX _NMMetaSettingInfo #else -#define _NMMetaSettingInfoXX _NMMetaSettingInfoCli + #define _NMMetaSettingInfoXX _NMMetaSettingInfoCli #endif struct _NMMetaSettingInfoXX { - const char *setting_name; - GType (*get_setting_gtype) (void); - NMMetaSettingType meta_type; - NMSettingPriority setting_priority; + const char *setting_name; + GType (*get_setting_gtype)(void); + NMMetaSettingType meta_type; + NMSettingPriority setting_priority; }; typedef struct _NMMetaSettingInfoXX NMMetaSettingInfo; @@ -200,8 +201,8 @@ typedef struct _NMMetaSettingInfoXX NMMetaSettingInfo; */ extern const NMMetaSettingInfo nm_meta_setting_infos[_NM_META_SETTING_TYPE_NUM + 1]; -const NMMetaSettingInfo *nm_meta_setting_infos_by_name (const char *name); -const NMMetaSettingInfo *nm_meta_setting_infos_by_gtype (GType gtype); +const NMMetaSettingInfo *nm_meta_setting_infos_by_name(const char *name); +const NMMetaSettingInfo *nm_meta_setting_infos_by_gtype(GType gtype); /*****************************************************************************/ diff --git a/shared/nm-std-aux/c-list-util.c b/shared/nm-std-aux/c-list-util.c index a6741c4c..a5837edd 100644 --- a/shared/nm-std-aux/c-list-util.c +++ b/shared/nm-std-aux/c-list-util.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -24,123 +24,118 @@ * the list can be fixed by c_list_relink(). */ void -c_list_relink (CList *lst) +c_list_relink(CList *lst) { - CList *ls, *ls_prev; - - ls_prev = lst; - ls = lst->next; - do { - ls->prev = ls_prev; - ls_prev = ls; - ls = ls->next; - } while (ls); - ls_prev->next = lst; - lst->prev = ls_prev; + CList *ls, *ls_prev; + + ls_prev = lst; + ls = lst->next; + do { + ls->prev = ls_prev; + ls_prev = ls; + ls = ls->next; + } while (ls); + ls_prev->next = lst; + lst->prev = ls_prev; } /*****************************************************************************/ static CList * -_c_list_srt_split (CList *ls) +_c_list_srt_split(CList *ls) { - CList *ls2; - - ls2 = ls; - ls = ls->next; - if (!ls) - return NULL; - do { - ls = ls->next; - if (!ls) - break; - ls = ls->next; - ls2 = ls2->next; - } while (ls); - ls = ls2->next; - ls2->next = NULL; - return ls; + CList *ls2; + + ls2 = ls; + ls = ls->next; + if (!ls) + return NULL; + do { + ls = ls->next; + if (!ls) + break; + ls = ls->next; + ls2 = ls2->next; + } while (ls); + ls = ls2->next; + ls2->next = NULL; + return ls; } static CList * -_c_list_srt_merge (CList *ls1, - CList *ls2, - CListSortCmp cmp, - const void *user_data) +_c_list_srt_merge(CList *ls1, CList *ls2, CListSortCmp cmp, const void *user_data) { - CList *ls; - CList head; - - ls = &head; - for (;;) { - /* while invoking the @cmp function, the list - * elements are not properly linked. Don't try to access - * their next/prev pointers. */ - if (cmp (ls1, ls2, user_data) <= 0) { - ls->next = ls1; - ls = ls1; - ls1 = ls1->next; - if (!ls1) - break; - } else { - ls->next = ls2; - ls = ls2; - ls2 = ls2->next; - if (!ls2) - break; - } - } - ls->next = ls1 ?: ls2; - - return head.next; + CList *ls; + CList head; + + ls = &head; + for (;;) { + /* while invoking the @cmp function, the list + * elements are not properly linked. Don't try to access + * their next/prev pointers. */ + if (cmp(ls1, ls2, user_data) <= 0) { + ls->next = ls1; + ls = ls1; + ls1 = ls1->next; + if (!ls1) + break; + } else { + ls->next = ls2; + ls = ls2; + ls2 = ls2->next; + if (!ls2) + break; + } + } + ls->next = ls1 ?: ls2; + + return head.next; } typedef struct { - CList *ls1; - CList *ls2; - char ls1_sorted; + CList *ls1; + CList *ls2; + char ls1_sorted; } SortStack; static CList * -_c_list_sort (CList *ls, - CListSortCmp cmp, - const void *user_data) +_c_list_sort(CList *ls, CListSortCmp cmp, const void *user_data) { - /* reserve a huge stack-size. We need roughly log2(n) entries, hence this - * is much more we will ever need. We don't guard for stack-overflow either. */ - SortStack stack_arr[70]; - SortStack *stack_head = stack_arr; + /* reserve a huge stack-size. We need roughly log2(n) entries, hence this + * is much more we will ever need. We don't guard for stack-overflow either. */ + SortStack stack_arr[70]; + SortStack *stack_head = stack_arr; - stack_arr[0].ls1 = ls; + stack_arr[0].ls1 = ls; - /* A simple top-down, non-recursive, stable merge-sort. - * - * Maybe natural merge-sort would be better, to do better for - * partially sorted lists. */ + /* A simple top-down, non-recursive, stable merge-sort. + * + * Maybe natural merge-sort would be better, to do better for + * partially sorted lists. */ _split: - stack_head[0].ls2 = _c_list_srt_split (stack_head[0].ls1); - if (stack_head[0].ls2) { - stack_head[0].ls1_sorted = 0; - stack_head[1].ls1 = stack_head[0].ls1; - stack_head++; - goto _split; - } + stack_head[0].ls2 = _c_list_srt_split(stack_head[0].ls1); + if (stack_head[0].ls2) { + stack_head[0].ls1_sorted = 0; + stack_head[1].ls1 = stack_head[0].ls1; + stack_head++; + goto _split; + } _backtrack: - if (stack_head == stack_arr) - return stack_arr[0].ls1; - - stack_head--; - if (!stack_head[0].ls1_sorted) { - stack_head[0].ls1 = stack_head[1].ls1; - stack_head[0].ls1_sorted = 1; - stack_head[1].ls1 = stack_head[0].ls2; - stack_head++; - goto _split; - } - - stack_head[0].ls1 = _c_list_srt_merge (stack_head[0].ls1, stack_head[1].ls1, cmp, user_data); - goto _backtrack; + if (stack_head == stack_arr) + return stack_arr[0].ls1; + + stack_head--; + if (!stack_head[0].ls1_sorted) { + stack_head[0].ls1 = stack_head[1].ls1; + stack_head[0].ls1_sorted = 1; + stack_head[1].ls1 = stack_head[0].ls2; + stack_head++; + goto _split; + } + + stack_head[0].ls1 = _c_list_srt_merge(stack_head[0].ls1, stack_head[1].ls1, cmp, user_data); + goto _backtrack; } /** @@ -157,16 +152,14 @@ _backtrack: * list head. */ CList * -c_list_sort_headless (CList *lst, - CListSortCmp cmp, - const void *user_data) +c_list_sort_headless(CList *lst, CListSortCmp cmp, const void *user_data) { - if (!c_list_is_empty (lst)) { - lst->prev->next = NULL; - lst = _c_list_sort (lst, cmp, user_data); - c_list_relink (lst); - } - return lst; + if (!c_list_is_empty(lst)) { + lst->prev->next = NULL; + lst = _c_list_sort(lst, cmp, user_data); + c_list_relink(lst); + } + return lst; } /** @@ -180,14 +173,11 @@ c_list_sort_headless (CList *lst, * Sorts the list @head according to @cmp. */ void -c_list_sort (CList *head, - CListSortCmp cmp, - const void *user_data) +c_list_sort(CList *head, CListSortCmp cmp, const void *user_data) { - if ( !c_list_is_empty (head) - && head->next->next != head) { - head->prev->next = NULL; - head->next = _c_list_sort (head->next, cmp, user_data); - c_list_relink (head); - } + if (!c_list_is_empty(head) && head->next->next != head) { + head->prev->next = NULL; + head->next = _c_list_sort(head->next, cmp, user_data); + c_list_relink(head); + } } diff --git a/shared/nm-std-aux/c-list-util.h b/shared/nm-std-aux/c-list-util.h index d1aaa0b1..828481e1 100644 --- a/shared/nm-std-aux/c-list-util.h +++ b/shared/nm-std-aux/c-list-util.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -10,19 +10,13 @@ /*****************************************************************************/ -void c_list_relink (CList *lst); +void c_list_relink(CList *lst); -typedef int (*CListSortCmp) (const CList *a, - const CList *b, - const void *user_data); +typedef int (*CListSortCmp)(const CList *a, const CList *b, const void *user_data); -CList *c_list_sort_headless (CList *lst, - CListSortCmp cmp, - const void *user_data); +CList *c_list_sort_headless(CList *lst, CListSortCmp cmp, const void *user_data); -void c_list_sort (CList *head, - CListSortCmp cmp, - const void *user_data); +void c_list_sort(CList *head, CListSortCmp cmp, const void *user_data); /* c_list_length_is: * @list: the #CList list head @@ -34,17 +28,18 @@ void c_list_sort (CList *head, * list, by passing @check_len as 1. */ static inline int -c_list_length_is (const CList *list, unsigned long check_len) { - unsigned long n = 0; - const CList *iter; - - c_list_for_each (iter, list) { - ++n; - if (n > check_len) - return 0; - } - - return n == check_len; +c_list_length_is(const CList *list, unsigned long check_len) +{ + unsigned long n = 0; + const CList * iter; + + c_list_for_each (iter, list) { + ++n; + if (n > check_len) + return 0; + } + + return n == check_len; } #endif /* __C_LIST_UTIL_H__ */ diff --git a/shared/nm-std-aux/nm-dbus-compat.h b/shared/nm-std-aux/nm-dbus-compat.h index 293e15cc..4100e343 100644 --- a/shared/nm-std-aux/nm-dbus-compat.h +++ b/shared/nm-std-aux/nm-dbus-compat.h @@ -1,11 +1,11 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ #ifndef __NM_DBUS_COMPAT_H__ #define __NM_DBUS_COMPAT_H__ -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" +#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -#define DBUS_PATH_DBUS "/org/freedesktop/DBus" +#define DBUS_PATH_DBUS "/org/freedesktop/DBus" #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" #define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" @@ -17,9 +17,9 @@ #define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 #define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 -#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 -#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 -#define DBUS_REQUEST_NAME_REPLY_EXISTS 3 -#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 +#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 +#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 +#define DBUS_REQUEST_NAME_REPLY_EXISTS 3 +#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 -#endif /* __NM_DBUS_COMPAT_H__ */ +#endif /* __NM_DBUS_COMPAT_H__ */ 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 00000000..762f104b --- /dev/null +++ b/shared/nm-std-aux/nm-std-aux.h @@ -0,0 +1,931 @@ +/* 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 <stdint.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 __CHECKER__ + #define _nm_bitwise __attribute__((__bitwise__)) + #define _nm_force __attribute__((__force__)) +#else + #define _nm_bitwise + #define _nm_force +#endif + +typedef uint16_t _nm_bitwise nm_le16_t; +typedef uint16_t _nm_bitwise nm_be16_t; +typedef uint32_t _nm_bitwise nm_le32_t; +typedef uint32_t _nm_bitwise nm_be32_t; +typedef uint64_t _nm_bitwise nm_le64_t; +typedef uint64_t _nm_bitwise nm_be64_t; + +/*****************************************************************************/ + +#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_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON struct _nm_dummy_struct_for_trailing_semicolon + +/*****************************************************************************/ + +#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_assert_unreachable_val(val) \ + ({ \ + nm_assert_not_reached(); \ + (val); \ + }) + +#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))) + +/* Determine whether @x is a power of two (@x being an integer type). + * Basically, this returns TRUE, if @x has exactly one bit set. + * For negative values and zero, this always returns FALSE. */ +#define nm_utils_is_power_of_two(x) \ + ({ \ + typeof(x) _x2 = (x); \ + const typeof(_x2) _X_0 = ((typeof(_x2)) 0); \ + const typeof(_x2) _X_1 = ((typeof(_x2)) 1); \ + \ + ((_x2 > _X_0) && ((_x2 & (_x2 - _X_1)) == _X_0)); \ + }) + +#define nm_utils_is_power_of_two_or_zero(x) \ + ({ \ + typeof(x) _x1 = (x); \ + \ + ((_x1 == 0) || nm_utils_is_power_of_two(_x1)); \ + }) + +/*****************************************************************************/ + +#define NM_SWAP(p_a, p_b) \ + do { \ + typeof(*(p_a)) *const _p_a = (p_a); \ + typeof(*(p_a)) *const _p_b = (p_b); \ + typeof(*(p_a)) _tmp; \ + \ + _tmp = *_p_a; \ + *_p_a = *_p_b; \ + *_p_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_STR_HAS_SUFFIX_WITH_MORE(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)); \ + }) + +/*****************************************************************************/ + +#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_17(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_16(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_18(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_17(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_19(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_18(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_20(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_19(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_21(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_20(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_22(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_21(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_23(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_22(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_24(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_23(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_25(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_24(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_26(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_25(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_27(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_26(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_28(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_27(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_29(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_28(op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_30(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_29(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_IN_SETOP_EVAL_1(op, op_eq, _x, y) (op_eq(_x, y)) +#define _NM_IN_SETOP_EVAL_2(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_1(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_3(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_2(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_4(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_3(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_5(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_4(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_6(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_5(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_7(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_6(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_8(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_7(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_9(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_8(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_10(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_9(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_11(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_10(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_12(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_11(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_13(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_12(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_14(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_13(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_15(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_14(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_16(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_15(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_17(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_16(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_18(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_17(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_19(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_18(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_20(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_19(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_21(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_20(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_22(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_21(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_23(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_22(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_24(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_23(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_25(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_24(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_26(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_25(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_27(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_26(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_28(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_27(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_29(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_28(op, op_eq, _x, __VA_ARGS__) +#define _NM_IN_SETOP_EVAL_30(op, op_eq, _x, y, ...) \ + (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_29(op, op_eq, _x, __VA_ARGS__) + +/*****************************************************************************/ + +#define _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, ...) \ + (_NM_IN_SETOP_EVAL_##n(op, op_ed, _x, __VA_ARGS__)) +#define _NM_IN_STRSET_EVAL_N(op, op_ed, 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, op_ed, _x, n, __VA_ARGS__))); \ + }) + +/*****************************************************************************/ + +static inline int +_NM_IN_STRSET_op_streq(const char *x, const char *s) +{ + return s && strcmp(x, s) == 0; +} + +/* 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(||, _NM_IN_STRSET_op_streq, 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(|, _NM_IN_STRSET_op_streq, 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)); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +#define NM_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \ + static inline void name(void *v) \ + { \ + if (*((CastType *) v)) \ + func(*((CastType *) v)); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +#define NM_AUTO_DEFINE_FCN(Type, name, func) \ + static inline void name(Type *v) \ + { \ + func(*v); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +#define NM_AUTO_DEFINE_FCN0(Type, name, func) \ + static inline void name(Type *v) \ + { \ + if (*v) \ + func(*v); \ + } \ + _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON + +/*****************************************************************************/ + +/** + * 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; +} + +/*****************************************************************************/ + +#define NM_CMP_RETURN(c) \ + do { \ + const int _cc = (c); \ + if (_cc) \ + return _cc < 0 ? -1 : 1; \ + } while (0) + +#define NM_CMP_RETURN_DIRECT(c) \ + do { \ + const int _cc = (c); \ + if (_cc) \ + return _cc; \ + } while (0) + +#define NM_CMP_SELF(a, b) \ + do { \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + if (_a == _b) \ + return 0; \ + if (!_a) \ + return -1; \ + if (!_b) \ + return 1; \ + } while (0) + +#define NM_CMP_DIRECT(a, b) \ + do { \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + \ + if (_a != _b) \ + return (_a < _b) ? -1 : 1; \ + } while (0) + +#define NM_CMP_DIRECT_UNSAFE(a, b) \ + do { \ + if ((a) != (b)) \ + return ((a) < (b)) ? -1 : 1; \ + } while (0) + +/* In the general case, direct pointer comparison is undefined behavior in C. + * Avoid that by casting pointers to void* and then to uintptr_t. This comparison + * is not really meaningful, except that it provides some kind of stable sort order + * between pointers (that can otherwise not be compared). */ +#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT((uintptr_t)((void *) (a)), (uintptr_t)((void *) (b))) + +#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size))) + +#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b))) + +#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b))) + +#define NM_CMP_DIRECT_IN6ADDR(a, b) \ + do { \ + const struct in6_addr *const _a = (a); \ + const struct in6_addr *const _b = (b); \ + NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ + } while (0) + +#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field)) + +#define NM_CMP_FIELD_UNSAFE(a, b, field) \ + do { \ + /* it's unsafe, because it evaluates the arguments more then once. + * This is necessary for bitfields, for which typeof() doesn't work. */ \ + if (((a)->field) != ((b)->field)) \ + return ((a)->field < ((b)->field)) ? -1 : 1; \ + } while (0) + +#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field)) + +#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field))) + +#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \ + do { \ + const char *_a = ((a)->field); \ + const char *_b = ((b)->field); \ + \ + if (_a != _b) { \ + NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \ + } \ + } while (0) + +#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field))) + +#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \ + NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field)))) + +#define NM_CMP_FIELD_MEMCMP(a, b, field) \ + NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field))) + +#define NM_CMP_FIELD_IN6ADDR(a, b, field) \ + do { \ + const struct in6_addr *const _a = &((a)->field); \ + const struct in6_addr *const _b = &((b)->field); \ + NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ + } while (0) + +/*****************************************************************************/ + +#define NM_AF_UNSPEC 0 /* AF_UNSPEC */ +#define NM_AF_INET 2 /* AF_INET */ +#define NM_AF_INET6 10 /* AF_INET6 */ + +#define NM_AF_INET_SIZE 4 /* sizeof (in_addr_t) */ +#define NM_AF_INET6_SIZE 16 /* sizeof (stuct in6_addr) */ + +static inline char +nm_utils_addr_family_to_char(int addr_family) +{ + switch (addr_family) { + case NM_AF_UNSPEC: + return 'X'; + case NM_AF_INET: + return '4'; + case NM_AF_INET6: + return '6'; + } + nm_assert_not_reached(); + return '?'; +} + +static inline size_t +nm_utils_addr_family_to_size(int addr_family) +{ + switch (addr_family) { + case NM_AF_INET: + return NM_AF_INET_SIZE; + case NM_AF_INET6: + return NM_AF_INET6_SIZE; + } + nm_assert_not_reached(); + return 0; +} + +static inline int +nm_utils_addr_family_from_size(size_t len) +{ + switch (len) { + case NM_AF_INET_SIZE: + return NM_AF_INET; + case NM_AF_INET6_SIZE: + return NM_AF_INET6; + } + return NM_AF_UNSPEC; +} + +#define nm_assert_addr_family(addr_family) \ + nm_assert(NM_IN_SET((addr_family), NM_AF_INET, NM_AF_INET6)) + +#define NM_IS_IPv4(addr_family) \ + ({ \ + const int _addr_family = (addr_family); \ + \ + nm_assert_addr_family(_addr_family); \ + \ + (_addr_family == NM_AF_INET); \ + }) + +#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 00000000..6f7f4c58 --- /dev/null +++ b/shared/nm-std-aux/nm-std-utils.c @@ -0,0 +1,75 @@ +/* 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 00000000..1f908191 --- /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-std-aux/unaligned.h b/shared/nm-std-aux/unaligned.h index 00c17f87..e0bc1043 100644 --- a/shared/nm-std-aux/unaligned.h +++ b/shared/nm-std-aux/unaligned.h @@ -6,94 +6,142 @@ /* BE */ -static inline uint16_t unaligned_read_be16(const void *_u) { - const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; - - return be16toh(u->x); +static inline uint16_t +unaligned_read_be16(const void *_u) +{ + const struct __attribute__((__packed__, __may_alias__)) { + uint16_t x; + } *u = _u; + + return be16toh(u->x); } -static inline uint32_t unaligned_read_be32(const void *_u) { - const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; +static inline uint32_t +unaligned_read_be32(const void *_u) +{ + const struct __attribute__((__packed__, __may_alias__)) { + uint32_t x; + } *u = _u; - return be32toh(u->x); + return be32toh(u->x); } -static inline uint64_t unaligned_read_be64(const void *_u) { - const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; +static inline uint64_t +unaligned_read_be64(const void *_u) +{ + const struct __attribute__((__packed__, __may_alias__)) { + uint64_t x; + } *u = _u; - return be64toh(u->x); + return be64toh(u->x); } -static inline void unaligned_write_be16(void *_u, uint16_t a) { - struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; +static inline void +unaligned_write_be16(void *_u, uint16_t a) +{ + struct __attribute__((__packed__, __may_alias__)) { + uint16_t x; + } *u = _u; - u->x = be16toh(a); + u->x = be16toh(a); } -static inline void unaligned_write_be32(void *_u, uint32_t a) { - struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; +static inline void +unaligned_write_be32(void *_u, uint32_t a) +{ + struct __attribute__((__packed__, __may_alias__)) { + uint32_t x; + } *u = _u; - u->x = be32toh(a); + u->x = be32toh(a); } -static inline void unaligned_write_be64(void *_u, uint64_t a) { - struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; +static inline void +unaligned_write_be64(void *_u, uint64_t a) +{ + struct __attribute__((__packed__, __may_alias__)) { + uint64_t x; + } *u = _u; - u->x = be64toh(a); + u->x = be64toh(a); } /* LE */ -static inline uint16_t unaligned_read_le16(const void *_u) { - const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; +static inline uint16_t +unaligned_read_le16(const void *_u) +{ + const struct __attribute__((__packed__, __may_alias__)) { + uint16_t x; + } *u = _u; - return le16toh(u->x); + return le16toh(u->x); } -static inline uint32_t unaligned_read_le32(const void *_u) { - const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; +static inline uint32_t +unaligned_read_le32(const void *_u) +{ + const struct __attribute__((__packed__, __may_alias__)) { + uint32_t x; + } *u = _u; - return le32toh(u->x); + return le32toh(u->x); } -static inline uint64_t unaligned_read_le64(const void *_u) { - const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; +static inline uint64_t +unaligned_read_le64(const void *_u) +{ + const struct __attribute__((__packed__, __may_alias__)) { + uint64_t x; + } *u = _u; - return le64toh(u->x); + return le64toh(u->x); } -static inline void unaligned_write_le16(void *_u, uint16_t a) { - struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; +static inline void +unaligned_write_le16(void *_u, uint16_t a) +{ + struct __attribute__((__packed__, __may_alias__)) { + uint16_t x; + } *u = _u; - u->x = le16toh(a); + u->x = le16toh(a); } -static inline void unaligned_write_le32(void *_u, uint32_t a) { - struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; +static inline void +unaligned_write_le32(void *_u, uint32_t a) +{ + struct __attribute__((__packed__, __may_alias__)) { + uint32_t x; + } *u = _u; - u->x = le32toh(a); + u->x = le32toh(a); } -static inline void unaligned_write_le64(void *_u, uint64_t a) { - struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; +static inline void +unaligned_write_le64(void *_u, uint64_t a) +{ + struct __attribute__((__packed__, __may_alias__)) { + uint64_t x; + } *u = _u; - u->x = le64toh(a); + u->x = le64toh(a); } #if __BYTE_ORDER == __BIG_ENDIAN -#define unaligned_read_ne16 unaligned_read_be16 -#define unaligned_read_ne32 unaligned_read_be32 -#define unaligned_read_ne64 unaligned_read_be64 + #define unaligned_read_ne16 unaligned_read_be16 + #define unaligned_read_ne32 unaligned_read_be32 + #define unaligned_read_ne64 unaligned_read_be64 -#define unaligned_write_ne16 unaligned_write_be16 -#define unaligned_write_ne32 unaligned_write_be32 -#define unaligned_write_ne64 unaligned_write_be64 + #define unaligned_write_ne16 unaligned_write_be16 + #define unaligned_write_ne32 unaligned_write_be32 + #define unaligned_write_ne64 unaligned_write_be64 #else -#define unaligned_read_ne16 unaligned_read_le16 -#define unaligned_read_ne32 unaligned_read_le32 -#define unaligned_read_ne64 unaligned_read_le64 + #define unaligned_read_ne16 unaligned_read_le16 + #define unaligned_read_ne32 unaligned_read_le32 + #define unaligned_read_ne64 unaligned_read_le64 -#define unaligned_write_ne16 unaligned_write_le16 -#define unaligned_write_ne32 unaligned_write_le32 -#define unaligned_write_ne64 unaligned_write_le64 + #define unaligned_write_ne16 unaligned_write_le16 + #define unaligned_write_ne32 unaligned_write_le32 + #define unaligned_write_ne64 unaligned_write_le64 #endif diff --git a/shared/nm-test-libnm-utils.h b/shared/nm-test-libnm-utils.h index 04e8fb64..b44db961 100644 --- a/shared/nm-test-libnm-utils.h +++ b/shared/nm-test-libnm-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2014 - 2015 Red Hat, Inc. */ @@ -11,79 +11,80 @@ #include "nm-utils/nm-test-utils.h" typedef struct { - GDBusConnection *bus; - GDBusProxy *proxy; - GPid pid; - int keepalive_fd; + GDBusConnection *bus; + GDBusProxy * proxy; + GPid pid; + int keepalive_fd; } NMTstcServiceInfo; -NMTstcServiceInfo *nmtstc_service_init (void); -void nmtstc_service_cleanup (NMTstcServiceInfo *info); -NMTstcServiceInfo *nmtstc_service_available (NMTstcServiceInfo *info); +NMTstcServiceInfo *nmtstc_service_init(void); +void nmtstc_service_cleanup(NMTstcServiceInfo *info); +NMTstcServiceInfo *nmtstc_service_available(NMTstcServiceInfo *info); -static inline void _nmtstc_auto_service_cleanup (NMTstcServiceInfo **info) +static inline void +_nmtstc_auto_service_cleanup(NMTstcServiceInfo **info) { - nmtstc_service_cleanup (g_steal_pointer (info)); + nmtstc_service_cleanup(g_steal_pointer(info)); } #define nmtstc_auto_service_cleanup nm_auto(_nmtstc_auto_service_cleanup) -#define NMTSTC_SERVICE_INFO_SETUP(sinfo) \ - NM_PRAGMA_WARNING_DISABLE ("-Wunused-variable") \ - nmtstc_auto_service_cleanup NMTstcServiceInfo *sinfo = ({ \ - NMTstcServiceInfo *_sinfo; \ - \ - _sinfo = nmtstc_service_init (); \ - if (!nmtstc_service_available (_sinfo)) \ - return; \ - _sinfo; \ - }); \ - NM_PRAGMA_WARNING_REENABLE - -NMDevice *nmtstc_service_add_device (NMTstcServiceInfo *info, - NMClient *client, - const char *method, - const char *ifname); - -NMDevice * nmtstc_service_add_wired_device (NMTstcServiceInfo *sinfo, - NMClient *client, - const char *ifname, - const char *hwaddr, - const char **subchannels); - -void nmtstc_service_add_connection (NMTstcServiceInfo *sinfo, - NMConnection *connection, - gboolean verify_connection, - char **out_path); - -void nmtstc_service_add_connection_variant (NMTstcServiceInfo *sinfo, - GVariant *connection, - gboolean verify_connection, - char **out_path); - -void nmtstc_service_update_connection (NMTstcServiceInfo *sinfo, - const char *path, - NMConnection *connection, - gboolean verify_connection); - -void nmtstc_service_update_connection_variant (NMTstcServiceInfo *sinfo, - const char *path, - GVariant *connection, - gboolean verify_connection); - -gpointer nmtstc_context_object_new_valist (GType gtype, - gboolean allow_iterate_main_context, - const char *first_property_name, - va_list var_args); - -gpointer nmtstc_context_object_new (GType gtype, - gboolean allow_iterate_main_context, - const char *first_property_name, - ...); +#define NMTSTC_SERVICE_INFO_SETUP(sinfo) \ + NM_PRAGMA_WARNING_DISABLE("-Wunused-variable") \ + nmtstc_auto_service_cleanup NMTstcServiceInfo *sinfo = ({ \ + NMTstcServiceInfo *_sinfo; \ + \ + _sinfo = nmtstc_service_init(); \ + if (!nmtstc_service_available(_sinfo)) \ + return; \ + _sinfo; \ + }); \ + NM_PRAGMA_WARNING_REENABLE + +NMDevice *nmtstc_service_add_device(NMTstcServiceInfo *info, + NMClient * client, + const char * method, + const char * ifname); + +NMDevice *nmtstc_service_add_wired_device(NMTstcServiceInfo *sinfo, + NMClient * client, + const char * ifname, + const char * hwaddr, + const char ** subchannels); + +void nmtstc_service_add_connection(NMTstcServiceInfo *sinfo, + NMConnection * connection, + gboolean verify_connection, + char ** out_path); + +void nmtstc_service_add_connection_variant(NMTstcServiceInfo *sinfo, + GVariant * connection, + gboolean verify_connection, + char ** out_path); + +void nmtstc_service_update_connection(NMTstcServiceInfo *sinfo, + const char * path, + NMConnection * connection, + gboolean verify_connection); + +void nmtstc_service_update_connection_variant(NMTstcServiceInfo *sinfo, + const char * path, + GVariant * connection, + gboolean verify_connection); + +gpointer nmtstc_context_object_new_valist(GType gtype, + gboolean allow_iterate_main_context, + const char *first_property_name, + va_list var_args); + +gpointer nmtstc_context_object_new(GType gtype, + gboolean allow_iterate_main_context, + const char *first_property_name, + ...); static inline NMClient * -nmtstc_client_new (gboolean allow_iterate_main_context) +nmtstc_client_new(gboolean allow_iterate_main_context) { - return nmtstc_context_object_new (NM_TYPE_CLIENT, allow_iterate_main_context, NULL); + return nmtstc_context_object_new(NM_TYPE_CLIENT, allow_iterate_main_context, NULL); } #endif /* __NM_TEST_LIBNM_UTILS_H__ */ diff --git a/shared/nm-test-utils-impl.c b/shared/nm-test-utils-impl.c index ce7cc8d1..7b71484e 100644 --- a/shared/nm-test-utils-impl.c +++ b/shared/nm-test-utils-impl.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2010 - 2015 Red Hat, Inc. */ @@ -12,626 +12,629 @@ #include "nm-test-libnm-utils.h" -#define NMTSTC_NM_SERVICE NM_BUILD_SRCDIR"/tools/test-networkmanager-service.py" +#define NMTSTC_NM_SERVICE NM_BUILD_SRCDIR "/tools/test-networkmanager-service.py" /*****************************************************************************/ static gboolean -name_exists (GDBusConnection *c, const char *name) +name_exists(GDBusConnection *c, const char *name) { - GVariant *reply; - gboolean exists = FALSE; - - reply = g_dbus_connection_call_sync (c, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetNameOwner", - g_variant_new ("(s)", name), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - NULL, - NULL); - if (reply != NULL) { - exists = TRUE; - g_variant_unref (reply); - } - - return exists; + GVariant *reply; + gboolean exists = FALSE; + + reply = g_dbus_connection_call_sync(c, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetNameOwner", + g_variant_new("(s)", name), + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, + NULL, + NULL); + if (reply != NULL) { + exists = TRUE; + g_variant_unref(reply); + } + + return exists; } typedef struct { - GMainLoop *mainloop; - GDBusConnection *bus; - int exit_code; - bool exited:1; - bool name_found:1; + GMainLoop * mainloop; + GDBusConnection *bus; + int exit_code; + bool exited : 1; + bool name_found : 1; } ServiceInitWaitData; static gboolean -_service_init_wait_probe_name (gpointer user_data) +_service_init_wait_probe_name(gpointer user_data) { - ServiceInitWaitData *data = user_data; + ServiceInitWaitData *data = user_data; - if (!name_exists (data->bus, "org.freedesktop.NetworkManager")) - return G_SOURCE_CONTINUE; + if (!name_exists(data->bus, "org.freedesktop.NetworkManager")) + return G_SOURCE_CONTINUE; - data->name_found = TRUE; - g_main_loop_quit (data->mainloop); - return G_SOURCE_REMOVE; + data->name_found = TRUE; + g_main_loop_quit(data->mainloop); + return G_SOURCE_REMOVE; } static void -_service_init_wait_child_wait (GPid pid, - int status, - gpointer user_data) +_service_init_wait_child_wait(GPid pid, int status, gpointer user_data) { - ServiceInitWaitData *data = user_data; + ServiceInitWaitData *data = user_data; - data->exited = TRUE; - data->exit_code = status; - g_main_loop_quit (data->mainloop); + data->exited = TRUE; + data->exit_code = status; + g_main_loop_quit(data->mainloop); } NMTstcServiceInfo * -nmtstc_service_available (NMTstcServiceInfo *info) +nmtstc_service_available(NMTstcServiceInfo *info) { - gs_free char *m = NULL; + gs_free char *m = NULL; - if (info) - return info; + if (info) + return info; - /* This happens, when test-networkmanager-service.py exits with 77 status - * code. */ - m = g_strdup_printf ("missing dependency for running NetworkManager stub service %s", NMTSTC_NM_SERVICE); - g_test_skip (m); - return NULL; + /* This happens, when test-networkmanager-service.py exits with 77 status + * code. */ + m = g_strdup_printf("missing dependency for running NetworkManager stub service %s", + NMTSTC_NM_SERVICE); + g_test_skip(m); + return NULL; } NMTstcServiceInfo * -nmtstc_service_init (void) +nmtstc_service_init(void) { - NMTstcServiceInfo *info; - const char *args[] = { TEST_NM_PYTHON, NMTSTC_NM_SERVICE, NULL }; - GError *error = NULL; - - info = g_malloc0 (sizeof (*info)); - - info->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - g_assert_no_error (error); - - /* Spawn the test service. info->keepalive_fd will be a pipe to the service's - * stdin; if it closes, the service will exit immediately. We use this to - * make sure the service exits if the test program crashes. - */ - g_spawn_async_with_pipes (NULL, (char **) args, NULL, - G_SPAWN_SEARCH_PATH - | G_SPAWN_DO_NOT_REAP_CHILD, - NULL, NULL, - &info->pid, &info->keepalive_fd, NULL, NULL, &error); - g_assert_no_error (error); - - { - nm_auto_unref_gsource GSource *timeout_source = NULL; - nm_auto_unref_gsource GSource *child_source = NULL; - GMainContext *context = g_main_context_new (); - ServiceInitWaitData data = { - .bus = info->bus, - .mainloop = g_main_loop_new (context, FALSE), - }; - gboolean had_timeout; - - timeout_source = g_timeout_source_new (50); - g_source_set_callback (timeout_source, _service_init_wait_probe_name, &data, NULL); - g_source_attach (timeout_source, context); - - child_source = g_child_watch_source_new (info->pid); - g_source_set_callback (child_source, G_SOURCE_FUNC (_service_init_wait_child_wait), &data, NULL); - g_source_attach (child_source, context); - - had_timeout = !nmtst_main_loop_run (data.mainloop, 30000); - - g_source_destroy (timeout_source); - g_source_destroy (child_source); - g_main_loop_unref (data.mainloop); - g_main_context_unref (context); - - if (had_timeout) - g_error ("test service %s did not start in time", NMTSTC_NM_SERVICE); - if (!data.name_found) { - g_assert (data.exited); - info->pid = NM_PID_T_INVAL; - nmtstc_service_cleanup (info); - - if ( WIFEXITED (data.exit_code) - && WEXITSTATUS (data.exit_code) == 77) { - /* If the stub service exited with status 77 it means that it decided - * that it cannot conduct the tests and the test should be (gracefully) - * skip. The likely reason for that, is that libnm is not available - * via pygobject. */ - return NULL; - } - g_error ("test service %s exited with error code %d", NMTSTC_NM_SERVICE, data.exit_code); - } - } - - /* Grab a proxy to our fake NM service to trigger tests */ - info->proxy = g_dbus_proxy_new_sync (info->bus, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - NM_DBUS_SERVICE, - NM_DBUS_PATH, - "org.freedesktop.NetworkManager.LibnmGlibTest", - NULL, &error); - g_assert_no_error (error); - - return info; + NMTstcServiceInfo *info; + const char * args[] = {TEST_NM_PYTHON, NMTSTC_NM_SERVICE, NULL}; + GError * error = NULL; + + info = g_malloc0(sizeof(*info)); + + info->bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); + g_assert_no_error(error); + + /* Spawn the test service. info->keepalive_fd will be a pipe to the service's + * stdin; if it closes, the service will exit immediately. We use this to + * make sure the service exits if the test program crashes. + */ + g_spawn_async_with_pipes(NULL, + (char **) args, + NULL, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &info->pid, + &info->keepalive_fd, + NULL, + NULL, + &error); + g_assert_no_error(error); + + { + nm_auto_unref_gsource GSource *timeout_source = NULL; + nm_auto_unref_gsource GSource *child_source = NULL; + GMainContext * context = g_main_context_new(); + ServiceInitWaitData data = { + .bus = info->bus, + .mainloop = g_main_loop_new(context, FALSE), + }; + gboolean had_timeout; + + timeout_source = g_timeout_source_new(50); + g_source_set_callback(timeout_source, _service_init_wait_probe_name, &data, NULL); + g_source_attach(timeout_source, context); + + child_source = g_child_watch_source_new(info->pid); + g_source_set_callback(child_source, + G_SOURCE_FUNC(_service_init_wait_child_wait), + &data, + NULL); + g_source_attach(child_source, context); + + had_timeout = !nmtst_main_loop_run(data.mainloop, 30000); + + g_source_destroy(timeout_source); + g_source_destroy(child_source); + g_main_loop_unref(data.mainloop); + g_main_context_unref(context); + + if (had_timeout) + g_error("test service %s did not start in time", NMTSTC_NM_SERVICE); + if (!data.name_found) { + g_assert(data.exited); + info->pid = NM_PID_T_INVAL; + nmtstc_service_cleanup(info); + + if (WIFEXITED(data.exit_code) && WEXITSTATUS(data.exit_code) == 77) { + /* If the stub service exited with status 77 it means that it decided + * that it cannot conduct the tests and the test should be (gracefully) + * skip. The likely reason for that, is that libnm is not available + * via pygobject. */ + return NULL; + } + g_error("test service %s exited with error code %d", NMTSTC_NM_SERVICE, data.exit_code); + } + } + + /* Grab a proxy to our fake NM service to trigger tests */ + info->proxy = g_dbus_proxy_new_sync(info->bus, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES + | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS + | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + NM_DBUS_SERVICE, + NM_DBUS_PATH, + "org.freedesktop.NetworkManager.LibnmGlibTest", + NULL, + &error); + g_assert_no_error(error); + + return info; } void -nmtstc_service_cleanup (NMTstcServiceInfo *info) +nmtstc_service_cleanup(NMTstcServiceInfo *info) { - int ret; - gint64 t; - int status; + int ret; + gint64 t; + int status; - if (!info) - return; + if (!info) + return; - nm_close (nm_steal_fd (&info->keepalive_fd)); + nm_close(nm_steal_fd(&info->keepalive_fd)); - g_clear_object (&info->proxy); + g_clear_object(&info->proxy); - if (info->pid != NM_PID_T_INVAL) { - kill (info->pid, SIGTERM); + if (info->pid != NM_PID_T_INVAL) { + kill(info->pid, SIGTERM); - t = g_get_monotonic_time (); + t = g_get_monotonic_time(); again_wait: - ret = waitpid (info->pid, &status, WNOHANG); - if (ret == 0) { - if (t + 2000000 < g_get_monotonic_time ()) { - kill (info->pid, SIGKILL); - g_error ("child process %lld did not exit within timeout", (long long) info->pid); - } - g_usleep (G_USEC_PER_SEC / 50); - goto again_wait; - } - if (ret == -1 && errno == EINTR) - goto again_wait; - - g_assert (ret == info->pid); - } - - g_assert (!name_exists (info->bus, "org.freedesktop.NetworkManager")); - - g_clear_object (&info->bus); - - memset (info, 0, sizeof (*info)); - g_free (info); + ret = waitpid(info->pid, &status, WNOHANG); + if (ret == 0) { + if (t + 2000000 < g_get_monotonic_time()) { + kill(info->pid, SIGKILL); + g_error("child process %lld did not exit within timeout", (long long) info->pid); + } + g_usleep(G_USEC_PER_SEC / 50); + goto again_wait; + } + if (ret == -1 && errno == EINTR) + goto again_wait; + + g_assert(ret == info->pid); + } + + g_assert(!name_exists(info->bus, "org.freedesktop.NetworkManager")); + + g_clear_object(&info->bus); + + memset(info, 0, sizeof(*info)); + g_free(info); } typedef struct { - GMainLoop *loop; - const char *ifname; - const char *path; - NMDevice *device; + GMainLoop * loop; + const char *ifname; + const char *path; + NMDevice * device; } AddDeviceInfo; static void -device_added_cb (NMClient *client, - NMDevice *device, - gpointer user_data) +device_added_cb(NMClient *client, NMDevice *device, gpointer user_data) { - AddDeviceInfo *info = user_data; + AddDeviceInfo *info = user_data; - g_assert (info); - g_assert (!info->device); + g_assert(info); + g_assert(!info->device); - g_assert (NM_IS_DEVICE (device)); - g_assert_cmpstr (nm_object_get_path (NM_OBJECT (device)), ==, info->path); - g_assert_cmpstr (nm_device_get_iface (device), ==, info->ifname); + g_assert(NM_IS_DEVICE(device)); + g_assert_cmpstr(nm_object_get_path(NM_OBJECT(device)), ==, info->path); + g_assert_cmpstr(nm_device_get_iface(device), ==, info->ifname); - info->device = g_object_ref (device); - g_main_loop_quit (info->loop); + info->device = g_object_ref(device); + g_main_loop_quit(info->loop); } static GVariant * -call_add_wired_device (GDBusProxy *proxy, const char *ifname, const char *hwaddr, - const char **subchannels, GError **error) +call_add_wired_device(GDBusProxy * proxy, + const char * ifname, + const char * hwaddr, + const char **subchannels, + GError ** error) { - const char *empty[] = { NULL }; - - if (!hwaddr) - hwaddr = "/"; - if (!subchannels) - subchannels = empty; - - return g_dbus_proxy_call_sync (proxy, - "AddWiredDevice", - g_variant_new ("(ss^as)", ifname, hwaddr, subchannels), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 3000, - NULL, - error); + const char *empty[] = {NULL}; + + if (!hwaddr) + hwaddr = "/"; + if (!subchannels) + subchannels = empty; + + return g_dbus_proxy_call_sync(proxy, + "AddWiredDevice", + g_variant_new("(ss^as)", ifname, hwaddr, subchannels), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 3000, + NULL, + error); } static GVariant * -call_add_device (GDBusProxy *proxy, const char *method, const char *ifname, GError **error) +call_add_device(GDBusProxy *proxy, const char *method, const char *ifname, GError **error) { - return g_dbus_proxy_call_sync (proxy, - method, - g_variant_new ("(s)", ifname), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 3000, - NULL, - error); + return g_dbus_proxy_call_sync(proxy, + method, + g_variant_new("(s)", ifname), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 3000, + NULL, + error); } static NMDevice * -add_device_common (NMTstcServiceInfo *sinfo, - NMClient *client, - const char *method, - const char *ifname, - const char *hwaddr, - const char **subchannels) +add_device_common(NMTstcServiceInfo *sinfo, + NMClient * client, + const char * method, + const char * ifname, + const char * hwaddr, + const char ** subchannels) { - nm_auto_unref_gmainloop GMainLoop *loop = NULL; - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - AddDeviceInfo info; + nm_auto_unref_gmainloop GMainLoop *loop = NULL; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError *error = NULL; + AddDeviceInfo info; - g_assert (sinfo); - g_assert (NM_IS_CLIENT (client)); + g_assert(sinfo); + g_assert(NM_IS_CLIENT(client)); - if (nm_streq0 (method, "AddWiredDevice")) - ret = call_add_wired_device (sinfo->proxy, ifname, hwaddr, subchannels, &error); - else - ret = call_add_device (sinfo->proxy, method, ifname, &error); + if (nm_streq0(method, "AddWiredDevice")) + ret = call_add_wired_device(sinfo->proxy, ifname, hwaddr, subchannels, &error); + else + ret = call_add_device(sinfo->proxy, method, ifname, &error); - nmtst_assert_success (ret, error); - g_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)"); + nmtst_assert_success(ret, error); + g_assert_cmpstr(g_variant_get_type_string(ret), ==, "(o)"); - /* Wait for NMClient to find the device */ + /* Wait for NMClient to find the device */ - loop = g_main_loop_new (nm_client_get_main_context (client), FALSE); + loop = g_main_loop_new(nm_client_get_main_context(client), FALSE); - info = (AddDeviceInfo) { - .ifname = ifname, - .loop = loop, - }; - g_variant_get (ret, "(&o)", &info.path); + info = (AddDeviceInfo){ + .ifname = ifname, + .loop = loop, + }; + g_variant_get(ret, "(&o)", &info.path); - g_signal_connect (client, - NM_CLIENT_DEVICE_ADDED, - G_CALLBACK (device_added_cb), - &info); + g_signal_connect(client, NM_CLIENT_DEVICE_ADDED, G_CALLBACK(device_added_cb), &info); - if (!nmtst_main_loop_run (loop, 5000)) - g_assert_not_reached (); + if (!nmtst_main_loop_run(loop, 5000)) + g_assert_not_reached(); - g_signal_handlers_disconnect_by_func (client, device_added_cb, &info); + g_signal_handlers_disconnect_by_func(client, device_added_cb, &info); - g_assert (NM_IS_DEVICE (info.device)); + g_assert(NM_IS_DEVICE(info.device)); - g_assert (info.device == nm_client_get_device_by_path (client, nm_object_get_path (NM_OBJECT (info.device)))); - g_object_unref (info.device); - return info.device; + g_assert(info.device + == nm_client_get_device_by_path(client, nm_object_get_path(NM_OBJECT(info.device)))); + g_object_unref(info.device); + return info.device; } NMDevice * -nmtstc_service_add_device (NMTstcServiceInfo *sinfo, NMClient *client, - const char *method, const char *ifname) +nmtstc_service_add_device(NMTstcServiceInfo *sinfo, + NMClient * client, + const char * method, + const char * ifname) { - return add_device_common (sinfo, client, method, ifname, NULL, NULL); + return add_device_common(sinfo, client, method, ifname, NULL, NULL); } NMDevice * -nmtstc_service_add_wired_device (NMTstcServiceInfo *sinfo, NMClient *client, - const char *ifname, const char *hwaddr, - const char **subchannels) +nmtstc_service_add_wired_device(NMTstcServiceInfo *sinfo, + NMClient * client, + const char * ifname, + const char * hwaddr, + const char ** subchannels) { - return add_device_common (sinfo, client, "AddWiredDevice", ifname, hwaddr, subchannels); + return add_device_common(sinfo, client, "AddWiredDevice", ifname, hwaddr, subchannels); } void -nmtstc_service_add_connection (NMTstcServiceInfo *sinfo, - NMConnection *connection, - gboolean verify_connection, - char **out_path) +nmtstc_service_add_connection(NMTstcServiceInfo *sinfo, + NMConnection * connection, + gboolean verify_connection, + char ** out_path) { - nmtstc_service_add_connection_variant (sinfo, - nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL), - verify_connection, - out_path); + nmtstc_service_add_connection_variant( + sinfo, + nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL), + verify_connection, + out_path); } void -nmtstc_service_add_connection_variant (NMTstcServiceInfo *sinfo, - GVariant *connection, - gboolean verify_connection, - char **out_path) +nmtstc_service_add_connection_variant(NMTstcServiceInfo *sinfo, + GVariant * connection, + gboolean verify_connection, + char ** out_path) { - GVariant *result; - GError *error = NULL; - - g_assert (sinfo); - g_assert (G_IS_DBUS_PROXY (sinfo->proxy)); - g_assert (g_variant_is_of_type (connection, G_VARIANT_TYPE ("a{sa{sv}}"))); - - result = g_dbus_proxy_call_sync (sinfo->proxy, - "AddConnection", - g_variant_new ("(vb)", connection, verify_connection), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 3000, - NULL, - &error); - g_assert_no_error (error); - g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)"))); - if (out_path) - g_variant_get (result, "(o)", out_path); - g_variant_unref (result); + GVariant *result; + GError * error = NULL; + + g_assert(sinfo); + g_assert(G_IS_DBUS_PROXY(sinfo->proxy)); + g_assert(g_variant_is_of_type(connection, G_VARIANT_TYPE("a{sa{sv}}"))); + + result = g_dbus_proxy_call_sync(sinfo->proxy, + "AddConnection", + g_variant_new("(vb)", connection, verify_connection), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 3000, + NULL, + &error); + g_assert_no_error(error); + g_assert(g_variant_is_of_type(result, G_VARIANT_TYPE("(o)"))); + if (out_path) + g_variant_get(result, "(o)", out_path); + g_variant_unref(result); } void -nmtstc_service_update_connection (NMTstcServiceInfo *sinfo, - const char *path, - NMConnection *connection, - gboolean verify_connection) +nmtstc_service_update_connection(NMTstcServiceInfo *sinfo, + const char * path, + NMConnection * connection, + gboolean verify_connection) { - if (!path) - path = nm_connection_get_path (connection); - g_assert (path); - - nmtstc_service_update_connection_variant (sinfo, - path, - nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL), - verify_connection); + if (!path) + path = nm_connection_get_path(connection); + g_assert(path); + + nmtstc_service_update_connection_variant( + sinfo, + path, + nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL), + verify_connection); } void -nmtstc_service_update_connection_variant (NMTstcServiceInfo *sinfo, - const char *path, - GVariant *connection, - gboolean verify_connection) +nmtstc_service_update_connection_variant(NMTstcServiceInfo *sinfo, + const char * path, + GVariant * connection, + gboolean verify_connection) { - GVariant *result; - GError *error = NULL; - - g_assert (sinfo); - g_assert (G_IS_DBUS_PROXY (sinfo->proxy)); - g_assert (g_variant_is_of_type (connection, G_VARIANT_TYPE ("a{sa{sv}}"))); - g_assert (path && path[0] == '/'); - - result = g_dbus_proxy_call_sync (sinfo->proxy, - "UpdateConnection", - g_variant_new ("(ovb)", path, connection, verify_connection), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 3000, - NULL, - &error); - g_assert_no_error (error); - g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE ("()"))); - g_variant_unref (result); + GVariant *result; + GError * error = NULL; + + g_assert(sinfo); + g_assert(G_IS_DBUS_PROXY(sinfo->proxy)); + g_assert(g_variant_is_of_type(connection, G_VARIANT_TYPE("a{sa{sv}}"))); + g_assert(path && path[0] == '/'); + + result = g_dbus_proxy_call_sync(sinfo->proxy, + "UpdateConnection", + g_variant_new("(ovb)", path, connection, verify_connection), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 3000, + NULL, + &error); + g_assert_no_error(error); + g_assert(g_variant_is_of_type(result, G_VARIANT_TYPE("()"))); + g_variant_unref(result); } /*****************************************************************************/ typedef struct { - GType gtype; - GMainLoop *loop; - GObject *obj; - bool call_nm_client_new_async:1; + GType gtype; + GMainLoop *loop; + GObject * obj; + bool call_nm_client_new_async : 1; } NMTstcObjNewData; static void -_context_object_new_do_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +_context_object_new_do_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) { - NMTstcObjNewData *d = user_data; - gs_free_error GError *error = NULL; + NMTstcObjNewData *d = user_data; + gs_free_error GError *error = NULL; - g_assert (!d->obj); + g_assert(!d->obj); - if (d->call_nm_client_new_async) { - d->obj = G_OBJECT (nm_client_new_finish (res, - nmtst_get_rand_bool () ? &error : NULL)); - } else { - d->obj = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), - res, - nmtst_get_rand_bool () ? &error : NULL); - } + if (d->call_nm_client_new_async) { + d->obj = G_OBJECT(nm_client_new_finish(res, nmtst_get_rand_bool() ? &error : NULL)); + } else { + d->obj = g_async_initable_new_finish(G_ASYNC_INITABLE(source_object), + res, + nmtst_get_rand_bool() ? &error : NULL); + } - nmtst_assert_success (G_IS_OBJECT (d->obj), error); - g_assert (G_OBJECT_TYPE (d->obj) == d->gtype); + nmtst_assert_success(G_IS_OBJECT(d->obj), error); + g_assert(G_OBJECT_TYPE(d->obj) == d->gtype); - g_main_loop_quit (d->loop); + g_main_loop_quit(d->loop); } static GObject * -_context_object_new_do (GType gtype, - gboolean sync, - const char *first_property_name, - va_list var_args) +_context_object_new_do(GType gtype, + gboolean sync, + const char *first_property_name, + va_list var_args) { - gs_free_error GError *error = NULL; - GObject *obj; - - /* Create a GObject instance synchronously, and arbitrarily use either - * the sync or async constructor. - * - * Note that the sync and async construct differ in one important aspect: - * the async constructor iterates the current g_main_context_get_thread_default(), - * while the sync constructor does not! Aside from that, both should behave - * pretty much the same way. */ - - if (sync) { - nm_auto_destroy_and_unref_gsource GSource *source = NULL; - - if (nmtst_get_rand_bool ()) { - /* the current main context must not be iterated! */ - source = g_idle_source_new (); - g_source_set_callback (source, nmtst_g_source_assert_not_called, NULL, NULL); - g_source_attach (source, g_main_context_get_thread_default ()); - } - - if ( gtype != NM_TYPE_CLIENT - || first_property_name - || nmtst_get_rand_bool ()) { - gboolean success; - - if ( first_property_name - || nmtst_get_rand_bool ()) - obj = g_object_new_valist (gtype, first_property_name, var_args); - else - obj = g_object_new (gtype, NULL); - - success = g_initable_init (G_INITABLE (obj), - NULL, - nmtst_get_rand_bool () ? &error : NULL); - nmtst_assert_success (success, error); - } else { - obj = G_OBJECT (nm_client_new (NULL, - nmtst_get_rand_bool () ? &error : NULL)); - } - } else { - nm_auto_unref_gmainloop GMainLoop *loop = NULL; - NMTstcObjNewData d = { - .gtype = gtype, - .loop = NULL, - }; - gs_unref_object GObject *obj2 = NULL; - - loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); - d.loop = loop; - - if ( gtype != NM_TYPE_CLIENT - || first_property_name - || nmtst_get_rand_bool ()) { - if ( first_property_name - || nmtst_get_rand_bool ()) - obj2 = g_object_new_valist (gtype, first_property_name, var_args); - else - obj2 = g_object_new (gtype, NULL); - - g_async_initable_init_async (G_ASYNC_INITABLE (obj2), - G_PRIORITY_DEFAULT, - NULL, - _context_object_new_do_cb, - &d); - } else { - d.call_nm_client_new_async = TRUE; - nm_client_new_async (NULL, - _context_object_new_do_cb, - &d); - } - g_main_loop_run (loop); - obj = d.obj; - g_assert (!obj2 || obj == obj2); - } - - nmtst_assert_success (G_IS_OBJECT (obj), error); - g_assert (G_OBJECT_TYPE (obj) == gtype); - return obj; + gs_free_error GError *error = NULL; + GObject * obj; + + /* Create a GObject instance synchronously, and arbitrarily use either + * the sync or async constructor. + * + * Note that the sync and async construct differ in one important aspect: + * the async constructor iterates the current g_main_context_get_thread_default(), + * while the sync constructor does not! Aside from that, both should behave + * pretty much the same way. */ + + if (sync) { + nm_auto_destroy_and_unref_gsource GSource *source = NULL; + + if (nmtst_get_rand_bool()) { + /* the current main context must not be iterated! */ + source = g_idle_source_new(); + g_source_set_callback(source, nmtst_g_source_assert_not_called, NULL, NULL); + g_source_attach(source, g_main_context_get_thread_default()); + } + + if (gtype != NM_TYPE_CLIENT || first_property_name || nmtst_get_rand_bool()) { + gboolean success; + + if (first_property_name || nmtst_get_rand_bool()) + obj = g_object_new_valist(gtype, first_property_name, var_args); + else + obj = g_object_new(gtype, NULL); + + success = g_initable_init(G_INITABLE(obj), NULL, nmtst_get_rand_bool() ? &error : NULL); + nmtst_assert_success(success, error); + } else { + obj = G_OBJECT(nm_client_new(NULL, nmtst_get_rand_bool() ? &error : NULL)); + } + } else { + nm_auto_unref_gmainloop GMainLoop *loop = NULL; + NMTstcObjNewData d = { + .gtype = gtype, + .loop = NULL, + }; + gs_unref_object GObject *obj2 = NULL; + + loop = g_main_loop_new(g_main_context_get_thread_default(), FALSE); + d.loop = loop; + + if (gtype != NM_TYPE_CLIENT || first_property_name || nmtst_get_rand_bool()) { + if (first_property_name || nmtst_get_rand_bool()) + obj2 = g_object_new_valist(gtype, first_property_name, var_args); + else + obj2 = g_object_new(gtype, NULL); + + g_async_initable_init_async(G_ASYNC_INITABLE(obj2), + G_PRIORITY_DEFAULT, + NULL, + _context_object_new_do_cb, + &d); + } else { + d.call_nm_client_new_async = TRUE; + nm_client_new_async(NULL, _context_object_new_do_cb, &d); + } + g_main_loop_run(loop); + obj = d.obj; + g_assert(!obj2 || obj == obj2); + } + + nmtst_assert_success(G_IS_OBJECT(obj), error); + g_assert(G_OBJECT_TYPE(obj) == gtype); + return obj; } typedef struct { - GType gtype; - const char *first_property_name; - va_list var_args; - GMainLoop *loop; - GObject *obj; - bool sync; + GType gtype; + const char *first_property_name; + va_list var_args; + GMainLoop * loop; + GObject * obj; + bool sync; } NewSyncInsideDispatchedData; static gboolean -_context_object_new_inside_loop_do (gpointer user_data) +_context_object_new_inside_loop_do(gpointer user_data) { - NewSyncInsideDispatchedData *d = user_data; + NewSyncInsideDispatchedData *d = user_data; - g_assert (d->loop); - g_assert (!d->obj); + g_assert(d->loop); + g_assert(!d->obj); - d->obj = nmtstc_context_object_new_valist (d->gtype, d->sync, d->first_property_name, d->var_args); - g_main_loop_quit (d->loop); - return G_SOURCE_CONTINUE; + d->obj = + nmtstc_context_object_new_valist(d->gtype, d->sync, d->first_property_name, d->var_args); + g_main_loop_quit(d->loop); + return G_SOURCE_CONTINUE; } static GObject * -_context_object_new_inside_loop (GType gtype, - gboolean sync, - const char *first_property_name, - va_list var_args) +_context_object_new_inside_loop(GType gtype, + gboolean sync, + const char *first_property_name, + va_list var_args) { - GMainContext *context = g_main_context_get_thread_default (); - nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new (context, FALSE); - NewSyncInsideDispatchedData d = { - .gtype = gtype, - .first_property_name = first_property_name, - .sync = sync, - .loop = loop, - }; - nm_auto_destroy_and_unref_gsource GSource *source = NULL; + GMainContext * context = g_main_context_get_thread_default(); + nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(context, FALSE); + NewSyncInsideDispatchedData d = { + .gtype = gtype, + .first_property_name = first_property_name, + .sync = sync, + .loop = loop, + }; + nm_auto_destroy_and_unref_gsource GSource *source = NULL; - va_copy (d.var_args, var_args); + va_copy(d.var_args, var_args); - source = g_idle_source_new (); - g_source_set_callback (source, _context_object_new_inside_loop_do, &d, NULL); - g_source_attach (source, context); + source = g_idle_source_new(); + g_source_set_callback(source, _context_object_new_inside_loop_do, &d, NULL); + g_source_attach(source, context); - g_main_loop_run (loop); + g_main_loop_run(loop); - va_end (d.var_args); + va_end(d.var_args); - g_assert (G_IS_OBJECT (d.obj)); - g_assert (G_OBJECT_TYPE (d.obj) == gtype); - return d.obj; + g_assert(G_IS_OBJECT(d.obj)); + g_assert(G_OBJECT_TYPE(d.obj) == gtype); + return d.obj; } gpointer -nmtstc_context_object_new_valist (GType gtype, - gboolean allow_iterate_main_context, - const char *first_property_name, - va_list var_args) +nmtstc_context_object_new_valist(GType gtype, + gboolean allow_iterate_main_context, + const char *first_property_name, + va_list var_args) { - gboolean inside_loop; - gboolean sync; - - if (!allow_iterate_main_context) { - sync = TRUE; - inside_loop = FALSE; - } else { - /* The caller allows to iterate the main context. That 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 (); - inside_loop = ((nmtst_get_rand_uint32 () % 3) == 0); - } - - if (inside_loop) { - /* Create the obj on an idle handler of the current context. - * In practice, it should make no difference, which this check - * tries to prove. */ - return _context_object_new_inside_loop (gtype, sync, first_property_name, var_args); - } - - return _context_object_new_do (gtype, sync, first_property_name, var_args); + gboolean inside_loop; + gboolean sync; + + if (!allow_iterate_main_context) { + sync = TRUE; + inside_loop = FALSE; + } else { + /* 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(); + inside_loop = ((nmtst_get_rand_uint32() % 3) == 0); + } + + if (inside_loop) { + /* Create the obj on an idle handler of the current context. + * In practice, it should make no difference, which this check + * tries to prove. */ + return _context_object_new_inside_loop(gtype, sync, first_property_name, var_args); + } + + return _context_object_new_do(gtype, sync, first_property_name, var_args); } gpointer -nmtstc_context_object_new (GType gtype, - gboolean allow_iterate_main_context, - const char *first_property_name, - ...) +nmtstc_context_object_new(GType gtype, + gboolean allow_iterate_main_context, + const char *first_property_name, + ...) { - GObject *obj; - va_list var_args; - - va_start (var_args, first_property_name); - obj = nmtstc_context_object_new_valist (gtype, allow_iterate_main_context, first_property_name, var_args); - va_end (var_args); - return obj; + GObject *obj; + va_list var_args; + + va_start(var_args, first_property_name); + obj = nmtstc_context_object_new_valist(gtype, + allow_iterate_main_context, + first_property_name, + var_args); + va_end(var_args); + return obj; } diff --git a/shared/nm-udev-aux/nm-udev-utils.c b/shared/nm-udev-aux/nm-udev-utils.c index c00dcd33..8131c04e 100644 --- a/shared/nm-udev-aux/nm-udev-utils.c +++ b/shared/nm-udev-aux/nm-udev-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -10,181 +10,172 @@ #include <libudev.h> struct _NMPUdevClient { - char **subsystems; - GSource *watch_source; - struct udev *udev; - struct udev_monitor *monitor; - NMUdevClientEvent event_handler; - gpointer event_user_data; + char ** subsystems; + GSource * watch_source; + struct udev * udev; + struct udev_monitor *monitor; + NMUdevClientEvent event_handler; + gpointer event_user_data; }; /*****************************************************************************/ gboolean -nm_udev_utils_property_as_boolean (const char *uproperty) +nm_udev_utils_property_as_boolean(const char *uproperty) { - /* taken from g_udev_device_get_property_as_boolean() */ - - if (uproperty) { - if ( strcmp (uproperty, "1") == 0 - || g_ascii_strcasecmp (uproperty, "true") == 0) - return TRUE; - } - return FALSE; + /* taken from g_udev_device_get_property_as_boolean() */ + + if (uproperty) { + if (strcmp(uproperty, "1") == 0 || g_ascii_strcasecmp(uproperty, "true") == 0) + return TRUE; + } + return FALSE; } const char * -nm_udev_utils_property_decode (const char *uproperty, char **to_free) +nm_udev_utils_property_decode(const char *uproperty, char **to_free) { - const char *p; - char *unescaped = NULL; - char *n = NULL; - - if (!uproperty) { - *to_free = NULL; - return NULL; - } - - p = uproperty; - while (*p) { - int a, b; - - if ( p[0] == '\\' - && p[1] == 'x' - && (a = g_ascii_xdigit_value (p[2])) >= 0 - && (b = g_ascii_xdigit_value (p[3])) >= 0 - && (a || b)) { - if (!n) { - gssize l = p - uproperty; - - unescaped = g_malloc (l + strlen (p) + 1 - 3); - memcpy (unescaped, uproperty, l); - n = &unescaped[l]; - } - *n++ = (a << 4) | b; - p += 4; - } else { - if (n) - *n++ = *p; - p++; - } - } - - if (!n) { - *to_free = NULL; - return uproperty; - } - - *n++ = '\0'; - return (*to_free = unescaped); + const char *p; + char * unescaped = NULL; + char * n = NULL; + + if (!uproperty) { + *to_free = NULL; + return NULL; + } + + p = uproperty; + while (*p) { + int a, b; + + if (p[0] == '\\' && p[1] == 'x' && (a = g_ascii_xdigit_value(p[2])) >= 0 + && (b = g_ascii_xdigit_value(p[3])) >= 0 && (a || b)) { + if (!n) { + gssize l = p - uproperty; + + unescaped = g_malloc(l + strlen(p) + 1 - 3); + memcpy(unescaped, uproperty, l); + n = &unescaped[l]; + } + *n++ = (a << 4) | b; + p += 4; + } else { + if (n) + *n++ = *p; + p++; + } + } + + if (!n) { + *to_free = NULL; + return uproperty; + } + + *n++ = '\0'; + return (*to_free = unescaped); } char * -nm_udev_utils_property_decode_cp (const char *uproperty) +nm_udev_utils_property_decode_cp(const char *uproperty) { - char *cpy; + char *cpy; - uproperty = nm_udev_utils_property_decode (uproperty, &cpy); - return cpy ?: g_strdup (uproperty); + uproperty = nm_udev_utils_property_decode(uproperty, &cpy); + return cpy ?: g_strdup(uproperty); } /*****************************************************************************/ static void -_subsystem_split (const char *subsystem_full, - const char **out_subsystem, - const char **out_devtype, - char **to_free) +_subsystem_split(const char * subsystem_full, + const char **out_subsystem, + const char **out_devtype, + char ** to_free) { - char *tmp, *s; - - nm_assert (subsystem_full); - nm_assert (out_subsystem); - nm_assert (out_devtype); - nm_assert (to_free); - - s = strstr (subsystem_full, "/"); - if (s) { - tmp = g_strdup (subsystem_full); - s = &tmp[s - subsystem_full]; - *s = '\0'; - *out_subsystem = tmp; - *out_devtype = &s[1]; - *to_free = tmp; - } else { - *out_subsystem = subsystem_full; - *out_devtype = NULL; - *to_free = NULL; - } + char *tmp, *s; + + nm_assert(subsystem_full); + nm_assert(out_subsystem); + nm_assert(out_devtype); + nm_assert(to_free); + + s = strstr(subsystem_full, "/"); + if (s) { + tmp = g_strdup(subsystem_full); + s = &tmp[s - subsystem_full]; + *s = '\0'; + *out_subsystem = tmp; + *out_devtype = &s[1]; + *to_free = tmp; + } else { + *out_subsystem = subsystem_full; + *out_devtype = NULL; + *to_free = NULL; + } } static struct udev_enumerate * -nm_udev_utils_enumerate (struct udev *uclient, - const char *const*subsystems) +nm_udev_utils_enumerate(struct udev *uclient, const char *const *subsystems) { - struct udev_enumerate *enumerate; - guint n; + struct udev_enumerate *enumerate; + guint n; - enumerate = udev_enumerate_new (uclient); + enumerate = udev_enumerate_new(uclient); - if (subsystems) { - for (n = 0; subsystems[n]; n++) { - const char *subsystem; - const char *devtype; - gs_free char *to_free = NULL; + if (subsystems) { + for (n = 0; subsystems[n]; n++) { + const char * subsystem; + const char * devtype; + gs_free char *to_free = NULL; - _subsystem_split (subsystems[n], &subsystem, &devtype, &to_free); + _subsystem_split(subsystems[n], &subsystem, &devtype, &to_free); - udev_enumerate_add_match_subsystem (enumerate, subsystem); + udev_enumerate_add_match_subsystem(enumerate, subsystem); - if (devtype != NULL) - udev_enumerate_add_match_property (enumerate, "DEVTYPE", devtype); - } - } + if (devtype != NULL) + udev_enumerate_add_match_property(enumerate, "DEVTYPE", devtype); + } + } - return enumerate; + return enumerate; } struct udev * -nm_udev_client_get_udev (NMUdevClient *self) +nm_udev_client_get_udev(NMUdevClient *self) { - g_return_val_if_fail (self, NULL); + g_return_val_if_fail(self, NULL); - return self->udev; + return self->udev; } struct udev_enumerate * -nm_udev_client_enumerate_new (NMUdevClient *self) +nm_udev_client_enumerate_new(NMUdevClient *self) { - g_return_val_if_fail (self, NULL); + g_return_val_if_fail(self, NULL); - return nm_udev_utils_enumerate (self->udev, (const char *const*) self->subsystems); + return nm_udev_utils_enumerate(self->udev, (const char *const *) self->subsystems); } /*****************************************************************************/ static gboolean -monitor_event (int fd, - GIOCondition condition, - gpointer user_data) +monitor_event(int fd, GIOCondition condition, gpointer user_data) { - NMUdevClient *self = user_data; - struct udev_device *udevice; + NMUdevClient * self = user_data; + struct udev_device *udevice; - if (!self->monitor) - goto out; + if (!self->monitor) + goto out; - udevice = udev_monitor_receive_device (self->monitor); - if (udevice == NULL) - goto out; + udevice = udev_monitor_receive_device(self->monitor); + if (udevice == NULL) + goto out; - self->event_handler (self, - udevice, - self->event_user_data); - udev_device_unref (udevice); + self->event_handler(self, udevice, self->event_user_data); + udev_device_unref(udevice); out: - return TRUE; + return TRUE; } /** @@ -199,76 +190,76 @@ out: * Returns: a new NMUdevClient instance. */ NMUdevClient * -nm_udev_client_new (const char *const*subsystems, - NMUdevClientEvent event_handler, - gpointer event_user_data) +nm_udev_client_new(const char *const *subsystems, + NMUdevClientEvent event_handler, + gpointer event_user_data) { - NMUdevClient *self; - guint n; - - self = g_slice_new0 (NMUdevClient); - - self->event_handler = event_handler; - self->event_user_data = event_user_data; - self->subsystems = subsystems && subsystems[0] ? g_strdupv ((char **) subsystems) : NULL; - - self->udev = udev_new (); - if (!self->udev) - goto fail; - - /* connect to event source */ - if (self->event_handler) { - self->monitor = udev_monitor_new_from_netlink (self->udev, "udev"); - if (!self->monitor) - goto fail; - - if (self->subsystems) { - /* install subsystem filters to only wake up for certain events */ - for (n = 0; self->subsystems[n]; n++) { - gs_free char *to_free = NULL; - const char *subsystem; - const char *devtype; - - _subsystem_split (self->subsystems[n], &subsystem, &devtype, &to_free); - udev_monitor_filter_add_match_subsystem_devtype (self->monitor, subsystem, devtype); - } - - /* listen to events, and buffer them */ - udev_monitor_set_receive_buffer_size (self->monitor, 4*1024*1024); - udev_monitor_enable_receiving (self->monitor); - - self->watch_source = nm_g_unix_fd_source_new (udev_monitor_get_fd (self->monitor), - G_IO_IN, - G_PRIORITY_DEFAULT, - monitor_event, - self, - NULL); - g_source_attach (self->watch_source, g_main_context_get_thread_default ()); - } - } - - return self; + NMUdevClient *self; + guint n; + + self = g_slice_new0(NMUdevClient); + + self->event_handler = event_handler; + self->event_user_data = event_user_data; + self->subsystems = subsystems && subsystems[0] ? g_strdupv((char **) subsystems) : NULL; + + self->udev = udev_new(); + if (!self->udev) + goto fail; + + /* connect to event source */ + if (self->event_handler) { + self->monitor = udev_monitor_new_from_netlink(self->udev, "udev"); + if (!self->monitor) + goto fail; + + if (self->subsystems) { + /* install subsystem filters to only wake up for certain events */ + for (n = 0; self->subsystems[n]; n++) { + gs_free char *to_free = NULL; + const char * subsystem; + const char * devtype; + + _subsystem_split(self->subsystems[n], &subsystem, &devtype, &to_free); + udev_monitor_filter_add_match_subsystem_devtype(self->monitor, subsystem, devtype); + } + + /* listen to events, and buffer them */ + udev_monitor_set_receive_buffer_size(self->monitor, 4 * 1024 * 1024); + udev_monitor_enable_receiving(self->monitor); + + self->watch_source = nm_g_unix_fd_source_new(udev_monitor_get_fd(self->monitor), + G_IO_IN, + G_PRIORITY_DEFAULT, + monitor_event, + self, + NULL); + g_source_attach(self->watch_source, g_main_context_get_thread_default()); + } + } + + return self; fail: - return nm_udev_client_unref (self); + return nm_udev_client_unref(self); } NMUdevClient * -nm_udev_client_unref (NMUdevClient *self) +nm_udev_client_unref(NMUdevClient *self) { - if (!self) - return NULL; + if (!self) + return NULL; - nm_clear_g_source_inst (&self->watch_source); + nm_clear_g_source_inst(&self->watch_source); - udev_monitor_unref (self->monitor); - self->monitor = NULL; - udev_unref (self->udev); - self->udev = NULL; + udev_monitor_unref(self->monitor); + self->monitor = NULL; + udev_unref(self->udev); + self->udev = NULL; - g_strfreev (self->subsystems); + g_strfreev(self->subsystems); - g_slice_free (NMUdevClient, self); + g_slice_free(NMUdevClient, self); - return NULL; + return NULL; } diff --git a/shared/nm-udev-aux/nm-udev-utils.h b/shared/nm-udev-aux/nm-udev-utils.h index 92fce699..f24659eb 100644 --- a/shared/nm-udev-aux/nm-udev-utils.h +++ b/shared/nm-udev-aux/nm-udev-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -10,24 +10,24 @@ struct udev; struct udev_device; struct udev_enumerate; -gboolean nm_udev_utils_property_as_boolean (const char *uproperty); -const char *nm_udev_utils_property_decode (const char *uproperty, char **to_free); -char *nm_udev_utils_property_decode_cp (const char *uproperty); +gboolean nm_udev_utils_property_as_boolean(const char *uproperty); +const char *nm_udev_utils_property_decode(const char *uproperty, char **to_free); +char * nm_udev_utils_property_decode_cp(const char *uproperty); typedef struct _NMPUdevClient NMUdevClient; -typedef void (*NMUdevClientEvent) (NMUdevClient *udev_client, - struct udev_device *udevice, - gpointer event_user_data); +typedef void (*NMUdevClientEvent)(NMUdevClient * udev_client, + struct udev_device *udevice, + gpointer event_user_data); -NMUdevClient *nm_udev_client_new (const char *const*subsystems, - NMUdevClientEvent event_handler, - gpointer event_user_data); +NMUdevClient *nm_udev_client_new(const char *const *subsystems, + NMUdevClientEvent event_handler, + gpointer event_user_data); -NMUdevClient *nm_udev_client_unref (NMUdevClient *self); +NMUdevClient *nm_udev_client_unref(NMUdevClient *self); -struct udev *nm_udev_client_get_udev (NMUdevClient *self); +struct udev *nm_udev_client_get_udev(NMUdevClient *self); -struct udev_enumerate *nm_udev_client_enumerate_new (NMUdevClient *self); +struct udev_enumerate *nm_udev_client_enumerate_new(NMUdevClient *self); #endif /* __NM_UDEV_UTILS_H__ */ diff --git a/shared/nm-utils/nm-compat.c b/shared/nm-utils/nm-compat.c index 895d9550..f87ef6b9 100644 --- a/shared/nm-utils/nm-compat.c +++ b/shared/nm-utils/nm-compat.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -10,71 +10,67 @@ /*****************************************************************************/ static void -_get_keys_cb (const char *key, const char *val, gpointer user_data) +_get_keys_cb(const char *key, const char *val, gpointer user_data) { - GPtrArray *a = user_data; + GPtrArray *a = user_data; - g_ptr_array_add (a, g_strdup (key)); + g_ptr_array_add(a, g_strdup(key)); } static const char ** -_get_keys (NMSettingVpn *setting, - gboolean is_secrets, - guint *out_length) +_get_keys(NMSettingVpn *setting, gboolean is_secrets, guint *out_length) { - guint len; - const char **keys = NULL; - GPtrArray *a; - - nm_assert (NM_IS_SETTING_VPN (setting)); - - if (is_secrets) - len = nm_setting_vpn_get_num_secrets (setting); - else - len = nm_setting_vpn_get_num_data_items (setting); - - a = g_ptr_array_sized_new (len + 1); - - if (is_secrets) - nm_setting_vpn_foreach_secret (setting, _get_keys_cb, a); - else - nm_setting_vpn_foreach_data_item (setting, _get_keys_cb, a); - - len = a->len; - if (len) { - g_ptr_array_sort (a, nm_strcmp_p); - g_ptr_array_add (a, NULL); - keys = g_malloc (a->len * sizeof (gpointer)); - memcpy (keys, a->pdata, a->len * sizeof (gpointer)); - - /* we need to cache the keys *somewhere*. */ - g_object_set_qdata_full (G_OBJECT (setting), - is_secrets - ? NM_CACHED_QUARK ("libnm._nm_setting_vpn_get_secret_keys") - : NM_CACHED_QUARK ("libnm._nm_setting_vpn_get_data_keys"), - g_ptr_array_free (a, FALSE), - (GDestroyNotify) g_strfreev); - } else - g_ptr_array_free (a, TRUE); - - NM_SET_OUT (out_length, len); - return keys; + guint len; + const char **keys = NULL; + GPtrArray * a; + + nm_assert(NM_IS_SETTING_VPN(setting)); + + if (is_secrets) + len = nm_setting_vpn_get_num_secrets(setting); + else + len = nm_setting_vpn_get_num_data_items(setting); + + a = g_ptr_array_sized_new(len + 1); + + if (is_secrets) + nm_setting_vpn_foreach_secret(setting, _get_keys_cb, a); + else + nm_setting_vpn_foreach_data_item(setting, _get_keys_cb, a); + + len = a->len; + if (len) { + g_ptr_array_sort(a, nm_strcmp_p); + g_ptr_array_add(a, NULL); + keys = g_malloc(a->len * sizeof(gpointer)); + memcpy(keys, a->pdata, a->len * sizeof(gpointer)); + + /* we need to cache the keys *somewhere*. */ + g_object_set_qdata_full(G_OBJECT(setting), + is_secrets + ? NM_CACHED_QUARK("libnm._nm_setting_vpn_get_secret_keys") + : NM_CACHED_QUARK("libnm._nm_setting_vpn_get_data_keys"), + g_ptr_array_free(a, FALSE), + (GDestroyNotify) g_strfreev); + } else + g_ptr_array_free(a, TRUE); + + NM_SET_OUT(out_length, len); + return keys; } const char ** -_nm_setting_vpn_get_data_keys (NMSettingVpn *setting, - guint *out_length) +_nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length) { - g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL); + g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL); - return _get_keys (setting, FALSE, out_length); + return _get_keys(setting, FALSE, out_length); } const char ** -_nm_setting_vpn_get_secret_keys (NMSettingVpn *setting, - guint *out_length) +_nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length) { - g_return_val_if_fail (NM_IS_SETTING_VPN (setting), NULL); + g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL); - return _get_keys (setting, TRUE, out_length); + return _get_keys(setting, TRUE, out_length); } diff --git a/shared/nm-utils/nm-compat.h b/shared/nm-utils/nm-compat.h index 55f764c7..fb136a5b 100644 --- a/shared/nm-utils/nm-compat.h +++ b/shared/nm-utils/nm-compat.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2017 Red Hat, Inc. */ @@ -8,30 +8,28 @@ #include "nm-setting-vpn.h" -const char **_nm_setting_vpn_get_data_keys (NMSettingVpn *setting, - guint *out_length); +const char **_nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length); -const char **_nm_setting_vpn_get_secret_keys (NMSettingVpn *setting, - guint *out_length); +const char **_nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length); -#if NM_CHECK_VERSION (1, 11, 0) -#define nm_setting_vpn_get_data_keys(setting, out_length) \ - ({ \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - nm_setting_vpn_get_data_keys (setting, out_length); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - }) -#define nm_setting_vpn_get_secret_keys(setting, out_length) \ - ({ \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - nm_setting_vpn_get_secret_keys (setting, out_length); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - }) +#if NM_CHECK_VERSION(1, 11, 0) + #define nm_setting_vpn_get_data_keys(setting, out_length) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + nm_setting_vpn_get_data_keys(setting, out_length); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) + #define nm_setting_vpn_get_secret_keys(setting, out_length) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + nm_setting_vpn_get_secret_keys(setting, out_length); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) #else -#define nm_setting_vpn_get_data_keys(setting, out_length) \ - _nm_setting_vpn_get_data_keys (setting, out_length) -#define nm_setting_vpn_get_secret_keys(setting, out_length) \ - _nm_setting_vpn_get_secret_keys (setting, out_length) + #define nm_setting_vpn_get_data_keys(setting, out_length) \ + _nm_setting_vpn_get_data_keys(setting, out_length) + #define nm_setting_vpn_get_secret_keys(setting, out_length) \ + _nm_setting_vpn_get_secret_keys(setting, out_length) #endif #endif /* __NM_COMPAT_H__ */ diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h index c270d2b9..9d484882 100644 --- a/shared/nm-utils/nm-test-utils.h +++ b/shared/nm-utils/nm-test-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2014 Red Hat, Inc. */ @@ -7,7 +7,7 @@ #define __NM_TEST_UTILS_H__ #if defined(NETWORKMANAGER_COMPILATION) && !defined(NETWORKMANAGER_COMPILATION_TEST) -#error Need to mark the compilation with NETWORKMANAGER_COMPILATION_TEST. + #error Need to mark the compilation with NETWORKMANAGER_COMPILATION_TEST. #endif /******************************************************************************* @@ -87,8 +87,8 @@ #include "nm-default.h" #if defined(NM_ASSERT_NO_MSG) && NM_ASSERT_NO_MSG -#undef g_return_if_fail_warning -#undef g_assertion_message_expr + #undef g_return_if_fail_warning + #undef g_assertion_message_expr #endif #include <arpa/inet.h> @@ -99,12 +99,12 @@ #include <errno.h> #ifndef NM_TEST_UTILS_NO_LIBNM -#include "nm-utils.h" + #include "nm-utils.h" #endif /*****************************************************************************/ -#define NMTST_G_RETURN_MSG_S(expr) "*: assertion '"NM_ASSERT_G_RETURN_EXPR(expr)"' failed" +#define NMTST_G_RETURN_MSG_S(expr) "*: assertion '" NM_ASSERT_G_RETURN_EXPR(expr) "' failed" #define NMTST_G_RETURN_MSG(expr) NMTST_G_RETURN_MSG_S(#expr) /*****************************************************************************/ @@ -112,72 +112,85 @@ /* general purpose functions that have no dependency on other nmtst functions */ #define nmtst_assert_error(error, expect_error_domain, expect_error_code, expect_error_pattern) \ - G_STMT_START { \ - GError *_error = (error); \ - GQuark _expect_error_domain = (expect_error_domain); \ - const char *_expect_error_pattern = (expect_error_pattern); \ - \ - if (_expect_error_domain) \ - g_assert_error (_error, _expect_error_domain, (expect_error_code)); \ - else \ - g_assert (_error); \ - g_assert (_error->message); \ - if ( _expect_error_pattern \ - && !g_pattern_match_simple (_expect_error_pattern, _error->message)) { \ - g_error ("%s:%d: error message does not have expected pattern '%s'. Instead it is '%s' (%s, %d)", \ - __FILE__, __LINE__, \ - _expect_error_pattern, _error->message, g_quark_to_string (_error->domain), _error->code); \ - } \ - } G_STMT_END - -#define NMTST_WAIT(max_wait_ms, wait) \ - ({ \ - gboolean _not_expired = TRUE; \ - const gint64 nmtst_wait_start_us = g_get_monotonic_time (); \ - const gint64 nmtst_wait_duration_us = (max_wait_ms) * 1000L; \ - const gint64 nmtst_wait_end_us = nmtst_wait_start_us + nmtst_wait_duration_us; \ - gint64 _nmtst_wait_remaining_us = nmtst_wait_duration_us; \ - int _nmtst_wait_iteration = 0; \ - \ - while (TRUE) { \ - _nm_unused const gint64 nmtst_wait_remaining_us = _nmtst_wait_remaining_us; \ - _nm_unused int nmtst_wait_iteration = _nmtst_wait_iteration++; \ - \ - { wait }; \ - _nmtst_wait_remaining_us = (nmtst_wait_end_us - g_get_monotonic_time ()); \ - if (_nmtst_wait_remaining_us <= 0) { \ - _not_expired = FALSE; \ - break; \ - } \ - } \ - _not_expired; \ - }) - -#define NMTST_WAIT_ASSERT(max_wait_ms, wait) \ - G_STMT_START { \ - if (!(NMTST_WAIT (max_wait_ms, wait))) \ - g_assert_not_reached (); \ - } G_STMT_END - -#define nmtst_assert_nonnull(command) \ - ({ \ - typeof (*(command)) *_ptr = (command); \ - \ - g_assert (_ptr && (TRUE || (command))); \ - _ptr; \ - }) + G_STMT_START \ + { \ + GError * _error = (error); \ + GQuark _expect_error_domain = (expect_error_domain); \ + const char *_expect_error_pattern = (expect_error_pattern); \ + \ + if (_expect_error_domain) \ + g_assert_error(_error, _expect_error_domain, (expect_error_code)); \ + else \ + g_assert(_error); \ + g_assert(_error->message); \ + if (_expect_error_pattern \ + && !g_pattern_match_simple(_expect_error_pattern, _error->message)) { \ + g_error("%s:%d: error message does not have expected pattern '%s'. Instead it is " \ + "'%s' (%s, %d)", \ + __FILE__, \ + __LINE__, \ + _expect_error_pattern, \ + _error->message, \ + g_quark_to_string(_error->domain), \ + _error->code); \ + } \ + } \ + G_STMT_END + +#define NMTST_WAIT(max_wait_ms, wait) \ + ({ \ + gboolean _not_expired = TRUE; \ + const gint64 nmtst_wait_start_us = g_get_monotonic_time(); \ + const gint64 nmtst_wait_duration_us = (max_wait_ms) *1000L; \ + const gint64 nmtst_wait_end_us = nmtst_wait_start_us + nmtst_wait_duration_us; \ + gint64 _nmtst_wait_remaining_us = nmtst_wait_duration_us; \ + int _nmtst_wait_iteration = 0; \ + \ + while (TRUE) { \ + _nm_unused const gint64 nmtst_wait_remaining_us = _nmtst_wait_remaining_us; \ + _nm_unused int nmtst_wait_iteration = _nmtst_wait_iteration++; \ + \ + {wait}; \ + _nmtst_wait_remaining_us = (nmtst_wait_end_us - g_get_monotonic_time()); \ + if (_nmtst_wait_remaining_us <= 0) { \ + _not_expired = FALSE; \ + break; \ + } \ + } \ + _not_expired; \ + }) + +#define NMTST_WAIT_ASSERT(max_wait_ms, wait) \ + G_STMT_START \ + { \ + if (!(NMTST_WAIT(max_wait_ms, wait))) \ + g_assert_not_reached(); \ + } \ + G_STMT_END + +#define nmtst_assert_nonnull(command) \ + ({ \ + typeof(*(command)) *_ptr = (command); \ + \ + g_assert(_ptr && (TRUE || (command))); \ + _ptr; \ + }) #define nmtst_assert_success(success, error) \ - G_STMT_START { \ - g_assert_no_error (error); \ - g_assert ((success)); \ - } G_STMT_END + G_STMT_START \ + { \ + g_assert_no_error(error); \ + g_assert((success)); \ + } \ + G_STMT_END #define nmtst_assert_no_success(success, error) \ - G_STMT_START { \ - g_assert (error); \ - g_assert (!(success)); \ - } G_STMT_END + G_STMT_START \ + { \ + g_assert(error); \ + g_assert(!(success)); \ + } \ + G_STMT_END /*****************************************************************************/ @@ -189,59 +202,59 @@ * are returned. For a lot of functions, positive return values are unexpected * and a bug. This macro evaluates @r to success or failure, while asserting * that @r is not positive. */ -#define NMTST_NM_ERR_SUCCESS(r) \ - ({ \ - const int _r = (r); \ - \ - if (_r >= 0) \ - g_assert_cmpint (_r, ==, 0); \ - (_r >= 0); \ - }) +#define NMTST_NM_ERR_SUCCESS(r) \ + ({ \ + const int _r = (r); \ + \ + if (_r >= 0) \ + g_assert_cmpint(_r, ==, 0); \ + (_r >= 0); \ + }) /*****************************************************************************/ -struct __nmtst_internal -{ - GRand *rand0; - guint32 rand_seed; - GRand *rand; - gboolean is_debug; - gboolean assert_logging; - gboolean no_expect_message; - gboolean test_quick; - gboolean test_tap_log; - char *sudo_cmd; - char **orig_argv; +struct __nmtst_internal { + GRand * rand0; + guint32 rand_seed; + GRand * rand; + gboolean is_debug; + gboolean assert_logging; + gboolean no_expect_message; + gboolean test_quick; + gboolean test_tap_log; + char * sudo_cmd; + char ** orig_argv; }; extern struct __nmtst_internal __nmtst_internal; -#define NMTST_DEFINE() \ -struct __nmtst_internal __nmtst_internal = { 0 }; \ -\ -__attribute__ ((destructor)) static void \ -_nmtst_exit (void) \ -{ \ - __nmtst_internal.assert_logging = FALSE; \ - g_test_assert_expected_messages (); \ - nmtst_free (); \ -} +#define NMTST_DEFINE() \ + struct __nmtst_internal __nmtst_internal = {0}; \ + \ + __attribute__((destructor)) static void _nmtst_exit(void) \ + { \ + __nmtst_internal.assert_logging = FALSE; \ + g_test_assert_expected_messages(); \ + nmtst_free(); \ + } static inline gboolean -nmtst_initialized (void) +nmtst_initialized(void) { - return !!__nmtst_internal.rand0; + return !!__nmtst_internal.rand0; } -#define __NMTST_LOG(cmd, ...) \ - G_STMT_START { \ - g_assert (nmtst_initialized ()); \ - if (!__nmtst_internal.assert_logging || __nmtst_internal.no_expect_message) { \ - cmd (__VA_ARGS__); \ - } else { \ - printf (_NM_UTILS_MACRO_FIRST (__VA_ARGS__) "\n" _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } \ - } G_STMT_END +#define __NMTST_LOG(cmd, ...) \ + G_STMT_START \ + { \ + g_assert(nmtst_initialized()); \ + if (!__nmtst_internal.assert_logging || __nmtst_internal.no_expect_message) { \ + cmd(__VA_ARGS__); \ + } else { \ + printf(_NM_UTILS_MACRO_FIRST(__VA_ARGS__) "\n" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END /* split the string inplace at specific delimiters, allowing escaping with '\\'. * Returns a zero terminated array of pointers into @str. @@ -249,739 +262,800 @@ nmtst_initialized (void) * The caller must g_free() the returned argv array. **/ static inline char ** -nmtst_str_split (char *str, const char *delimiters) -{ - const char *d; - GArray *result = g_array_sized_new (TRUE, FALSE, sizeof (char *), 3); - - g_assert (str); - g_assert (delimiters && !strchr (delimiters, '\\')); - - while (*str) { - gsize i = 0, j = 0; - - while (TRUE) { - char c = str[i]; - - if (c == '\0') { - str[j++] = 0; - break; - } else if (c == '\\') { - str[j++] = str[++i]; - if (!str[i]) - break; - } else { - for (d = delimiters; *d; d++) { - if (c == *d) { - str[j++] = 0; - i++; - goto BREAK_INNER_LOOPS; - } - } - str[j++] = c; - } - i++; - } +nmtst_str_split(char *str, const char *delimiters) +{ + const char *d; + GArray * result = g_array_sized_new(TRUE, FALSE, sizeof(char *), 3); + + g_assert(str); + g_assert(delimiters && !strchr(delimiters, '\\')); + + while (*str) { + gsize i = 0, j = 0; + + while (TRUE) { + char c = str[i]; + + if (c == '\0') { + str[j++] = 0; + break; + } else if (c == '\\') { + str[j++] = str[++i]; + if (!str[i]) + break; + } else { + for (d = delimiters; *d; d++) { + if (c == *d) { + str[j++] = 0; + i++; + goto BREAK_INNER_LOOPS; + } + } + str[j++] = c; + } + i++; + } BREAK_INNER_LOOPS: - g_array_append_val (result, str); - str = &str[i]; - } + g_array_append_val(result, str); + str = &str[i]; + } - return (char **) g_array_free (result, FALSE); + return (char **) g_array_free(result, FALSE); } /* free instances allocated by nmtst (especially nmtst_init()) on shutdown * to release memory. After nmtst_free(), the test is uninitialized again. */ static inline void -nmtst_free (void) +nmtst_free(void) { - if (!nmtst_initialized ()) - return; + if (!nmtst_initialized()) + return; - g_rand_free (__nmtst_internal.rand0); - if (__nmtst_internal.rand) - g_rand_free (__nmtst_internal.rand); - g_free (__nmtst_internal.sudo_cmd); - g_strfreev (__nmtst_internal.orig_argv); + g_rand_free(__nmtst_internal.rand0); + if (__nmtst_internal.rand) + g_rand_free(__nmtst_internal.rand); + g_free(__nmtst_internal.sudo_cmd); + g_strfreev(__nmtst_internal.orig_argv); - memset (&__nmtst_internal, 0, sizeof (__nmtst_internal)); + memset(&__nmtst_internal, 0, sizeof(__nmtst_internal)); } static inline void -_nmtst_log_handler (const char *log_domain, - GLogLevelFlags log_level, - const char *message, - gpointer user_data) +_nmtst_log_handler(const char * log_domain, + GLogLevelFlags log_level, + const char * message, + gpointer user_data) { - g_print ("%s\n", message); + g_print("%s\n", message); } static inline void -__nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_level, const char *log_domains, gboolean *out_set_logging) -{ - const char *nmtst_debug; - gboolean is_debug = FALSE; - char *c_log_level = NULL, *c_log_domains = NULL; - char *sudo_cmd = NULL; - GArray *debug_messages = g_array_new (TRUE, FALSE, sizeof (char *)); - int i; - gboolean no_expect_message = FALSE; - gboolean _out_set_logging; - gboolean test_quick = FALSE; - gboolean test_quick_set = FALSE; - gboolean test_quick_argv = FALSE; - gs_unref_ptrarray GPtrArray *p_tests = NULL; - gs_unref_ptrarray GPtrArray *s_tests = NULL; - - if (!out_set_logging) - out_set_logging = &_out_set_logging; - *out_set_logging = FALSE; - - g_assert (!nmtst_initialized ()); - - g_assert (!((!!argc) ^ (!!argv))); - g_assert (!argc || (g_strv_length (*argv) == *argc)); - g_assert (!assert_logging || (!log_level && !log_domains)); +__nmtst_init(int * argc, + char *** argv, + gboolean assert_logging, + const char *log_level, + const char *log_domains, + gboolean * out_set_logging) +{ + const char * nmtst_debug; + gboolean is_debug = FALSE; + char * c_log_level = NULL, *c_log_domains = NULL; + char * sudo_cmd = NULL; + GArray * debug_messages = g_array_new(TRUE, FALSE, sizeof(char *)); + int i; + gboolean no_expect_message = FALSE; + gboolean _out_set_logging; + gboolean test_quick = FALSE; + gboolean test_quick_set = FALSE; + gboolean test_quick_argv = FALSE; + gs_unref_ptrarray GPtrArray *p_tests = NULL; + gs_unref_ptrarray GPtrArray *s_tests = NULL; + + if (!out_set_logging) + out_set_logging = &_out_set_logging; + *out_set_logging = FALSE; + + g_assert(!nmtst_initialized()); + + g_assert(!((!!argc) ^ (!!argv))); + g_assert(!argc || (g_strv_length(*argv) == *argc)); + g_assert(!assert_logging || (!log_level && !log_domains)); #ifdef __NETWORKMANAGER_UTILS_H__ - if (!nm_utils_get_testing_initialized ()) - _nm_utils_set_testing (_NM_UTILS_TEST_GENERAL); + if (!nm_utils_get_testing_initialized()) + _nm_utils_set_testing(_NM_UTILS_TEST_GENERAL); #endif - if (argc) - __nmtst_internal.orig_argv = g_strdupv (*argv); - - __nmtst_internal.assert_logging = !!assert_logging; - - nm_g_type_init (); - - is_debug = g_test_verbose (); - - nmtst_debug = g_getenv ("NMTST_DEBUG"); - if (nmtst_debug) { - char **d_argv, **i_argv, *nmtst_debug_copy; - - /* By setting then NMTST_DEBUG variable, @is_debug is set automatically. - * This can be reverted with no-debug (on command line or environment variable). */ - is_debug = TRUE; - - nmtst_debug_copy = g_strdup (nmtst_debug); - d_argv = nmtst_str_split (nmtst_debug_copy, ",; \t\r\n"); - - for (i_argv = d_argv; *i_argv; i_argv++) { - const char *debug = *i_argv; - - if (!g_ascii_strcasecmp (debug, "debug")) - is_debug = TRUE; - else if (!g_ascii_strcasecmp (debug, "no-debug")) { - /* when specifying the NMTST_DEBUG variable, we set is_debug to true. Use this flag to disable this - * (e.g. for only setting the log-level, but not is_debug). */ - is_debug = FALSE; - } else if (!g_ascii_strncasecmp (debug, "log-level=", strlen ("log-level="))) { - g_free (c_log_level); - log_level = c_log_level = g_strdup (&debug[strlen ("log-level=")]); - } else if (!g_ascii_strcasecmp (debug, "D")) { - /* shorthand for "log-level=TRACE,no-expect-message" */ - g_free (c_log_level); - log_level = c_log_level = g_strdup ("TRACE"); - no_expect_message = TRUE; - } else if (!g_ascii_strcasecmp (debug, "TRACE")) { - g_free (c_log_level); - log_level = c_log_level = g_strdup ("TRACE"); - } else if (!g_ascii_strncasecmp (debug, "log-domains=", strlen ("log-domains="))) { - g_free (c_log_domains); - log_domains = c_log_domains = g_strdup (&debug[strlen ("log-domains=")]); - } else if (!g_ascii_strncasecmp (debug, "sudo-cmd=", strlen ("sudo-cmd="))) { - g_free (sudo_cmd); - sudo_cmd = g_strdup (&debug[strlen ("sudo-cmd=")]); - } else if (!g_ascii_strcasecmp (debug, "no-expect-message")) { - no_expect_message = TRUE; - } else if (!g_ascii_strncasecmp (debug, "p=", strlen ("p="))) { - if (!p_tests) - p_tests = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (p_tests, g_strdup (&debug[strlen ("p=")])); - } else if (!g_ascii_strncasecmp (debug, "s=", strlen ("s="))) { - if (!s_tests) - s_tests = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (s_tests, g_strdup (&debug[strlen ("s=")])); - } else if (!g_ascii_strcasecmp (debug, "slow") || !g_ascii_strcasecmp (debug, "thorough")) { - test_quick = FALSE; - test_quick_set = TRUE; - } else if (!g_ascii_strcasecmp (debug, "quick")) { - test_quick = TRUE; - test_quick_set = TRUE; - } else { - char *msg = g_strdup_printf (">>> nmtst: ignore unrecognized NMTST_DEBUG option \"%s\"", debug); - - g_array_append_val (debug_messages, msg); - } - } - - g_free (d_argv); - g_free (nmtst_debug_copy); - } - - if (__nmtst_internal.orig_argv) { - char **a = __nmtst_internal.orig_argv; - - for (; *a; a++) { - if (!g_ascii_strcasecmp (*a, "--debug")) - is_debug = TRUE; - else if (!g_ascii_strcasecmp (*a, "--no-debug")) - is_debug = FALSE; - else if ( !strcmp (*a, "-m=slow") - || !strcmp (*a, "-m=thorough") - || !strcmp (*a, "-m=quick") - || (!strcmp (*a, "-m") && *(a+1) - && ( !strcmp (*(a+1), "quick") - || !strcmp (*(a+1), "slow") - || !strcmp (*(a+1), "thorough")))) - test_quick_argv = TRUE; - else if (strcmp (*a, "--tap") == 0) - __nmtst_internal.test_tap_log = TRUE; - } - } - - if (!argc || g_test_initialized ()) { - if (p_tests || s_tests) { - char *msg = g_strdup_printf (">>> nmtst: ignore -p and -s options for test which calls g_test_init() itself"); - - g_array_append_val (debug_messages, msg); - } - } else { - /* We're intentionally assigning a value to static variables - * s_tests_x and p_tests_x without using it afterwards, just - * so that valgrind doesn't complain about the leak. */ - NM_PRAGMA_WARNING_DISABLE("-Wunused-but-set-variable") - - /* g_test_init() is a variadic function, so we cannot pass it - * (variadic) arguments. If you need to pass additional parameters, - * call nmtst_init() with argc==NULL and call g_test_init() yourself. */ - - /* g_test_init() sets g_log_set_always_fatal() for G_LOG_LEVEL_WARNING - * and G_LOG_LEVEL_CRITICAL. So, beware that the test will fail if you - * have any WARN or ERR log messages -- unless you g_test_expect_message(). */ - GPtrArray *arg_array = g_ptr_array_new (); - gs_free char **arg_array_c = NULL; - int arg_array_n, j; - static char **s_tests_x, **p_tests_x; - - if (*argc) { - for (i = 0; i < *argc; i++) - g_ptr_array_add (arg_array, (*argv)[i]); - } else - g_ptr_array_add (arg_array, "./test"); - - if (test_quick_set && !test_quick_argv) - g_ptr_array_add (arg_array, "-m=quick"); - - if (!__nmtst_internal.test_tap_log) { - for (i = 0; p_tests && i < p_tests->len; i++) { - g_ptr_array_add (arg_array, "-p"); - g_ptr_array_add (arg_array, p_tests->pdata[i]); - } - for (i = 0; s_tests && i < s_tests->len; i++) { - g_ptr_array_add (arg_array, "-s"); - g_ptr_array_add (arg_array, s_tests->pdata[i]); - } - } else if (p_tests || s_tests) { - char *msg = g_strdup_printf (">>> nmtst: ignore -p and -s options for tap-tests"); - - g_array_append_val (debug_messages, msg); - } - - g_ptr_array_add (arg_array, NULL); - - arg_array_n = arg_array->len - 1; - arg_array_c = (char **) g_ptr_array_free (arg_array, FALSE); - - g_test_init (&arg_array_n, &arg_array_c, NULL); - - if (*argc > 1) { - /* collaps argc/argv by removing the arguments detected - * by g_test_init(). */ - for (i = 1, j = 1; i < *argc; i++) { - if ((*argv)[i] == arg_array_c[j]) - j++; - else - (*argv)[i] = NULL; - } - for (i = 1, j = 1; i < *argc; i++) { - if ((*argv)[i]) { - (*argv)[j++] = (*argv)[i]; - if (i >= j) - (*argv)[i] = NULL; - } - } - *argc = j; - } - - /* we must "leak" the test paths because they are not cloned by g_test_init(). */ - if (!__nmtst_internal.test_tap_log) { - if (p_tests) { - p_tests_x = (char **) g_ptr_array_free (p_tests, FALSE); - p_tests = NULL; - } - if (s_tests) { - s_tests_x = (char **) g_ptr_array_free (s_tests, FALSE); - s_tests = NULL; - } - } - - NM_PRAGMA_WARNING_REENABLE - } - - if (test_quick_set) - __nmtst_internal.test_quick = test_quick; - else if (test_quick_argv) - __nmtst_internal.test_quick = g_test_quick (); - else { + if (argc) + __nmtst_internal.orig_argv = g_strdupv(*argv); + + __nmtst_internal.assert_logging = !!assert_logging; + + nm_g_type_init(); + + is_debug = g_test_verbose(); + + nmtst_debug = g_getenv("NMTST_DEBUG"); + if (nmtst_debug) { + char **d_argv, **i_argv, *nmtst_debug_copy; + + /* By setting then NMTST_DEBUG variable, @is_debug is set automatically. + * This can be reverted with no-debug (on command line or environment variable). */ + is_debug = TRUE; + + nmtst_debug_copy = g_strdup(nmtst_debug); + d_argv = nmtst_str_split(nmtst_debug_copy, ",; \t\r\n"); + + for (i_argv = d_argv; *i_argv; i_argv++) { + const char *debug = *i_argv; + + if (!g_ascii_strcasecmp(debug, "debug")) + is_debug = TRUE; + else if (!g_ascii_strcasecmp(debug, "no-debug")) { + /* when specifying the NMTST_DEBUG variable, we set is_debug to true. Use this flag to disable this + * (e.g. for only setting the log-level, but not is_debug). */ + is_debug = FALSE; + } else if (!g_ascii_strncasecmp(debug, "log-level=", strlen("log-level="))) { + g_free(c_log_level); + log_level = c_log_level = g_strdup(&debug[strlen("log-level=")]); + } else if (!g_ascii_strcasecmp(debug, "D")) { + /* shorthand for "log-level=TRACE,no-expect-message" */ + g_free(c_log_level); + log_level = c_log_level = g_strdup("TRACE"); + no_expect_message = TRUE; + } else if (!g_ascii_strcasecmp(debug, "TRACE")) { + g_free(c_log_level); + log_level = c_log_level = g_strdup("TRACE"); + } else if (!g_ascii_strncasecmp(debug, "log-domains=", strlen("log-domains="))) { + g_free(c_log_domains); + log_domains = c_log_domains = g_strdup(&debug[strlen("log-domains=")]); + } else if (!g_ascii_strncasecmp(debug, "sudo-cmd=", strlen("sudo-cmd="))) { + g_free(sudo_cmd); + sudo_cmd = g_strdup(&debug[strlen("sudo-cmd=")]); + } else if (!g_ascii_strcasecmp(debug, "no-expect-message")) { + no_expect_message = TRUE; + } else if (!g_ascii_strncasecmp(debug, "p=", strlen("p="))) { + if (!p_tests) + p_tests = g_ptr_array_new_with_free_func(g_free); + g_ptr_array_add(p_tests, g_strdup(&debug[strlen("p=")])); + } else if (!g_ascii_strncasecmp(debug, "s=", strlen("s="))) { + if (!s_tests) + s_tests = g_ptr_array_new_with_free_func(g_free); + g_ptr_array_add(s_tests, g_strdup(&debug[strlen("s=")])); + } else if (!g_ascii_strcasecmp(debug, "slow") + || !g_ascii_strcasecmp(debug, "thorough")) { + test_quick = FALSE; + test_quick_set = TRUE; + } else if (!g_ascii_strcasecmp(debug, "quick")) { + test_quick = TRUE; + test_quick_set = TRUE; + } else { + char *msg = + g_strdup_printf(">>> nmtst: ignore unrecognized NMTST_DEBUG option \"%s\"", + debug); + + g_array_append_val(debug_messages, msg); + } + } + + g_free(d_argv); + g_free(nmtst_debug_copy); + } + + if (__nmtst_internal.orig_argv) { + char **a = __nmtst_internal.orig_argv; + + for (; *a; a++) { + if (!g_ascii_strcasecmp(*a, "--debug")) + is_debug = TRUE; + else if (!g_ascii_strcasecmp(*a, "--no-debug")) + is_debug = FALSE; + else if (!strcmp(*a, "-m=slow") || !strcmp(*a, "-m=thorough") || !strcmp(*a, "-m=quick") + || (!strcmp(*a, "-m") && *(a + 1) + && (!strcmp(*(a + 1), "quick") || !strcmp(*(a + 1), "slow") + || !strcmp(*(a + 1), "thorough")))) + test_quick_argv = TRUE; + else if (strcmp(*a, "--tap") == 0) + __nmtst_internal.test_tap_log = TRUE; + } + } + + if (!argc || g_test_initialized()) { + if (p_tests || s_tests) { + char *msg = g_strdup_printf( + ">>> nmtst: ignore -p and -s options for test which calls g_test_init() itself"); + + g_array_append_val(debug_messages, msg); + } + } else { + /* We're intentionally assigning a value to static variables + * s_tests_x and p_tests_x without using it afterwards, just + * so that valgrind doesn't complain about the leak. */ + NM_PRAGMA_WARNING_DISABLE("-Wunused-but-set-variable") + + /* g_test_init() is a variadic function, so we cannot pass it + * (variadic) arguments. If you need to pass additional parameters, + * call nmtst_init() with argc==NULL and call g_test_init() yourself. */ + + /* g_test_init() sets g_log_set_always_fatal() for G_LOG_LEVEL_WARNING + * and G_LOG_LEVEL_CRITICAL. So, beware that the test will fail if you + * have any WARN or ERR log messages -- unless you g_test_expect_message(). */ + GPtrArray * arg_array = g_ptr_array_new(); + gs_free char **arg_array_c = NULL; + int arg_array_n, j; + static char ** s_tests_x, **p_tests_x; + + if (*argc) { + for (i = 0; i < *argc; i++) + g_ptr_array_add(arg_array, (*argv)[i]); + } else + g_ptr_array_add(arg_array, "./test"); + + if (test_quick_set && !test_quick_argv) + g_ptr_array_add(arg_array, "-m=quick"); + + if (!__nmtst_internal.test_tap_log) { + for (i = 0; p_tests && i < p_tests->len; i++) { + g_ptr_array_add(arg_array, "-p"); + g_ptr_array_add(arg_array, p_tests->pdata[i]); + } + for (i = 0; s_tests && i < s_tests->len; i++) { + g_ptr_array_add(arg_array, "-s"); + g_ptr_array_add(arg_array, s_tests->pdata[i]); + } + } else if (p_tests || s_tests) { + char *msg = g_strdup_printf(">>> nmtst: ignore -p and -s options for tap-tests"); + + g_array_append_val(debug_messages, msg); + } + + g_ptr_array_add(arg_array, NULL); + + arg_array_n = arg_array->len - 1; + arg_array_c = (char **) g_ptr_array_free(arg_array, FALSE); + + g_test_init(&arg_array_n, &arg_array_c, NULL); + + if (*argc > 1) { + /* collaps argc/argv by removing the arguments detected + * by g_test_init(). */ + for (i = 1, j = 1; i < *argc; i++) { + if ((*argv)[i] == arg_array_c[j]) + j++; + else + (*argv)[i] = NULL; + } + for (i = 1, j = 1; i < *argc; i++) { + if ((*argv)[i]) { + (*argv)[j++] = (*argv)[i]; + if (i >= j) + (*argv)[i] = NULL; + } + } + *argc = j; + } + + /* we must "leak" the test paths because they are not cloned by g_test_init(). */ + if (!__nmtst_internal.test_tap_log) { + if (p_tests) { + p_tests_x = (char **) g_ptr_array_free(p_tests, FALSE); + p_tests = NULL; + } + if (s_tests) { + s_tests_x = (char **) g_ptr_array_free(s_tests, FALSE); + s_tests = NULL; + } + } + + NM_PRAGMA_WARNING_REENABLE + } + + if (test_quick_set) + __nmtst_internal.test_quick = test_quick; + else if (test_quick_argv) + __nmtst_internal.test_quick = g_test_quick(); + else { #ifdef NMTST_TEST_QUICK - __nmtst_internal.test_quick = NMTST_TEST_QUICK; + __nmtst_internal.test_quick = NMTST_TEST_QUICK; #else - __nmtst_internal.test_quick = FALSE; + __nmtst_internal.test_quick = FALSE; #endif - } + } - __nmtst_internal.is_debug = is_debug; - __nmtst_internal.rand0 = g_rand_new_with_seed (0); - __nmtst_internal.sudo_cmd = sudo_cmd; - __nmtst_internal.no_expect_message = no_expect_message; + __nmtst_internal.is_debug = is_debug; + __nmtst_internal.rand0 = g_rand_new_with_seed(0); + __nmtst_internal.sudo_cmd = sudo_cmd; + __nmtst_internal.no_expect_message = no_expect_message; - if (!log_level && log_domains) { - /* if the log level is not specified (but the domain is), we assume - * the caller wants to set it depending on is_debug */ - log_level = is_debug ? "DEBUG" : "WARN"; - } + if (!log_level && log_domains) { + /* if the log level is not specified (but the domain is), we assume + * the caller wants to set it depending on is_debug */ + log_level = is_debug ? "DEBUG" : "WARN"; + } - if (!__nmtst_internal.assert_logging) { - gboolean success = TRUE; + if (!__nmtst_internal.assert_logging) { + gboolean success = TRUE; #ifdef _NMTST_INSIDE_CORE - success = nm_logging_setup (log_level, log_domains, NULL, NULL); - *out_set_logging = TRUE; + success = nm_logging_setup(log_level, log_domains, NULL, NULL); + *out_set_logging = TRUE; #endif - g_assert (success); -#if GLIB_CHECK_VERSION(2,34,0) - if (__nmtst_internal.no_expect_message) - g_log_set_always_fatal (G_LOG_FATAL_MASK); + g_assert(success); +#if GLIB_CHECK_VERSION(2, 34, 0) + if (__nmtst_internal.no_expect_message) + g_log_set_always_fatal(G_LOG_FATAL_MASK); #else - /* g_test_expect_message() is a NOP, so allow any messages */ - g_log_set_always_fatal (G_LOG_FATAL_MASK); + /* g_test_expect_message() is a NOP, so allow any messages */ + g_log_set_always_fatal(G_LOG_FATAL_MASK); #endif - } else if (__nmtst_internal.no_expect_message) { - /* We have a test that would be assert_logging, but the user specified no_expect_message. - * This transforms g_test_expect_message() into a NOP, but we also have to relax - * g_log_set_always_fatal(), which was set by g_test_init(). */ - g_log_set_always_fatal (G_LOG_FATAL_MASK); + } else if (__nmtst_internal.no_expect_message) { + /* We have a test that would be assert_logging, but the user specified no_expect_message. + * This transforms g_test_expect_message() into a NOP, but we also have to relax + * g_log_set_always_fatal(), which was set by g_test_init(). */ + g_log_set_always_fatal(G_LOG_FATAL_MASK); #ifdef _NMTST_INSIDE_CORE - if (c_log_domains || c_log_level) { - /* Normally, tests with assert_logging do not overwrite the logging level/domains because - * the logging statements are part of the assertions. But if the test is run with - * no-expect-message *and* the logging is set explicitly via environment variables, - * we still reset the logging. */ - gboolean success; - - success = nm_logging_setup (log_level, log_domains, NULL, NULL); - *out_set_logging = TRUE; - g_assert (success); - } + if (c_log_domains || c_log_level) { + /* Normally, tests with assert_logging do not overwrite the logging level/domains because + * the logging statements are part of the assertions. But if the test is run with + * no-expect-message *and* the logging is set explicitly via environment variables, + * we still reset the logging. */ + gboolean success; + + success = nm_logging_setup(log_level, log_domains, NULL, NULL); + *out_set_logging = TRUE; + g_assert(success); + } #endif - } else { -#if GLIB_CHECK_VERSION(2,34,0) - /* We were called not to set logging levels. This means, that the user - * expects to assert against (all) messages. - * Any uncaught message on >debug level is fatal. */ - g_log_set_always_fatal (G_LOG_LEVEL_MASK & ~G_LOG_LEVEL_DEBUG); + } else { +#if GLIB_CHECK_VERSION(2, 34, 0) + /* We were called not to set logging levels. This means, that the user + * expects to assert against (all) messages. + * Any uncaught message on >debug level is fatal. */ + g_log_set_always_fatal(G_LOG_LEVEL_MASK & ~G_LOG_LEVEL_DEBUG); #else - /* g_test_expect_message() is a NOP, so allow any messages */ - g_log_set_always_fatal (G_LOG_FATAL_MASK); + /* g_test_expect_message() is a NOP, so allow any messages */ + g_log_set_always_fatal(G_LOG_FATAL_MASK); #endif - } - - if ((!__nmtst_internal.assert_logging || (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message)) && - (is_debug || (c_log_level && (!g_ascii_strcasecmp (c_log_level, "DEBUG") || !g_ascii_strcasecmp (c_log_level, "TRACE")))) && - !g_getenv ("G_MESSAGES_DEBUG")) - { - /* if we are @is_debug or @log_level=="DEBUG" and - * G_MESSAGES_DEBUG is unset, we set G_MESSAGES_DEBUG=all. - * To disable this default behaviour, set G_MESSAGES_DEBUG='' */ - - /* Note that g_setenv is not thread safe, but you should anyway call - * nmtst_init() at the very start. */ - g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); - } - - /* Delay messages until we setup logging. */ - for (i = 0; i < debug_messages->len; i++) - __NMTST_LOG (g_message, "%s", g_array_index (debug_messages, const char *, i)); - - g_strfreev ((char **) g_array_free (debug_messages, FALSE)); - g_free (c_log_level); - g_free (c_log_domains); + } + + if ((!__nmtst_internal.assert_logging + || (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message)) + && (is_debug + || (c_log_level + && (!g_ascii_strcasecmp(c_log_level, "DEBUG") + || !g_ascii_strcasecmp(c_log_level, "TRACE")))) + && !g_getenv("G_MESSAGES_DEBUG")) { + /* if we are @is_debug or @log_level=="DEBUG" and + * G_MESSAGES_DEBUG is unset, we set G_MESSAGES_DEBUG=all. + * To disable this default behaviour, set G_MESSAGES_DEBUG='' */ + + /* Note that g_setenv is not thread safe, but you should anyway call + * nmtst_init() at the very start. */ + g_setenv("G_MESSAGES_DEBUG", "all", TRUE); + } + + /* Delay messages until we setup logging. */ + for (i = 0; i < debug_messages->len; i++) + __NMTST_LOG(g_message, "%s", g_array_index(debug_messages, const char *, i)); + + g_strfreev((char **) g_array_free(debug_messages, FALSE)); + g_free(c_log_level); + g_free(c_log_domains); #ifdef __NETWORKMANAGER_UTILS_H__ - /* ensure that monotonic timestamp is called (because it initially logs a line) */ - nm_utils_get_monotonic_timestamp_sec (); + /* ensure that monotonic timestamp is called (because it initially logs a line) */ + nm_utils_get_monotonic_timestamp_sec(); #endif #ifdef NM_UTILS_H - { - gs_free_error GError *error = NULL; + { + gs_free_error GError *error = NULL; - if (!nm_utils_init (&error)) - g_assert_not_reached (); - g_assert_no_error (error); - } + if (!nm_utils_init(&error)) + g_assert_not_reached(); + g_assert_no_error(error); + } #endif - g_log_set_handler (G_LOG_DOMAIN, - G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, - _nmtst_log_handler, - NULL); + g_log_set_handler(G_LOG_DOMAIN, + G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, + _nmtst_log_handler, + NULL); } #ifndef _NMTST_INSIDE_CORE static inline void -nmtst_init (int *argc, char ***argv, gboolean assert_logging) +nmtst_init(int *argc, char ***argv, gboolean assert_logging) { - __nmtst_init (argc, argv, assert_logging, NULL, NULL, NULL); + __nmtst_init(argc, argv, assert_logging, NULL, NULL, NULL); } #endif static inline gboolean -nmtst_is_debug (void) +nmtst_is_debug(void) { - g_assert (nmtst_initialized ()); - return __nmtst_internal.is_debug; + g_assert(nmtst_initialized()); + return __nmtst_internal.is_debug; } static inline gboolean -nmtst_test_quick (void) -{ - g_assert (nmtst_initialized ()); - return __nmtst_internal.test_quick; -} - -#if GLIB_CHECK_VERSION(2,34,0) -#undef g_test_expect_message -#define g_test_expect_message(...) \ - G_STMT_START { \ - g_assert (nmtst_initialized ()); \ - if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) { \ - g_debug ("nmtst: assert-logging: g_test_expect_message %s", G_STRINGIFY ((__VA_ARGS__))); \ - } else { \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - g_test_expect_message (__VA_ARGS__); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - } \ - } G_STMT_END -#undef g_test_assert_expected_messages_internal -#define g_test_assert_expected_messages_internal(domain, file, line, func) \ - G_STMT_START { \ - const char *_domain = (domain); \ - const char *_file = (file); \ - const char *_func = (func); \ - int _line = (line); \ - \ - if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) \ - g_debug ("nmtst: assert-logging: g_test_assert_expected_messages(%s, %s:%d, %s)", _domain?:"", _file?:"", _line, _func?:""); \ - \ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ - g_test_assert_expected_messages_internal (_domain, _file, _line, _func); \ - G_GNUC_END_IGNORE_DEPRECATIONS \ - } G_STMT_END +nmtst_test_quick(void) +{ + g_assert(nmtst_initialized()); + return __nmtst_internal.test_quick; +} + +#if GLIB_CHECK_VERSION(2, 34, 0) + #undef g_test_expect_message + #define g_test_expect_message(...) \ + G_STMT_START \ + { \ + g_assert(nmtst_initialized()); \ + if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) { \ + g_debug("nmtst: assert-logging: g_test_expect_message %s", \ + G_STRINGIFY((__VA_ARGS__))); \ + } else { \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_test_expect_message(__VA_ARGS__); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + } \ + } \ + G_STMT_END + #undef g_test_assert_expected_messages_internal + #define g_test_assert_expected_messages_internal(domain, file, line, func) \ + G_STMT_START \ + { \ + const char *_domain = (domain); \ + const char *_file = (file); \ + const char *_func = (func); \ + int _line = (line); \ + \ + if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) \ + g_debug("nmtst: assert-logging: g_test_assert_expected_messages(%s, %s:%d, %s)", \ + _domain ?: "", \ + _file ?: "", \ + _line, \ + _func ?: ""); \ + \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_test_assert_expected_messages_internal(_domain, _file, _line, _func); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + } \ + G_STMT_END #endif -#define NMTST_EXPECT(domain, level, msg) g_test_expect_message (domain, level, msg) +#define NMTST_EXPECT(domain, level, msg) g_test_expect_message(domain, level, msg) -#define NMTST_EXPECT_LIBNM(level, msg) NMTST_EXPECT ("libnm", level, msg) +#define NMTST_EXPECT_LIBNM(level, msg) NMTST_EXPECT("libnm", level, msg) -#define NMTST_EXPECT_LIBNM_WARNING(msg) NMTST_EXPECT_LIBNM (G_LOG_LEVEL_WARNING, msg) -#define NMTST_EXPECT_LIBNM_CRITICAL(msg) NMTST_EXPECT_LIBNM (G_LOG_LEVEL_CRITICAL, msg) +#define NMTST_EXPECT_LIBNM_WARNING(msg) NMTST_EXPECT_LIBNM(G_LOG_LEVEL_WARNING, msg) +#define NMTST_EXPECT_LIBNM_CRITICAL(msg) NMTST_EXPECT_LIBNM(G_LOG_LEVEL_CRITICAL, msg) /*****************************************************************************/ typedef struct _NmtstTestData NmtstTestData; -typedef void (*NmtstTestHandler) (const NmtstTestData *test_data); +typedef void (*NmtstTestHandler)(const NmtstTestData *test_data); struct _NmtstTestData { - union { - const char *testpath; - char *_testpath; - }; - gsize n_args; - gpointer *args; - NmtstTestHandler _func_setup; - GTestDataFunc _func_test; - NmtstTestHandler _func_teardown; + union { + const char *testpath; + char * _testpath; + }; + gsize n_args; + gpointer * args; + NmtstTestHandler _func_setup; + GTestDataFunc _func_test; + NmtstTestHandler _func_teardown; }; static inline void -_nmtst_test_data_unpack (const NmtstTestData *test_data, gsize n_args, ...) +_nmtst_test_data_unpack(const NmtstTestData *test_data, gsize n_args, ...) { - gsize i; - va_list ap; - gpointer *p; + gsize i; + va_list ap; + gpointer *p; - g_assert (test_data); - g_assert_cmpint (n_args, ==, test_data->n_args); + g_assert(test_data); + g_assert_cmpint(n_args, ==, test_data->n_args); - va_start (ap, n_args); - for (i = 0; i < n_args; i++) { - p = va_arg (ap, gpointer *); + va_start(ap, n_args); + for (i = 0; i < n_args; i++) { + p = va_arg(ap, gpointer *); - if (p) - *p = test_data->args[i]; - } - va_end (ap); + if (p) + *p = test_data->args[i]; + } + va_end(ap); } -#define nmtst_test_data_unpack(test_data, ...) _nmtst_test_data_unpack(test_data, NM_NARG (__VA_ARGS__), ##__VA_ARGS__) +#define nmtst_test_data_unpack(test_data, ...) \ + _nmtst_test_data_unpack(test_data, NM_NARG(__VA_ARGS__), ##__VA_ARGS__) static inline void -_nmtst_test_data_free (gpointer data) +_nmtst_test_data_free(gpointer data) { - NmtstTestData *test_data = data; + NmtstTestData *test_data = data; - g_assert (test_data); + g_assert(test_data); - g_free (test_data->_testpath); - g_free (test_data); + g_free(test_data->_testpath); + g_free(test_data); } static inline void -_nmtst_test_run (gconstpointer data) +_nmtst_test_run(gconstpointer data) { - const NmtstTestData *test_data = data; + const NmtstTestData *test_data = data; - if (test_data->_func_setup) - test_data->_func_setup (test_data); + if (test_data->_func_setup) + test_data->_func_setup(test_data); - test_data->_func_test (test_data); + test_data->_func_test(test_data); - if (test_data->_func_teardown) - test_data->_func_teardown (test_data); + if (test_data->_func_teardown) + test_data->_func_teardown(test_data); } static inline void -_nmtst_add_test_func_full (const char *testpath, GTestDataFunc func_test, NmtstTestHandler func_setup, NmtstTestHandler func_teardown, gsize n_args, ...) -{ - gsize i; - NmtstTestData *data; - va_list ap; - - g_assert (testpath && testpath[0]); - g_assert (func_test); - - data = g_malloc0 (sizeof (NmtstTestData) + (sizeof (gpointer) * (n_args + 1))); - - data->_testpath = g_strdup (testpath); - data->_func_test = func_test; - data->_func_setup = func_setup; - data->_func_teardown = func_teardown; - data->n_args = n_args; - data->args = (gpointer) &data[1]; - va_start (ap, n_args); - for (i = 0; i < n_args; i++) - data->args[i] = va_arg (ap, gpointer); - data->args[i] = NULL; - va_end (ap); - - g_test_add_data_func_full (testpath, - data, - _nmtst_test_run, - _nmtst_test_data_free); -} -#define nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, ...) _nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, NM_NARG (__VA_ARGS__), ##__VA_ARGS__) -#define nmtst_add_test_func(testpath, func_test, ...) nmtst_add_test_func_full(testpath, func_test, NULL, NULL, ##__VA_ARGS__) +_nmtst_add_test_func_full(const char * testpath, + GTestDataFunc func_test, + NmtstTestHandler func_setup, + NmtstTestHandler func_teardown, + gsize n_args, + ...) +{ + gsize i; + NmtstTestData *data; + va_list ap; + + g_assert(testpath && testpath[0]); + g_assert(func_test); + + data = g_malloc0(sizeof(NmtstTestData) + (sizeof(gpointer) * (n_args + 1))); + + data->_testpath = g_strdup(testpath); + data->_func_test = func_test; + data->_func_setup = func_setup; + data->_func_teardown = func_teardown; + data->n_args = n_args; + data->args = (gpointer) &data[1]; + va_start(ap, n_args); + for (i = 0; i < n_args; i++) + data->args[i] = va_arg(ap, gpointer); + data->args[i] = NULL; + va_end(ap); + + g_test_add_data_func_full(testpath, data, _nmtst_test_run, _nmtst_test_data_free); +} +#define nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, ...) \ + _nmtst_add_test_func_full(testpath, \ + func_test, \ + func_setup, \ + func_teardown, \ + NM_NARG(__VA_ARGS__), \ + ##__VA_ARGS__) +#define nmtst_add_test_func(testpath, func_test, ...) \ + nmtst_add_test_func_full(testpath, func_test, NULL, NULL, ##__VA_ARGS__) /*****************************************************************************/ static inline GRand * -nmtst_get_rand0 (void) +nmtst_get_rand0(void) { - g_assert (nmtst_initialized ()); - return __nmtst_internal.rand0; + g_assert(nmtst_initialized()); + return __nmtst_internal.rand0; } static inline GRand * -nmtst_get_rand (void) +nmtst_get_rand(void) { - g_assert (nmtst_initialized ()); + g_assert(nmtst_initialized()); - if (G_UNLIKELY (!__nmtst_internal.rand)) { - guint32 seed; - const char *str = g_getenv ("NMTST_SEED_RAND"); + if (G_UNLIKELY(!__nmtst_internal.rand)) { + guint32 seed; + const char *str = g_getenv("NMTST_SEED_RAND"); - if (!str) { - /* No NMTST_SEED_RAND. Pick a stable one. */ - seed = 0; - __nmtst_internal.rand = g_rand_new_with_seed (seed); - } else if (str[0] == '\0') { - /* NMTST_SEED_RAND is set but empty. Pick a random one. */ - __nmtst_internal.rand = g_rand_new (); + if (!str) { + /* No NMTST_SEED_RAND. Pick a stable one. */ + seed = 0; + __nmtst_internal.rand = g_rand_new_with_seed(seed); + } else if (str[0] == '\0') { + /* NMTST_SEED_RAND is set but empty. Pick a random one. */ + __nmtst_internal.rand = g_rand_new(); - seed = g_rand_int (__nmtst_internal.rand); - g_rand_set_seed (__nmtst_internal.rand, seed); - } else { - /* NMTST_SEED_RAND is set. Use it as a seed. */ - char *s; - gint64 i; + seed = g_rand_int(__nmtst_internal.rand); + g_rand_set_seed(__nmtst_internal.rand, seed); + } else { + /* NMTST_SEED_RAND is set. Use it as a seed. */ + char * s; + gint64 i; - i = g_ascii_strtoll (str, &s, 0); - g_assert (s[0] == '\0' && i >= 0 && i < G_MAXUINT32); + i = g_ascii_strtoll(str, &s, 0); + g_assert(s[0] == '\0' && i >= 0 && i < G_MAXUINT32); - seed = i; - __nmtst_internal.rand = g_rand_new_with_seed (seed); - } - __nmtst_internal.rand_seed = seed; + seed = i; + __nmtst_internal.rand = g_rand_new_with_seed(seed); + } + __nmtst_internal.rand_seed = seed; - g_print ("\nnmtst: initialize nmtst_get_rand() with NMTST_SEED_RAND=%u\n", seed); - } - return __nmtst_internal.rand; + g_print("\nnmtst: initialize nmtst_get_rand() with NMTST_SEED_RAND=%u\n", seed); + } + return __nmtst_internal.rand; } static inline guint32 -nmtst_get_rand_uint32 (void) +nmtst_get_rand_uint32(void) { - return g_rand_int (nmtst_get_rand ()); + return g_rand_int(nmtst_get_rand()); } static inline guint64 -nmtst_get_rand_uint64 (void) +nmtst_get_rand_uint64(void) { - GRand *rand = nmtst_get_rand (); + GRand *rand = nmtst_get_rand(); - return (((guint64) g_rand_int (rand)) ) - | (((guint64) g_rand_int (rand)) << 32); + return (((guint64) g_rand_int(rand))) | (((guint64) g_rand_int(rand)) << 32); } static inline guint -nmtst_get_rand_uint (void) +nmtst_get_rand_uint(void) { - G_STATIC_ASSERT_EXPR (sizeof (guint32) == sizeof (guint)); - return nmtst_get_rand_uint32 (); + G_STATIC_ASSERT_EXPR(sizeof(guint32) == sizeof(guint)); + return nmtst_get_rand_uint32(); } static inline gsize -nmtst_get_rand_size (void) +nmtst_get_rand_size(void) { - G_STATIC_ASSERT_EXPR ( sizeof (gsize) == sizeof (guint32) - || sizeof (gsize) == sizeof (guint64)); - if (sizeof (gsize) == sizeof (guint32)) - return nmtst_get_rand_uint32 (); - return nmtst_get_rand_uint64 (); + G_STATIC_ASSERT_EXPR(sizeof(gsize) == sizeof(guint32) || sizeof(gsize) == sizeof(guint64)); + if (sizeof(gsize) == sizeof(guint32)) + return nmtst_get_rand_uint32(); + return nmtst_get_rand_uint64(); } static inline gboolean -nmtst_get_rand_bool (void) +nmtst_get_rand_bool(void) { - return nmtst_get_rand_uint32 () % 2; + return nmtst_get_rand_uint32() % 2; } static inline gpointer -nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length) +nmtst_rand_buf(GRand *rand, gpointer buffer, gsize buffer_length) { - guint32 v; - guint8 *b = buffer; + guint32 v; + guint8 *b = buffer; - if (!buffer_length) - return buffer; + if (!buffer_length) + return buffer; - g_assert (buffer); + g_assert(buffer); - if (!rand) - rand = nmtst_get_rand (); + if (!rand) + rand = nmtst_get_rand(); - for (; buffer_length >= sizeof (guint32); buffer_length -= sizeof (guint32), b += sizeof (guint32)) { - v = g_rand_int (rand); - memcpy (b, &v, sizeof (guint32)); - } - if (buffer_length > 0) { - v = g_rand_int (rand); - do { - *(b++) = v & 0xFF; - v >>= 8; - } while (--buffer_length > 0); - } - return buffer; + for (; buffer_length >= sizeof(guint32); + buffer_length -= sizeof(guint32), b += sizeof(guint32)) { + v = g_rand_int(rand); + memcpy(b, &v, sizeof(guint32)); + } + if (buffer_length > 0) { + v = g_rand_int(rand); + do { + *(b++) = v & 0xFF; + v >>= 8; + } while (--buffer_length > 0); + } + return buffer; } -#define _nmtst_rand_select(uniq, v0, ...) \ - ({ \ - typeof (v0) NM_UNIQ_T (UNIQ, uniq)[1 + NM_NARG (__VA_ARGS__)] = { (v0), __VA_ARGS__ }; \ - \ - NM_UNIQ_T (UNIQ, uniq)[nmtst_get_rand_uint32 () % G_N_ELEMENTS (NM_UNIQ_T (UNIQ, uniq))]; \ - }) +#define _nmtst_rand_select(uniq, v0, ...) \ + ({ \ + typeof(v0) NM_UNIQ_T(UNIQ, uniq)[1 + NM_NARG(__VA_ARGS__)] = {(v0), __VA_ARGS__}; \ + \ + NM_UNIQ_T(UNIQ, uniq)[nmtst_get_rand_uint32() % G_N_ELEMENTS(NM_UNIQ_T(UNIQ, uniq))]; \ + }) -#define nmtst_rand_select(...) \ - _nmtst_rand_select (NM_UNIQ, __VA_ARGS__) +#define nmtst_rand_select(...) _nmtst_rand_select(NM_UNIQ, __VA_ARGS__) static inline void * -nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt) +nmtst_rand_perm(GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt) { - gsize i, j; - char *p_, *pj; - char *bu; + gsize i, j; + char *p_, *pj; + char *bu; - g_assert (dst); - g_assert (elmt_size > 0); - g_assert (n_elmt < G_MAXINT32); + g_assert(dst); + g_assert(elmt_size > 0); + g_assert(n_elmt < G_MAXINT32); - if (n_elmt == 0) - return dst; + if (n_elmt == 0) + return dst; - if (src && dst != src) - memcpy (dst, src, elmt_size * n_elmt); + if (src && dst != src) + memcpy(dst, src, elmt_size * n_elmt); - if (!rand) - rand = nmtst_get_rand (); + if (!rand) + rand = nmtst_get_rand(); - bu = g_slice_alloc (elmt_size); + bu = g_slice_alloc(elmt_size); - p_ = dst; - for (i = n_elmt; i > 1; i--) { - j = g_rand_int_range (rand, 0, i); + p_ = dst; + for (i = n_elmt; i > 1; i--) { + j = g_rand_int_range(rand, 0, i); - if (j != 0) { - pj = &p_[j * elmt_size]; + if (j != 0) { + pj = &p_[j * elmt_size]; - /* swap */ - memcpy (bu, p_, elmt_size); - memcpy (p_, pj, elmt_size); - memcpy (pj, bu, elmt_size); - } - p_ += elmt_size; - } + /* swap */ + memcpy(bu, p_, elmt_size); + memcpy(p_, pj, elmt_size); + memcpy(pj, bu, elmt_size); + } + p_ += elmt_size; + } - g_slice_free1 (elmt_size, bu); - return dst; + g_slice_free1(elmt_size, bu); + return dst; } static inline GSList * -nmtst_rand_perm_gslist (GRand *rand, GSList *list) +nmtst_rand_perm_gslist(GRand *rand, GSList *list) { - GSList *result; - guint l; + GSList *result; + guint l; - if (!rand) - rand = nmtst_get_rand (); + if (!rand) + rand = nmtst_get_rand(); - /* no need for an efficient implementation :) */ + /* no need for an efficient implementation :) */ - result = 0; - for (l = g_slist_length (list); l > 0; l--) { - GSList *tmp; + result = 0; + for (l = g_slist_length(list); l > 0; l--) { + GSList *tmp; - tmp = g_slist_nth (list, g_rand_int (rand) % l); - g_assert (tmp); + tmp = g_slist_nth(list, g_rand_int(rand) % l); + g_assert(tmp); - list = g_slist_remove_link (list, tmp); - result = g_slist_concat (tmp, result); - } - g_assert (!list); - return result; + list = g_slist_remove_link(list, tmp); + result = g_slist_concat(tmp, result); + } + g_assert(!list); + return result; +} + +static inline void +nmtst_stable_rand(guint64 seed, gpointer buf, gsize len) +{ + const guint64 C = 1442695040888963407llu; + const guint64 A = 6364136223846793005llu; + guint8 * b; + union { + guint8 a[sizeof(guint64)]; + guint64 n; + } n; + + /* We want a stable random generator that is in our control and does not + * depend on glibc/glib versions. + * Use a linear congruential generator (x[n+1] = (A * x[n] + C) % M) + * https://en.wikipedia.org/wiki/Linear_congruential_generator + * + * We choose (Knuth’s LCG MMIX) + * A = 6364136223846793005llu + * C = 1442695040888963407llu + * M = 2^64 + */ + + g_assert(len == 0 || buf); + + n.n = seed; + b = buf; + for (; len > 0; len--, b++) { + n.n = (A * n.n + C); + + /* let's combine the 64 bits randomness in one byte. By xor-ing, it's + * also independent of endianness. */ + b[0] = n.a[0] ^ n.a[1] ^ n.a[2] ^ n.a[3] ^ n.a[4] ^ n.a[5] ^ n.a[6] ^ n.a[7]; + } } /*****************************************************************************/ @@ -995,610 +1069,640 @@ nmtst_rand_perm_gslist (GRand *rand, GSList *list) * be used when we generate random input for unit tests. */ static inline guint -nmtst_get_rand_word_length (GRand *rand) -{ - guint n; - - if (!rand) - rand = nmtst_get_rand (); - - n = 0; - while (TRUE) { - guint32 rnd = g_rand_int (rand); - guint probability; - - /* The following python code implements a random sample with this - * distribution: - * - * def random_histogram(n_tries, scale = None): - * def probability(n_tok): - * import math - * return max(2, math.floor(100 / (2*(n_tok+1)))) - * def n_tokens(): - * import random - * n_tok = 0 - * while True: - * if random.randint(0, 0xFFFFFFFF) % probability(n_tok) == 0: - * return n_tok - * n_tok += 1 - * hist = [] - * i = 0; - * while i < n_tries: - * n_tok = n_tokens() - * while n_tok >= len(hist): - * hist.append(0) - * hist[n_tok] = hist[n_tok] + 1 - * i += 1 - * if scale is not None: - * hist = list([round(x / n_tries * scale) for x in hist]) - * return hist - * - * For example, random_histogram(n_tries = 1000000, scale = 1000) may give - * - * IDX: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] - * SEEN: [20, 39, 59, 73, 80, 91, 92, 90, 91, 73, 73, 54, 55, 36, 24, 16, 16, 8, 4, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0] - * - * which give a sense of the probability with this individual results are returned. - */ - probability = NM_MAX (2u, (100u / (2u * (n + 1u)))); - if ((rnd % probability) == 0) - return n; - n++; - } +nmtst_get_rand_word_length(GRand *rand) +{ + guint n; + + if (!rand) + rand = nmtst_get_rand(); + + n = 0; + while (TRUE) { + guint32 rnd = g_rand_int(rand); + guint probability; + + /* The following python code implements a random sample with this + * distribution: + * + * def random_histogram(n_tries, scale = None): + * def probability(n_tok): + * import math + * return max(2, math.floor(100 / (2*(n_tok+1)))) + * def n_tokens(): + * import random + * n_tok = 0 + * while True: + * if random.randint(0, 0xFFFFFFFF) % probability(n_tok) == 0: + * return n_tok + * n_tok += 1 + * hist = [] + * i = 0; + * while i < n_tries: + * n_tok = n_tokens() + * while n_tok >= len(hist): + * hist.append(0) + * hist[n_tok] = hist[n_tok] + 1 + * i += 1 + * if scale is not None: + * hist = list([round(x / n_tries * scale) for x in hist]) + * return hist + * + * For example, random_histogram(n_tries = 1000000, scale = 1000) may give + * + * IDX: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] + * SEEN: [20, 39, 59, 73, 80, 91, 92, 90, 91, 73, 73, 54, 55, 36, 24, 16, 16, 8, 4, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0] + * + * which give a sense of the probability with this individual results are returned. + */ + probability = NM_MAX(2u, (100u / (2u * (n + 1u)))); + if ((rnd % probability) == 0) + return n; + n++; + } } /*****************************************************************************/ static inline gboolean -nmtst_g_source_assert_not_called (gpointer user_data) +nmtst_g_source_assert_not_called(gpointer user_data) { - g_assert_not_reached (); - return G_SOURCE_CONTINUE; + g_assert_not_reached(); + return G_SOURCE_CONTINUE; } static inline gboolean -nmtst_g_source_set_boolean_true (gpointer user_data) +nmtst_g_source_set_boolean_true(gpointer user_data) { - gboolean *ptr = user_data; + gboolean *ptr = user_data; - g_assert (ptr); - g_assert (!*ptr); - *ptr = TRUE; - return G_SOURCE_CONTINUE; + g_assert(ptr); + g_assert(!*ptr); + *ptr = TRUE; + return G_SOURCE_CONTINUE; } /*****************************************************************************/ static inline gboolean -_nmtst_main_loop_run_timeout (gpointer user_data) +_nmtst_main_loop_run_timeout(gpointer user_data) { - GMainLoop **p_loop = user_data; + GMainLoop **p_loop = user_data; - g_assert (p_loop && *p_loop); - g_main_loop_quit (g_steal_pointer (p_loop)); - return G_SOURCE_REMOVE; + g_assert(p_loop && *p_loop); + g_main_loop_quit(g_steal_pointer(p_loop)); + return G_SOURCE_REMOVE; } static inline gboolean -nmtst_main_loop_run (GMainLoop *loop, guint timeout_msec) +nmtst_main_loop_run(GMainLoop *loop, guint timeout_msec) { - nm_auto_unref_gsource GSource *source = NULL; - GMainLoop *loopx = loop; + nm_auto_unref_gsource GSource *source = NULL; + GMainLoop * loopx = loop; - if (timeout_msec > 0) { - source = g_timeout_source_new (timeout_msec); - g_source_set_callback (source, _nmtst_main_loop_run_timeout, &loopx, NULL); - g_source_attach (source, g_main_loop_get_context (loop)); - } + if (timeout_msec > 0) { + source = g_timeout_source_new(timeout_msec); + g_source_set_callback(source, _nmtst_main_loop_run_timeout, &loopx, NULL); + g_source_attach(source, g_main_loop_get_context(loop)); + } - g_main_loop_run (loop); + g_main_loop_run(loop); - if (source) - g_source_destroy (source); + if (source) + g_source_destroy(source); - /* if the timeout was reached, return FALSE. */ - return loopx != NULL; + /* if the timeout was reached, return FALSE. */ + return loopx != NULL; } static inline void -_nmtst_main_loop_quit_on_notify (GObject *object, GParamSpec *pspec, gpointer user_data) +_nmtst_main_loop_quit_on_notify(GObject *object, GParamSpec *pspec, gpointer user_data) { - GMainLoop *loop = user_data; + GMainLoop *loop = user_data; - g_assert (G_IS_OBJECT (object)); - g_assert (loop); + g_assert(G_IS_OBJECT(object)); + g_assert(loop); - g_main_loop_quit (loop); + g_main_loop_quit(loop); } #define nmtst_main_loop_quit_on_notify ((GCallback) _nmtst_main_loop_quit_on_notify) -#define nmtst_main_context_iterate_until(context, timeout_msec, condition) \ - ({ \ - nm_auto_destroy_and_unref_gsource GSource *_source = NULL; \ - GMainContext *_context = (context); \ - gboolean _had_timeout = FALSE; \ - \ - _source = g_timeout_source_new (timeout_msec); \ - g_source_set_callback (_source, nmtst_g_source_set_boolean_true, &_had_timeout, NULL); \ - g_source_attach (_source, _context); \ - \ - while (TRUE) { \ - if (condition) \ - break; \ - g_main_context_iteration (_context, TRUE); \ - if (_had_timeout) \ - break; \ - } \ - \ - !_had_timeout; \ - }) +#define nmtst_main_context_iterate_until(context, timeout_msec, condition) \ + ({ \ + nm_auto_destroy_and_unref_gsource GSource *_source = NULL; \ + GMainContext * _context = (context); \ + gboolean _had_timeout = FALSE; \ + \ + _source = g_timeout_source_new(timeout_msec); \ + g_source_set_callback(_source, nmtst_g_source_set_boolean_true, &_had_timeout, NULL); \ + g_source_attach(_source, _context); \ + \ + while (TRUE) { \ + if (condition) \ + break; \ + g_main_context_iteration(_context, TRUE); \ + if (_had_timeout) \ + break; \ + } \ + \ + !_had_timeout; \ + }) #define nmtst_main_context_iterate_until_assert(context, timeout_msec, condition) \ - G_STMT_START { \ - if (!nmtst_main_context_iterate_until (context, timeout_msec, condition)) \ - g_assert (FALSE && #condition); \ - } G_STMT_END + G_STMT_START \ + { \ + if (!nmtst_main_context_iterate_until(context, timeout_msec, condition)) \ + g_assert(FALSE &&#condition); \ + } \ + G_STMT_END /*****************************************************************************/ static inline void -nmtst_main_context_assert_no_dispatch (GMainContext *context, - guint timeout_msec) +nmtst_main_context_assert_no_dispatch(GMainContext *context, guint timeout_msec) { - nm_auto_destroy_and_unref_gsource GSource *source = NULL; - gboolean timeout_hit = FALSE; + nm_auto_destroy_and_unref_gsource GSource *source = NULL; + gboolean timeout_hit = FALSE; - source = g_timeout_source_new (timeout_msec); - g_source_set_callback (source, nmtst_g_source_set_boolean_true, &timeout_hit, NULL); - g_source_attach (source, context); + source = g_timeout_source_new(timeout_msec); + g_source_set_callback(source, nmtst_g_source_set_boolean_true, &timeout_hit, NULL); + g_source_attach(source, context); - while (g_main_context_iteration (context, TRUE)) { - if (timeout_hit) - return; - g_assert_not_reached (); - } + while (g_main_context_iteration(context, TRUE)) { + if (timeout_hit) + return; + g_assert_not_reached(); + } } /*****************************************************************************/ typedef struct { - GMainLoop *_main_loop; - union { - GSList *_list; - const void *const is_waiting; - }; + GMainLoop *_main_loop; + union { + GSList * _list; + const void *const is_waiting; + }; } NMTstContextBusyWatcherData; static inline void -_nmtst_context_busy_watcher_add_cb (gpointer data, - GObject *where_the_object_was) +_nmtst_context_busy_watcher_add_cb(gpointer data, GObject *where_the_object_was) { - NMTstContextBusyWatcherData *watcher_data = data; - GSList *l; + NMTstContextBusyWatcherData *watcher_data = data; + GSList * l; - g_assert (watcher_data); + g_assert(watcher_data); - l = g_slist_find (watcher_data->_list, where_the_object_was); - g_assert (l); + l = g_slist_find(watcher_data->_list, where_the_object_was); + g_assert(l); - watcher_data->_list = g_slist_delete_link (watcher_data->_list, l); - if (!watcher_data->_list) - g_main_loop_quit (watcher_data->_main_loop); + watcher_data->_list = g_slist_delete_link(watcher_data->_list, l); + if (!watcher_data->_list) + g_main_loop_quit(watcher_data->_main_loop); } static inline void -nmtst_context_busy_watcher_add (NMTstContextBusyWatcherData *watcher_data, - GObject *object) +nmtst_context_busy_watcher_add(NMTstContextBusyWatcherData *watcher_data, GObject *object) { - g_assert (watcher_data); - g_assert (G_IS_OBJECT (object)); + g_assert(watcher_data); + g_assert(G_IS_OBJECT(object)); - if (!watcher_data->_main_loop) { - watcher_data->_main_loop = g_main_loop_new (g_main_context_get_thread_default (), - FALSE); - g_assert (!watcher_data->_list); - } else { - g_assert ( g_main_loop_get_context (watcher_data->_main_loop) - == (g_main_context_get_thread_default () ?: g_main_context_default ())); - } + if (!watcher_data->_main_loop) { + watcher_data->_main_loop = g_main_loop_new(g_main_context_get_thread_default(), FALSE); + g_assert(!watcher_data->_list); + } else { + g_assert(g_main_loop_get_context(watcher_data->_main_loop) + == (g_main_context_get_thread_default() ?: g_main_context_default())); + } - g_object_weak_ref (object, - _nmtst_context_busy_watcher_add_cb, - watcher_data); - watcher_data->_list = g_slist_prepend (watcher_data->_list, object); + g_object_weak_ref(object, _nmtst_context_busy_watcher_add_cb, watcher_data); + watcher_data->_list = g_slist_prepend(watcher_data->_list, object); } static inline void -nmtst_context_busy_watcher_wait (NMTstContextBusyWatcherData *watcher_data) +nmtst_context_busy_watcher_wait(NMTstContextBusyWatcherData *watcher_data) { - g_assert (watcher_data); + g_assert(watcher_data); - if (!watcher_data->_main_loop) { - g_assert (!watcher_data->_list); - return; - } + if (!watcher_data->_main_loop) { + g_assert(!watcher_data->_list); + return; + } - if (watcher_data->_list) { - if (!nmtst_main_loop_run (watcher_data->_main_loop, 5000)) - g_error ("timeout running mainloop waiting for GObject to destruct"); - } + if (watcher_data->_list) { + if (!nmtst_main_loop_run(watcher_data->_main_loop, 5000)) + g_error("timeout running mainloop waiting for GObject to destruct"); + } - g_assert (!watcher_data->_list); - nm_clear_pointer (&watcher_data->_main_loop, g_main_loop_unref); + g_assert(!watcher_data->_list); + nm_clear_pointer(&watcher_data->_main_loop, g_main_loop_unref); } /*****************************************************************************/ static inline const char * -nmtst_get_sudo_cmd (void) +nmtst_get_sudo_cmd(void) { - g_assert (nmtst_initialized ()); - return __nmtst_internal.sudo_cmd; + g_assert(nmtst_initialized()); + return __nmtst_internal.sudo_cmd; } static inline void -nmtst_reexec_sudo (void) +nmtst_reexec_sudo(void) { - char *str; - char **argv; - int i; - int errsv; + char * str; + char **argv; + int i; + int errsv; - g_assert (nmtst_initialized ()); - g_assert (__nmtst_internal.orig_argv); + g_assert(nmtst_initialized()); + g_assert(__nmtst_internal.orig_argv); - if (!__nmtst_internal.sudo_cmd) - return; + if (!__nmtst_internal.sudo_cmd) + return; - str = g_strjoinv (" ", __nmtst_internal.orig_argv); - __NMTST_LOG (g_message, ">> exec %s %s", __nmtst_internal.sudo_cmd, str); + str = g_strjoinv(" ", __nmtst_internal.orig_argv); + __NMTST_LOG(g_message, ">> exec %s %s", __nmtst_internal.sudo_cmd, str); - argv = g_new0 (char *, 1 + g_strv_length (__nmtst_internal.orig_argv) + 1); - argv[0] = __nmtst_internal.sudo_cmd; - for (i = 0; __nmtst_internal.orig_argv[i]; i++) - argv[i+1] = __nmtst_internal.orig_argv[i]; + argv = g_new0(char *, 1 + g_strv_length(__nmtst_internal.orig_argv) + 1); + argv[0] = __nmtst_internal.sudo_cmd; + for (i = 0; __nmtst_internal.orig_argv[i]; i++) + argv[i + 1] = __nmtst_internal.orig_argv[i]; - execvp (__nmtst_internal.sudo_cmd, argv); + execvp(__nmtst_internal.sudo_cmd, argv); - errsv = errno; - g_error (">> exec %s failed: %d - %s", __nmtst_internal.sudo_cmd, errsv, nm_strerror_native (errsv)); + errsv = errno; + g_error(">> exec %s failed: %d - %s", + __nmtst_internal.sudo_cmd, + errsv, + nm_strerror_native(errsv)); } /*****************************************************************************/ static inline gsize -nmtst_find_all_indexes (gpointer *elements, - gsize n_elements, - gpointer *needles, - gsize n_needles, - gboolean (*equal_fcn) (gpointer element, gpointer needle, gpointer user_data), - gpointer user_data, - gssize *out_idx) -{ - gsize i, j, k; - gsize found = 0; - - for (i = 0; i < n_needles; i++) { - gssize idx = -1; - - for (j = 0; j < n_elements; j++) { - - /* no duplicates */ - for (k = 0; k < i; k++) { - if (out_idx[k] == j) - goto next; - } - - if (equal_fcn (elements[j], needles[i], user_data)) { - idx = j; - break; - } -next: - ; - } - - out_idx[i] = idx; - if (idx >= 0) - found++; - } - - return found; +nmtst_find_all_indexes(gpointer *elements, + gsize n_elements, + gpointer *needles, + gsize n_needles, + gboolean (*equal_fcn)(gpointer element, gpointer needle, gpointer user_data), + gpointer user_data, + gssize * out_idx) +{ + gsize i, j, k; + gsize found = 0; + + for (i = 0; i < n_needles; i++) { + gssize idx = -1; + + for (j = 0; j < n_elements; j++) { + /* no duplicates */ + for (k = 0; k < i; k++) { + if (out_idx[k] == j) + goto next; + } + + if (equal_fcn(elements[j], needles[i], user_data)) { + idx = j; + break; + } +next:; + } + + out_idx[i] = idx; + if (idx >= 0) + found++; + } + + return found; } /*****************************************************************************/ -#define __define_nmtst_static(NUM,SIZE) \ -static inline const char * \ -nmtst_static_##SIZE##_##NUM (const char *str) \ -{ \ - gsize l; \ - static char buf[SIZE]; \ -\ - if (!str) \ - return NULL; \ - l = g_strlcpy (buf, str, sizeof (buf)); \ - g_assert (l < sizeof (buf)); \ - return buf; \ -} -__define_nmtst_static(01, 1024) -__define_nmtst_static(02, 1024) -__define_nmtst_static(03, 1024) +#define __define_nmtst_static(NUM, SIZE) \ + static inline const char *nmtst_static_##SIZE##_##NUM(const char *str) \ + { \ + gsize l; \ + static _nm_thread_local char buf[SIZE]; \ + \ + if (!str) \ + return NULL; \ + l = g_strlcpy(buf, str, sizeof(buf)); \ + g_assert(l < sizeof(buf)); \ + return buf; \ + } +__define_nmtst_static(01, 1024) __define_nmtst_static(02, 1024) __define_nmtst_static(03, 1024) #undef __define_nmtst_static -#if defined (__NM_UTILS_H__) || defined (NM_UTILS_H) +#if defined(__NM_UTILS_H__) || defined(NM_UTILS_H) -#define NMTST_UUID_INIT(uuid) \ - gs_free char *_nmtst_hidden_##uuid = nm_utils_uuid_generate (); \ - const char *const uuid = _nmtst_hidden_##uuid + #define NMTST_UUID_INIT(uuid) \ + gs_free char * _nmtst_hidden_##uuid = nm_utils_uuid_generate(); \ + const char *const uuid = _nmtst_hidden_##uuid -static inline const char * -nmtst_uuid_generate (void) + static inline const char *nmtst_uuid_generate(void) { - static char u[37]; - gs_free char *m = NULL; + static _nm_thread_local char u[37]; + gs_free char * m = NULL; - m = nm_utils_uuid_generate (); - g_assert (m && strlen (m) == sizeof (u) - 1); - memcpy (u, m, sizeof (u)); - return u; + m = nm_utils_uuid_generate(); + g_assert(m && strlen(m) == sizeof(u) - 1); + memcpy(u, m, sizeof(u)); + return u; } #endif -#define nmtst_assert_str_has_substr(str, substr) \ - G_STMT_START { \ - const char *__str = (str); \ - const char *__substr = (substr); \ - \ - g_assert (__str); \ - g_assert (__substr); \ - if (strstr (__str, __substr) == NULL) \ - g_error ("%s:%d: Expects \"%s\" but got \"%s\"", __FILE__, __LINE__, __substr, __str); \ - } G_STMT_END +#define nmtst_assert_str_has_substr(str, substr) \ + G_STMT_START \ + { \ + const char *__str = (str); \ + const char *__substr = (substr); \ + \ + g_assert(__str); \ + g_assert(__substr); \ + if (strstr(__str, __substr) == NULL) \ + g_error("%s:%d: Expects \"%s\" but got \"%s\"", __FILE__, __LINE__, __substr, __str); \ + } \ + G_STMT_END -static inline guint32 -nmtst_inet4_from_string (const char *str) +static inline in_addr_t +nmtst_inet4_from_string(const char *str) { - guint32 addr; - int success; + in_addr_t addr; + int success; - if (!str) - return 0; + if (!str) + return 0; - success = inet_pton (AF_INET, str, &addr); + success = inet_pton(AF_INET, str, &addr); - g_assert (success == 1); + g_assert(success == 1); - return addr; + return addr; } static inline const struct in6_addr * -nmtst_inet6_from_string (const char *str) +nmtst_inet6_from_string(const char *str) { - static struct in6_addr addr; - int success; + static _nm_thread_local struct in6_addr addr; + int success; - if (!str) - addr = in6addr_any; - else { - success = inet_pton (AF_INET6, str, &addr); - g_assert (success == 1); - } + if (!str) + addr = in6addr_any; + else { + success = inet_pton(AF_INET6, str, &addr); + g_assert(success == 1); + } - return &addr; + return &addr; } static inline gconstpointer -nmtst_inet_from_string (int addr_family, const char *str) +nmtst_inet_from_string(int addr_family, const char *str) { - if (addr_family == AF_INET) { - static in_addr_t a; + if (addr_family == AF_INET) { + static in_addr_t a; - a = nmtst_inet4_from_string (str); - return &a; - } - if (addr_family == AF_INET6) - return nmtst_inet6_from_string (str); + a = nmtst_inet4_from_string(str); + return &a; + } + if (addr_family == AF_INET6) + return nmtst_inet6_from_string(str); - g_assert_not_reached (); - return NULL; + g_assert_not_reached(); + return NULL; } static inline const char * -nmtst_inet_to_string (int addr_family, gconstpointer addr) +nmtst_inet_to_string(int addr_family, gconstpointer addr) { - static char buf[NM_CONST_MAX (INET6_ADDRSTRLEN, INET_ADDRSTRLEN)]; + static _nm_thread_local char buf[NM_CONST_MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)]; - g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - g_assert (addr); + g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); + g_assert(addr); - if (inet_ntop (addr_family, addr, buf, sizeof (buf)) != buf) - g_assert_not_reached (); + if (inet_ntop(addr_family, addr, buf, sizeof(buf)) != buf) + g_assert_not_reached(); - return buf; + return buf; } static inline const char * -nmtst_inet4_to_string (in_addr_t addr) +nmtst_inet4_to_string(in_addr_t addr) { - return nmtst_inet_to_string (AF_INET, &addr); + return nmtst_inet_to_string(AF_INET, &addr); } static inline const char * -nmtst_inet6_to_string (const struct in6_addr *addr) +nmtst_inet6_to_string(const struct in6_addr *addr) { - return nmtst_inet_to_string (AF_INET6, addr); + return nmtst_inet_to_string(AF_INET6, addr); } static inline void -_nmtst_assert_ip4_address (const char *file, int line, in_addr_t addr, const char *str_expected) +_nmtst_assert_ip4_address(const char *file, int line, in_addr_t addr, const char *str_expected) { - if (nmtst_inet4_from_string (str_expected) != addr) { - char buf[100]; + if (nmtst_inet4_from_string(str_expected) != addr) { + char buf[100]; - g_error ("%s:%d: Unexpected IPv4 address: expected %s, got %s", - file, line, str_expected ?: "0.0.0.0", - inet_ntop (AF_INET, &addr, buf, sizeof (buf))); - } + g_error("%s:%d: Unexpected IPv4 address: expected %s, got %s", + file, + line, + str_expected ?: "0.0.0.0", + inet_ntop(AF_INET, &addr, buf, sizeof(buf))); + } } -#define nmtst_assert_ip4_address(addr, str_expected) _nmtst_assert_ip4_address (__FILE__, __LINE__, addr, str_expected) +#define nmtst_assert_ip4_address(addr, str_expected) \ + _nmtst_assert_ip4_address(__FILE__, __LINE__, addr, str_expected) static inline void -_nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *addr, const char *str_expected) -{ - struct in6_addr any = in6addr_any; - - if (!addr) - addr = &any; - - if (memcmp (nmtst_inet6_from_string (str_expected), addr, sizeof (*addr)) != 0) { - char buf[100]; - - g_error ("%s:%d: Unexpected IPv6 address: expected %s, got %s", - file, line, str_expected ?: "::", - inet_ntop (AF_INET6, addr, buf, sizeof (buf))); - } -} -#define nmtst_assert_ip6_address(addr, str_expected) _nmtst_assert_ip6_address (__FILE__, __LINE__, addr, str_expected) +_nmtst_assert_ip6_address(const char * file, + int line, + const struct in6_addr *addr, + const char * str_expected) +{ + struct in6_addr any = in6addr_any; + + if (!addr) + addr = &any; + + if (memcmp(nmtst_inet6_from_string(str_expected), addr, sizeof(*addr)) != 0) { + char buf[100]; + + g_error("%s:%d: Unexpected IPv6 address: expected %s, got %s", + file, + line, + str_expected ?: "::", + inet_ntop(AF_INET6, addr, buf, sizeof(buf))); + } +} +#define nmtst_assert_ip6_address(addr, str_expected) \ + _nmtst_assert_ip6_address(__FILE__, __LINE__, addr, str_expected) + +#define nmtst_assert_ip_address(addr_family, addr, str_expected) \ + G_STMT_START \ + { \ + if (NM_IS_IPv4(addr_family)) \ + nmtst_assert_ip4_address(*((const in_addr_t *) (addr)), (str_expected)); \ + else \ + nmtst_assert_ip6_address((const struct in6_addr *) (addr), (str_expected)); \ + } \ + G_STMT_END #define nmtst_spawn_sync(working_directory, standard_out, standard_err, assert_exit_status, ...) \ - __nmtst_spawn_sync (working_directory, standard_out, standard_err, assert_exit_status, ##__VA_ARGS__, NULL) -static inline int -__nmtst_spawn_sync (const char *working_directory, char **standard_out, char **standard_err, int assert_exit_status, ...) G_GNUC_NULL_TERMINATED; + __nmtst_spawn_sync(working_directory, \ + standard_out, \ + standard_err, \ + assert_exit_status, \ + ##__VA_ARGS__, \ + NULL) +static inline int __nmtst_spawn_sync(const char *working_directory, + char ** standard_out, + char ** standard_err, + int assert_exit_status, + ...) G_GNUC_NULL_TERMINATED; static inline int -__nmtst_spawn_sync (const char *working_directory, char **standard_out, char **standard_err, int assert_exit_status, ...) -{ - int exit_status = 0; - GError *error = NULL; - char *arg; - va_list va_args; - GPtrArray *argv = g_ptr_array_new (); - gboolean success; - - va_start (va_args, assert_exit_status); - while ((arg = va_arg (va_args, char *))) - g_ptr_array_add (argv, arg); - va_end (va_args); - - g_assert (argv->len >= 1); - g_ptr_array_add (argv, NULL); - - success = g_spawn_sync (working_directory, - (char**) argv->pdata, - NULL, - 0 /*G_SPAWN_DEFAULT*/, - NULL, - NULL, - standard_out, - standard_err, - &exit_status, - &error); - if (!success) - g_error ("nmtst_spawn_sync(%s): %s", ((char **) argv->pdata)[0], error->message); - g_assert (!error); - - g_assert (!standard_out || *standard_out); - g_assert (!standard_err || *standard_err); - - if (assert_exit_status != -1) { - /* exit status is a guint8 on success. Set @assert_exit_status to -1 - * not to check for the exit status. */ - g_assert (WIFEXITED (exit_status)); - g_assert_cmpint (WEXITSTATUS (exit_status), ==, assert_exit_status); - } - - g_ptr_array_free (argv, TRUE); - return exit_status; +__nmtst_spawn_sync(const char *working_directory, + char ** standard_out, + char ** standard_err, + int assert_exit_status, + ...) +{ + int exit_status = 0; + GError * error = NULL; + char * arg; + va_list va_args; + GPtrArray *argv = g_ptr_array_new(); + gboolean success; + + va_start(va_args, assert_exit_status); + while ((arg = va_arg(va_args, char *))) + g_ptr_array_add(argv, arg); + va_end(va_args); + + g_assert(argv->len >= 1); + g_ptr_array_add(argv, NULL); + + success = g_spawn_sync(working_directory, + (char **) argv->pdata, + NULL, + 0 /*G_SPAWN_DEFAULT*/, + NULL, + NULL, + standard_out, + standard_err, + &exit_status, + &error); + if (!success) + g_error("nmtst_spawn_sync(%s): %s", ((char **) argv->pdata)[0], error->message); + g_assert(!error); + + g_assert(!standard_out || *standard_out); + g_assert(!standard_err || *standard_err); + + if (assert_exit_status != -1) { + /* exit status is a guint8 on success. Set @assert_exit_status to -1 + * not to check for the exit status. */ + g_assert(WIFEXITED(exit_status)); + g_assert_cmpint(WEXITSTATUS(exit_status), ==, assert_exit_status); + } + + g_ptr_array_free(argv, TRUE); + return exit_status; } /*****************************************************************************/ static inline char * -nmtst_file_resolve_relative_path (const char *rel, const char *cwd) +nmtst_file_resolve_relative_path(const char *rel, const char *cwd) { - gs_free char *cwd_free = NULL; + gs_free char *cwd_free = NULL; - g_assert (rel && *rel); + g_assert(rel && *rel); - if (g_path_is_absolute (rel)) - return g_strdup (rel); + if (g_path_is_absolute(rel)) + return g_strdup(rel); - if (!cwd) - cwd = cwd_free = g_get_current_dir (); - return g_build_filename (cwd, rel, NULL); + if (!cwd) + cwd = cwd_free = g_get_current_dir(); + return g_build_filename(cwd, rel, NULL); } static inline char * -nmtst_file_get_contents (const char *filename) -{ - GError *error = NULL; - gboolean success; - char *contents = NULL; - gsize len; - - success = g_file_get_contents (filename, &contents, &len, &error); - nmtst_assert_success (success && contents, error); - g_assert_cmpint (strlen (contents), ==, len); - return contents; -} - -#define nmtst_file_set_contents_size(filename, content, size) \ - G_STMT_START { \ - GError *_error = NULL; \ - gboolean _success; \ - const char *_content = (content); \ - gssize _size = (size); \ - \ - g_assert (_content); \ - \ - if (_size < 0) { \ - g_assert (_size == -1); \ - _size = strlen (_content); \ - } \ - \ - _success = g_file_set_contents ((filename), _content, _size, &_error); \ - nmtst_assert_success (_success, _error); \ - } G_STMT_END +nmtst_file_get_contents(const char *filename) +{ + GError * error = NULL; + gboolean success; + char * contents = NULL; + gsize len; + + success = g_file_get_contents(filename, &contents, &len, &error); + nmtst_assert_success(success && contents, error); + g_assert_cmpint(strlen(contents), ==, len); + return contents; +} + +#define nmtst_file_set_contents_size(filename, content, size) \ + G_STMT_START \ + { \ + GError * _error = NULL; \ + gboolean _success; \ + const char *_content = (content); \ + gssize _size = (size); \ + \ + g_assert(_content); \ + \ + if (_size < 0) { \ + g_assert(_size == -1); \ + _size = strlen(_content); \ + } \ + \ + _success = g_file_set_contents((filename), _content, _size, &_error); \ + nmtst_assert_success(_success, _error); \ + } \ + G_STMT_END #define nmtst_file_set_contents(filename, content) \ - nmtst_file_set_contents_size (filename, content, -1) + nmtst_file_set_contents_size(filename, content, -1) /*****************************************************************************/ static inline void -nmtst_file_unlink_if_exists (const char *name) +nmtst_file_unlink_if_exists(const char *name) { - int errsv; + int errsv; - g_assert (name && name[0]); + g_assert(name && name[0]); - if (unlink (name) != 0) { - errsv = errno; - if (errsv != ENOENT) - g_error ("nmtst_file_unlink_if_exists(%s): failed with %s", name, nm_strerror_native (errsv)); - } + if (unlink(name) != 0) { + errsv = errno; + if (errsv != ENOENT) + g_error("nmtst_file_unlink_if_exists(%s): failed with %s", + name, + nm_strerror_native(errsv)); + } } static inline void -nmtst_file_unlink (const char *name) +nmtst_file_unlink(const char *name) { - int errsv; + int errsv; - g_assert (name && name[0]); + g_assert(name && name[0]); - if (unlink (name) != 0) { - errsv = errno; - g_error ("nmtst_file_unlink(%s): failed with %s", name, nm_strerror_native (errsv)); - } + if (unlink(name) != 0) { + errsv = errno; + g_error("nmtst_file_unlink(%s): failed with %s", name, nm_strerror_native(errsv)); + } } static inline void -_nmtst_auto_unlinkfile (char **p_name) +_nmtst_auto_unlinkfile(char **p_name) { - if (*p_name) { - nmtst_file_unlink (*p_name); - nm_clear_g_free (p_name); - } + if (*p_name) { + nmtst_file_unlink(*p_name); + nm_clear_g_free(p_name); + } } #define nmtst_auto_unlinkfile nm_auto(_nmtst_auto_unlinkfile) @@ -1606,54 +1710,64 @@ _nmtst_auto_unlinkfile (char **p_name) /*****************************************************************************/ static inline void -_nmtst_assert_resolve_relative_path_equals (const char *f1, const char *f2, const char *file, int line) -{ - gs_free char *p1 = NULL, *p2 = NULL; - - p1 = nmtst_file_resolve_relative_path (f1, NULL); - p2 = nmtst_file_resolve_relative_path (f2, NULL); - g_assert (p1 && *p1); - - /* Fixme: later we might need to coalesce repeated '/', "./", and "../". - * For now, it's good enough. */ - if (g_strcmp0 (p1, p2) != 0) - g_error ("%s:%d : filenames don't match \"%s\" vs. \"%s\" // \"%s\" - \"%s\"", file, line, f1, f2, p1, p2); -} -#define nmtst_assert_resolve_relative_path_equals(f1, f2) _nmtst_assert_resolve_relative_path_equals (f1, f2, __FILE__, __LINE__); +_nmtst_assert_resolve_relative_path_equals(const char *f1, + const char *f2, + const char *file, + int line) +{ + gs_free char *p1 = NULL, *p2 = NULL; + + p1 = nmtst_file_resolve_relative_path(f1, NULL); + p2 = nmtst_file_resolve_relative_path(f2, NULL); + g_assert(p1 && *p1); + + /* Fixme: later we might need to coalesce repeated '/', "./", and "../". + * For now, it's good enough. */ + if (g_strcmp0(p1, p2) != 0) + g_error("%s:%d : filenames don't match \"%s\" vs. \"%s\" // \"%s\" - \"%s\"", + file, + line, + f1, + f2, + p1, + p2); +} +#define nmtst_assert_resolve_relative_path_equals(f1, f2) \ + _nmtst_assert_resolve_relative_path_equals(f1, f2, __FILE__, __LINE__); /*****************************************************************************/ #ifdef __NETWORKMANAGER_LOGGING_H__ static inline gpointer -nmtst_logging_disable (gboolean always) +nmtst_logging_disable(gboolean always) { - gpointer p; + gpointer p; - g_assert (nmtst_initialized ()); - if (!always && __nmtst_internal.no_expect_message) { - /* The caller does not want to @always suppress logging. Instead, - * the caller wants to suppress unexpected log messages that would - * fail assertions (since we possibly assert against all unexpected - * log messages). - * - * If the test is run with no-expect-message, then don't suppress - * the loggings, because they also wouldn't fail assertions. */ - return NULL; - } + g_assert(nmtst_initialized()); + if (!always && __nmtst_internal.no_expect_message) { + /* The caller does not want to @always suppress logging. Instead, + * the caller wants to suppress unexpected log messages that would + * fail assertions (since we possibly assert against all unexpected + * log messages). + * + * If the test is run with no-expect-message, then don't suppress + * the loggings, because they also wouldn't fail assertions. */ + return NULL; + } - p = g_memdup (_nm_logging_enabled_state, sizeof (_nm_logging_enabled_state)); - memset (_nm_logging_enabled_state, 0, sizeof (_nm_logging_enabled_state)); - return p; + p = g_memdup(_nm_logging_enabled_state, sizeof(_nm_logging_enabled_state)); + memset(_nm_logging_enabled_state, 0, sizeof(_nm_logging_enabled_state)); + return p; } static inline void -nmtst_logging_reenable (gpointer old_state) +nmtst_logging_reenable(gpointer old_state) { - g_assert (nmtst_initialized ()); - if (old_state) { - memcpy (_nm_logging_enabled_state, old_state, sizeof (_nm_logging_enabled_state)); - g_free (old_state); - } + g_assert(nmtst_initialized()); + if (old_state) { + memcpy(_nm_logging_enabled_state, old_state, sizeof(_nm_logging_enabled_state)); + g_free(old_state); + } } #endif @@ -1661,616 +1775,639 @@ nmtst_logging_reenable (gpointer old_state) #ifdef NM_SETTING_IP_CONFIG_H static inline void -nmtst_setting_ip_config_add_address (NMSettingIPConfig *s_ip, - const char *address, - guint prefix) +nmtst_setting_ip_config_add_address(NMSettingIPConfig *s_ip, const char *address, guint prefix) { - NMIPAddress *addr; - int family; + NMIPAddress *addr; + int family; - g_assert (s_ip); + g_assert(s_ip); - if (nm_utils_ipaddr_is_valid (AF_INET, address)) - family = AF_INET; - else if (nm_utils_ipaddr_is_valid (AF_INET6, address)) - family = AF_INET6; - else - g_assert_not_reached (); + if (nm_utils_ipaddr_is_valid(AF_INET, address)) + family = AF_INET; + else if (nm_utils_ipaddr_is_valid(AF_INET6, address)) + family = AF_INET6; + else + g_assert_not_reached(); - addr = nm_ip_address_new (family, address, prefix, NULL); - g_assert (addr); - g_assert (nm_setting_ip_config_add_address (s_ip, addr)); - nm_ip_address_unref (addr); + addr = nm_ip_address_new(family, address, prefix, NULL); + g_assert(addr); + g_assert(nm_setting_ip_config_add_address(s_ip, addr)); + nm_ip_address_unref(addr); } static inline void -nmtst_setting_ip_config_add_route (NMSettingIPConfig *s_ip, - const char *dest, - guint prefix, - const char *next_hop, - gint64 metric) +nmtst_setting_ip_config_add_route(NMSettingIPConfig *s_ip, + const char * dest, + guint prefix, + const char * next_hop, + gint64 metric) { - NMIPRoute *route; - int family; + NMIPRoute *route; + int family; - g_assert (s_ip); + g_assert(s_ip); - if (nm_utils_ipaddr_is_valid (AF_INET, dest)) - family = AF_INET; - else if (nm_utils_ipaddr_is_valid (AF_INET6, dest)) - family = AF_INET6; - else - g_assert_not_reached (); + if (nm_utils_ipaddr_is_valid(AF_INET, dest)) + family = AF_INET; + else if (nm_utils_ipaddr_is_valid(AF_INET6, dest)) + family = AF_INET6; + else + g_assert_not_reached(); - route = nm_ip_route_new (family, dest, prefix, next_hop, metric, NULL); - g_assert (route); - g_assert (nm_setting_ip_config_add_route (s_ip, route)); - nm_ip_route_unref (route); + route = nm_ip_route_new(family, dest, prefix, next_hop, metric, NULL); + g_assert(route); + g_assert(nm_setting_ip_config_add_route(s_ip, route)); + nm_ip_route_unref(route); } static inline void -nmtst_assert_route_attribute_string (NMIPRoute *route, const char *name, const char *value) +nmtst_assert_route_attribute_string(NMIPRoute *route, const char *name, const char *value) { - GVariant *variant; + GVariant *variant; - variant = nm_ip_route_get_attribute (route, name); - g_assert (variant); - g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); - g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, value); + variant = nm_ip_route_get_attribute(route, name); + g_assert(variant); + g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr(g_variant_get_string(variant, NULL), ==, value); } static inline void -nmtst_assert_route_attribute_byte (NMIPRoute *route, const char *name, guchar value) +nmtst_assert_route_attribute_byte(NMIPRoute *route, const char *name, guchar value) { - GVariant *variant; + GVariant *variant; - variant = nm_ip_route_get_attribute (route, name); - g_assert (variant); - g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)); - g_assert_cmpint (g_variant_get_byte (variant), ==, value); + variant = nm_ip_route_get_attribute(route, name); + g_assert(variant); + g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTE)); + g_assert_cmpint(g_variant_get_byte(variant), ==, value); } static inline void -nmtst_assert_route_attribute_uint32 (NMIPRoute *route, const char *name, guint32 value) +nmtst_assert_route_attribute_uint32(NMIPRoute *route, const char *name, guint32 value) { - GVariant *variant; + GVariant *variant; - variant = nm_ip_route_get_attribute (route, name); - g_assert (variant); - g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); - g_assert_cmpint (g_variant_get_uint32 (variant), ==, value); + variant = nm_ip_route_get_attribute(route, name); + g_assert(variant); + g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpint(g_variant_get_uint32(variant), ==, value); } static inline void -nmtst_assert_route_attribute_boolean (NMIPRoute *route, const char *name, gboolean value) +nmtst_assert_route_attribute_boolean(NMIPRoute *route, const char *name, gboolean value) { - GVariant *variant; + GVariant *variant; - variant = nm_ip_route_get_attribute (route, name); - g_assert (variant); - g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)); - g_assert_cmpint (g_variant_get_boolean (variant), ==, value); + variant = nm_ip_route_get_attribute(route, name); + g_assert(variant); + g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)); + g_assert_cmpint(g_variant_get_boolean(variant), ==, value); } #endif /* NM_SETTING_IP_CONFIG_H */ -#if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) || (defined(NM_CONNECTION_H)) +#if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) \ + || (defined(NM_CONNECTION_H)) static inline NMConnection * -nmtst_clone_connection (NMConnection *connection) +nmtst_clone_connection(NMConnection *connection) { - g_assert (NM_IS_CONNECTION (connection)); + g_assert(NM_IS_CONNECTION(connection)); -#if defined(__NM_SIMPLE_CONNECTION_H__) - return nm_simple_connection_new_clone (connection); -#else - return nm_connection_duplicate (connection); -#endif + #if defined(__NM_SIMPLE_CONNECTION_H__) + return nm_simple_connection_new_clone(connection); + #else + return nm_connection_duplicate(connection); + #endif } static inline NMConnection * -nmtst_create_minimal_connection (const char *id, const char *uuid, const char *type, NMSettingConnection **out_s_con) +nmtst_create_minimal_connection(const char * id, + const char * uuid, + const char * type, + NMSettingConnection **out_s_con) { - NMConnection *con; - NMSetting *s_base = NULL; - NMSettingConnection *s_con; - gs_free char *uuid_free = NULL; + NMConnection * con; + NMSetting * s_base = NULL; + NMSettingConnection *s_con; + gs_free char * uuid_free = NULL; - g_assert (id); + g_assert(id); - if (uuid) - g_assert (nm_utils_is_uuid (uuid)); - else - uuid = uuid_free = nm_utils_uuid_generate (); + if (uuid) + g_assert(nm_utils_is_uuid(uuid)); + else + uuid = uuid_free = nm_utils_uuid_generate(); - if (type) { - GType type_g; + if (type) { + GType type_g; -#if defined(__NM_SIMPLE_CONNECTION_H__) - type_g = nm_setting_lookup_type (type); -#else - type_g = nm_connection_lookup_setting_type (type); -#endif + #if defined(__NM_SIMPLE_CONNECTION_H__) + type_g = nm_setting_lookup_type(type); + #else + type_g = nm_connection_lookup_setting_type(type); + #endif - g_assert (type_g != G_TYPE_INVALID); + g_assert(type_g != G_TYPE_INVALID); - s_base = g_object_new (type_g, NULL); - g_assert (NM_IS_SETTING (s_base)); - } + s_base = g_object_new(type_g, NULL); + g_assert(NM_IS_SETTING(s_base)); + } -#if defined(__NM_SIMPLE_CONNECTION_H__) - con = nm_simple_connection_new (); -#else - con = nm_connection_new (); -#endif + #if defined(__NM_SIMPLE_CONNECTION_H__) + con = nm_simple_connection_new(); + #else + con = nm_connection_new(); + #endif - g_assert (con); + g_assert(con); - s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + s_con = NM_SETTING_CONNECTION(nm_setting_connection_new()); - g_assert (s_con); + g_assert(s_con); - g_object_set (s_con, - NM_SETTING_CONNECTION_ID, id, - NM_SETTING_CONNECTION_UUID, uuid, - NM_SETTING_CONNECTION_TYPE, type, - NULL); - nm_connection_add_setting (con, NM_SETTING (s_con)); + g_object_set(s_con, + NM_SETTING_CONNECTION_ID, + id, + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_TYPE, + type, + NULL); + nm_connection_add_setting(con, NM_SETTING(s_con)); - if (s_base) - nm_connection_add_setting (con, s_base); + if (s_base) + nm_connection_add_setting(con, s_base); - if (out_s_con) - *out_s_con = s_con; - return con; + if (out_s_con) + *out_s_con = s_con; + return con; } static inline gboolean -_nmtst_connection_normalize_v (NMConnection *connection, va_list args) +_nmtst_connection_normalize_v(NMConnection *connection, va_list args) { - GError *error = NULL; - gboolean success; - gboolean was_modified = FALSE; - GHashTable *parameters = NULL; - const char *p_name; + GError * error = NULL; + gboolean success; + gboolean was_modified = FALSE; + GHashTable *parameters = NULL; + const char *p_name; - g_assert (NM_IS_CONNECTION (connection)); + g_assert(NM_IS_CONNECTION(connection)); - while ((p_name = va_arg (args, const char *))) { - if (!parameters) - parameters = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (parameters, (gpointer *) p_name, va_arg (args, gpointer)); - } + while ((p_name = va_arg(args, const char *))) { + if (!parameters) + parameters = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(parameters, (gpointer *) p_name, va_arg(args, gpointer)); + } - success = nm_connection_normalize (connection, - parameters, - &was_modified, - &error); - g_assert_no_error (error); - g_assert (success); + success = nm_connection_normalize(connection, parameters, &was_modified, &error); + g_assert_no_error(error); + g_assert(success); - if (parameters) - g_hash_table_destroy (parameters); + if (parameters) + g_hash_table_destroy(parameters); - return was_modified; + return was_modified; } static inline gboolean -_nmtst_connection_normalize (NMConnection *connection, ...) +_nmtst_connection_normalize(NMConnection *connection, ...) { - gboolean was_modified; - va_list args; + gboolean was_modified; + va_list args; - va_start (args, connection); - was_modified = _nmtst_connection_normalize_v (connection, args); - va_end (args); + va_start(args, connection); + was_modified = _nmtst_connection_normalize_v(connection, args); + va_end(args); - return was_modified; + return was_modified; } -#define nmtst_connection_normalize(connection, ...) \ - _nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL) + #define nmtst_connection_normalize(connection, ...) \ + _nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL) static inline NMConnection * -_nmtst_connection_duplicate_and_normalize (NMConnection *connection, ...) +_nmtst_connection_duplicate_and_normalize(NMConnection *connection, ...) { - va_list args; + va_list args; - connection = nmtst_clone_connection (connection); + connection = nmtst_clone_connection(connection); - va_start (args, connection); - _nmtst_connection_normalize_v (connection, args); - va_end (args); + va_start(args, connection); + _nmtst_connection_normalize_v(connection, args); + va_end(args); - return connection; + return connection; } -#define nmtst_connection_duplicate_and_normalize(connection, ...) \ - _nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL) + #define nmtst_connection_duplicate_and_normalize(connection, ...) \ + _nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL) static inline void -nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnection *b, gboolean normalize_b) -{ - gboolean compare; - gs_unref_object NMConnection *a2 = NULL; - gs_unref_object NMConnection *b2 = NULL; - GHashTable *out_settings = NULL; - - g_assert (NM_IS_CONNECTION (a)); - g_assert (NM_IS_CONNECTION (b)); - - if (normalize_a) - a = a2 = nmtst_connection_duplicate_and_normalize (a); - if (normalize_b) - b = b2 = nmtst_connection_duplicate_and_normalize (b); - - compare = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_settings); - if (!compare || out_settings) { - const char *name, *pname; - GHashTable *setting; - GHashTableIter iter, iter2; - - __NMTST_LOG (g_message, ">>> ASSERTION nmtst_assert_connection_equals() fails"); - if (out_settings) { - g_hash_table_iter_init (&iter, out_settings); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) { - __NMTST_LOG (g_message, ">>> differences in setting '%s':", name); - - g_hash_table_iter_init (&iter2, setting); - while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL)) - __NMTST_LOG (g_message, ">>> differences in setting '%s.%s'", name, pname); - } - } - -#ifdef __NM_KEYFILE_INTERNAL_H__ - { - gs_unref_keyfile GKeyFile *kf_a = NULL, *kf_b = NULL; - gs_free char *str_a = NULL, *str_b = NULL; - - kf_a = nm_keyfile_write (a, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, NULL); - kf_b = nm_keyfile_write (b, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, NULL); - - if (kf_a) - str_a = g_key_file_to_data (kf_a, NULL, NULL); - if (kf_b) - str_b = g_key_file_to_data (kf_b, NULL, NULL); - - __NMTST_LOG (g_message, ">>> Connection A as kf (*WARNING: keyfile representation might not show the difference*):\n%s", str_a); - __NMTST_LOG (g_message, ">>> Connection B as kf (*WARNING: keyfile representation might not show the difference*):\n%s", str_b); - } -#endif - } - g_assert (compare); - g_assert (!out_settings); - - compare = nm_connection_compare (a, b, NM_SETTING_COMPARE_FLAG_EXACT); - g_assert (compare); +nmtst_assert_connection_equals(NMConnection *a, + gboolean normalize_a, + NMConnection *b, + gboolean normalize_b) +{ + gboolean compare; + gs_unref_object NMConnection *a2 = NULL; + gs_unref_object NMConnection *b2 = NULL; + GHashTable * out_settings = NULL; + + g_assert(NM_IS_CONNECTION(a)); + g_assert(NM_IS_CONNECTION(b)); + + if (normalize_a) + a = a2 = nmtst_connection_duplicate_and_normalize(a); + if (normalize_b) + b = b2 = nmtst_connection_duplicate_and_normalize(b); + + compare = nm_connection_diff(a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_settings); + if (!compare || out_settings) { + const char * name, *pname; + GHashTable * setting; + GHashTableIter iter, iter2; + + __NMTST_LOG(g_message, ">>> ASSERTION nmtst_assert_connection_equals() fails"); + if (out_settings) { + g_hash_table_iter_init(&iter, out_settings); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &setting)) { + __NMTST_LOG(g_message, ">>> differences in setting '%s':", name); + + g_hash_table_iter_init(&iter2, setting); + while (g_hash_table_iter_next(&iter2, (gpointer *) &pname, NULL)) + __NMTST_LOG(g_message, ">>> differences in setting '%s.%s'", name, pname); + } + } + + #ifdef __NM_KEYFILE_INTERNAL_H__ + { + nm_auto_unref_keyfile GKeyFile *kf_a = NULL, *kf_b = NULL; + gs_free char * str_a = NULL, *str_b = NULL; + + kf_a = nm_keyfile_write(a, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, NULL); + kf_b = nm_keyfile_write(b, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, NULL); + + if (kf_a) + str_a = g_key_file_to_data(kf_a, NULL, NULL); + if (kf_b) + str_b = g_key_file_to_data(kf_b, NULL, NULL); + + __NMTST_LOG(g_message, + ">>> Connection A as kf (*WARNING: keyfile representation might not show " + "the difference*):\n%s", + str_a); + __NMTST_LOG(g_message, + ">>> Connection B as kf (*WARNING: keyfile representation might not show " + "the difference*):\n%s", + str_b); + } + #endif + } + g_assert(compare); + g_assert(!out_settings); + + compare = nm_connection_compare(a, b, NM_SETTING_COMPARE_FLAG_EXACT); + g_assert(compare); } static inline void -nmtst_assert_connection_verifies (NMConnection *con) +nmtst_assert_connection_verifies(NMConnection *con) { - /* assert that the connection does verify, it might be normaliziable or not */ - GError *error = NULL; - gboolean success; + /* assert that the connection does verify, it might be normaliziable or not */ + GError * error = NULL; + gboolean success; - g_assert (NM_IS_CONNECTION (con)); + g_assert(NM_IS_CONNECTION(con)); - success = nm_connection_verify (con, &error); - g_assert_no_error (error); - g_assert (success); + success = nm_connection_verify(con, &error); + g_assert_no_error(error); + g_assert(success); } static inline void -nmtst_assert_connection_verifies_without_normalization (NMConnection *con) +nmtst_assert_connection_verifies_without_normalization(NMConnection *con) { - /* assert that the connection verifies and does not need any normalization */ - GError *error = NULL; - gboolean success; - gboolean was_modified = FALSE; - gs_unref_object NMConnection *clone = NULL; + /* assert that the connection verifies and does not need any normalization */ + GError * error = NULL; + gboolean success; + gboolean was_modified = FALSE; + gs_unref_object NMConnection *clone = NULL; - clone = nmtst_clone_connection (con); + clone = nmtst_clone_connection(con); - nmtst_assert_connection_verifies (con); + nmtst_assert_connection_verifies(con); - success = nm_connection_normalize (clone, NULL, &was_modified, &error); - g_assert_no_error (error); - g_assert (success); - nmtst_assert_connection_equals (con, FALSE, clone, FALSE); - g_assert (!was_modified); + success = nm_connection_normalize(clone, NULL, &was_modified, &error); + g_assert_no_error(error); + g_assert(success); + nmtst_assert_connection_equals(con, FALSE, clone, FALSE); + g_assert(!was_modified); } static inline void -nmtst_assert_connection_verifies_and_normalizable (NMConnection *con) +nmtst_assert_connection_verifies_and_normalizable(NMConnection *con) { - /* assert that the connection does verify, but normalization still modifies it */ - GError *error = NULL; - gboolean success; - gboolean was_modified = FALSE; - gs_unref_object NMConnection *clone = NULL; + /* assert that the connection does verify, but normalization still modifies it */ + GError * error = NULL; + gboolean success; + gboolean was_modified = FALSE; + gs_unref_object NMConnection *clone = NULL; - clone = nmtst_clone_connection (con); + clone = nmtst_clone_connection(con); - nmtst_assert_connection_verifies (con); + nmtst_assert_connection_verifies(con); - success = nm_connection_normalize (clone, NULL, &was_modified, &error); - g_assert_no_error (error); - g_assert (success); - g_assert (was_modified); + success = nm_connection_normalize(clone, NULL, &was_modified, &error); + g_assert_no_error(error); + g_assert(success); + g_assert(was_modified); - /* again! */ - nmtst_assert_connection_verifies_without_normalization (clone); + /* again! */ + nmtst_assert_connection_verifies_without_normalization(clone); } static inline void -nmtst_assert_connection_verifies_after_normalization (NMConnection *con, - GQuark expect_error_domain, - int expect_error_code) +nmtst_assert_connection_verifies_after_normalization(NMConnection *con, + GQuark expect_error_domain, + int expect_error_code) { - /* assert that the connection does not verify, but normalization does fix it */ - GError *error = NULL; - gboolean success; - gboolean was_modified = FALSE; - gs_unref_object NMConnection *clone = NULL; + /* assert that the connection does not verify, but normalization does fix it */ + GError * error = NULL; + gboolean success; + gboolean was_modified = FALSE; + gs_unref_object NMConnection *clone = NULL; - clone = nmtst_clone_connection (con); + clone = nmtst_clone_connection(con); - success = nm_connection_verify (con, &error); - nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL); - g_assert (!success); - g_clear_error (&error); + success = nm_connection_verify(con, &error); + nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL); + g_assert(!success); + g_clear_error(&error); - success = nm_connection_normalize (clone, NULL, &was_modified, &error); - g_assert_no_error (error); - g_assert (success); - g_assert (was_modified); + success = nm_connection_normalize(clone, NULL, &was_modified, &error); + g_assert_no_error(error); + g_assert(success); + g_assert(was_modified); - /* again! */ - nmtst_assert_connection_verifies_without_normalization (clone); + /* again! */ + nmtst_assert_connection_verifies_without_normalization(clone); } static inline void -nmtst_assert_connection_unnormalizable (NMConnection *con, - GQuark expect_error_domain, - int expect_error_code) +nmtst_assert_connection_unnormalizable(NMConnection *con, + GQuark expect_error_domain, + int expect_error_code) { - /* assert that the connection does not verify, and it cannot be fixed by normalization */ + /* assert that the connection does not verify, and it cannot be fixed by normalization */ - GError *error = NULL; - gboolean success; - gboolean was_modified = FALSE; - gs_unref_object NMConnection *clone = NULL; + GError * error = NULL; + gboolean success; + gboolean was_modified = FALSE; + gs_unref_object NMConnection *clone = NULL; - clone = nmtst_clone_connection (con); + clone = nmtst_clone_connection(con); - success = nm_connection_verify (con, &error); - nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL); - g_assert (!success); - g_clear_error (&error); + success = nm_connection_verify(con, &error); + nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL); + g_assert(!success); + g_clear_error(&error); - success = nm_connection_normalize (clone, NULL, &was_modified, &error); - nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL); - g_assert (!success); - g_assert (!was_modified); - nmtst_assert_connection_equals (con, FALSE, clone, FALSE); - g_clear_error (&error); + success = nm_connection_normalize(clone, NULL, &was_modified, &error); + nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL); + g_assert(!success); + g_assert(!was_modified); + nmtst_assert_connection_equals(con, FALSE, clone, FALSE); + g_clear_error(&error); } static inline void -nmtst_assert_setting_verifies (NMSetting *setting) +nmtst_assert_setting_verifies(NMSetting *setting) { - /* assert that the setting verifies without an error */ + /* assert that the setting verifies without an error */ - GError *error = NULL; - gboolean success; + GError * error = NULL; + gboolean success; - g_assert (NM_IS_SETTING (setting)); + g_assert(NM_IS_SETTING(setting)); - success = nm_setting_verify (setting, NULL, &error); - g_assert_no_error (error); - g_assert (success); + success = nm_setting_verify(setting, NULL, &error); + g_assert_no_error(error); + g_assert(success); } -#if defined(__NM_SIMPLE_CONNECTION_H__) && NM_CHECK_VERSION (1, 10, 0) && (!defined (NM_VERSION_MAX_ALLOWED) || NM_VERSION_MAX_ALLOWED >= NM_VERSION_1_10) + #if defined(__NM_SIMPLE_CONNECTION_H__) && NM_CHECK_VERSION(1, 10, 0) \ + && (!defined(NM_VERSION_MAX_ALLOWED) || NM_VERSION_MAX_ALLOWED >= NM_VERSION_1_10) static inline void -_nmtst_assert_connection_has_settings (NMConnection *connection, gboolean has_at_least, gboolean has_at_most, ...) -{ - gs_unref_hashtable GHashTable *names = NULL; - gs_free NMSetting **settings = NULL; - va_list ap; - const char *name; - guint i, len; - gs_unref_ptrarray GPtrArray *names_arr = NULL; - - g_assert (NM_IS_CONNECTION (connection)); - - names = g_hash_table_new (g_str_hash, g_str_equal); - names_arr = g_ptr_array_new (); - - va_start (ap, has_at_most); - while ((name = va_arg (ap, const char *))) { - if (!nm_g_hash_table_add (names, (gpointer) name)) - g_assert_not_reached (); - g_ptr_array_add (names_arr, (gpointer) name); - } - va_end (ap); - - g_ptr_array_add (names_arr, NULL); - - settings = nm_connection_get_settings (connection, &len); - for (i = 0; i < len; i++) { - if ( !g_hash_table_remove (names, nm_setting_get_name (settings[i])) - && has_at_most) { - g_error ("nmtst_assert_connection_has_settings(): has setting \"%s\" which is not expected", - nm_setting_get_name (settings[i])); - } - } - if ( g_hash_table_size (names) > 0 - && has_at_least) { - gs_free char *expected_str = g_strjoinv (" ", (char **) names_arr->pdata); - gs_free const char **settings_names = NULL; - gs_free char *has_str = NULL; - - settings_names = g_new0 (const char *, len + 1); - for (i = 0; i < len; i++) - settings_names[i] = nm_setting_get_name (settings[i]); - has_str = g_strjoinv (" ", (char **) settings_names); - - g_error ("nmtst_assert_connection_has_settings(): the setting lacks %u expected settings (expected: [%s] vs. has: [%s])", - g_hash_table_size (names), - expected_str, - has_str); - } -} -#define nmtst_assert_connection_has_settings(connection, ...) _nmtst_assert_connection_has_settings ((connection), TRUE, TRUE, __VA_ARGS__, NULL) -#define nmtst_assert_connection_has_settings_at_least(connection, ...) _nmtst_assert_connection_has_settings ((connection), TRUE, FALSE, __VA_ARGS__, NULL) -#define nmtst_assert_connection_has_settings_at_most(connection, ...) _nmtst_assert_connection_has_settings ((connection), FALSE, TRUE, __VA_ARGS__, NULL) -#endif +_nmtst_assert_connection_has_settings(NMConnection *connection, + gboolean has_at_least, + gboolean has_at_most, + ...) +{ + gs_unref_hashtable GHashTable *names = NULL; + gs_free NMSetting **settings = NULL; + va_list ap; + const char * name; + guint i, len; + gs_unref_ptrarray GPtrArray *names_arr = NULL; + + g_assert(NM_IS_CONNECTION(connection)); + + names = g_hash_table_new(g_str_hash, g_str_equal); + names_arr = g_ptr_array_new(); + + va_start(ap, has_at_most); + while ((name = va_arg(ap, const char *))) { + if (!nm_g_hash_table_add(names, (gpointer) name)) + g_assert_not_reached(); + g_ptr_array_add(names_arr, (gpointer) name); + } + va_end(ap); + + g_ptr_array_add(names_arr, NULL); + + settings = nm_connection_get_settings(connection, &len); + for (i = 0; i < len; i++) { + if (!g_hash_table_remove(names, nm_setting_get_name(settings[i])) && has_at_most) { + g_error( + "nmtst_assert_connection_has_settings(): has setting \"%s\" which is not expected", + nm_setting_get_name(settings[i])); + } + } + if (g_hash_table_size(names) > 0 && has_at_least) { + gs_free char * expected_str = g_strjoinv(" ", (char **) names_arr->pdata); + gs_free const char **settings_names = NULL; + gs_free char * has_str = NULL; + + settings_names = g_new0(const char *, len + 1); + for (i = 0; i < len; i++) + settings_names[i] = nm_setting_get_name(settings[i]); + has_str = g_strjoinv(" ", (char **) settings_names); + + g_error("nmtst_assert_connection_has_settings(): the setting lacks %u expected settings " + "(expected: [%s] vs. has: [%s])", + g_hash_table_size(names), + expected_str, + has_str); + } +} + #define nmtst_assert_connection_has_settings(connection, ...) \ + _nmtst_assert_connection_has_settings((connection), TRUE, TRUE, __VA_ARGS__, NULL) + #define nmtst_assert_connection_has_settings_at_least(connection, ...) \ + _nmtst_assert_connection_has_settings((connection), TRUE, FALSE, __VA_ARGS__, NULL) + #define nmtst_assert_connection_has_settings_at_most(connection, ...) \ + _nmtst_assert_connection_has_settings((connection), FALSE, TRUE, __VA_ARGS__, NULL) + #endif static inline void -nmtst_assert_setting_verify_fails (NMSetting *setting, - GQuark expect_error_domain, - int expect_error_code) +nmtst_assert_setting_verify_fails(NMSetting *setting, + GQuark expect_error_domain, + int expect_error_code) { - /* assert that the setting verification fails */ + /* assert that the setting verification fails */ - GError *error = NULL; - gboolean success; + GError * error = NULL; + gboolean success; - g_assert (NM_IS_SETTING (setting)); + g_assert(NM_IS_SETTING(setting)); - success = nm_setting_verify (setting, NULL, &error); - nmtst_assert_error (error, expect_error_domain, expect_error_code, NULL); - g_assert (!success); - g_clear_error (&error); + success = nm_setting_verify(setting, NULL, &error); + nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL); + g_assert(!success); + g_clear_error(&error); } static inline void -nmtst_assert_setting_is_equal (gconstpointer /* const NMSetting * */ a, - gconstpointer /* const NMSetting * */ b, - NMSettingCompareFlags flags) +nmtst_assert_setting_is_equal(gconstpointer /* const NMSetting * */ a, + gconstpointer /* const NMSetting * */ b, + NMSettingCompareFlags flags) { - gs_unref_hashtable GHashTable *hash = NULL; - guint32 r = nmtst_get_rand_uint32 (); + gs_unref_hashtable GHashTable *hash = NULL; + guint32 r = nmtst_get_rand_uint32(); - g_assert (NM_IS_SETTING (a)); - g_assert (NM_IS_SETTING (b)); + g_assert(NM_IS_SETTING(a)); + g_assert(NM_IS_SETTING(b)); - if (NM_FLAGS_HAS (r, 0x4)) - NM_SWAP (a, b); + if (NM_FLAGS_HAS(r, 0x4)) + NM_SWAP(&a, &b); - g_assert (nm_setting_compare ((NMSetting *) a, - (NMSetting *) b, - flags)); + g_assert(nm_setting_compare((NMSetting *) a, (NMSetting *) b, flags)); - if (NM_FLAGS_HAS (r, 0x8)) - NM_SWAP (a, b); + if (NM_FLAGS_HAS(r, 0x8)) + NM_SWAP(&a, &b); - g_assert (nm_setting_diff ((NMSetting *) a, - (NMSetting *) b, - flags, - NM_FLAGS_HAS (r, 0x1), - &hash)); - g_assert (!hash); + g_assert(nm_setting_diff((NMSetting *) a, (NMSetting *) b, flags, NM_FLAGS_HAS(r, 0x1), &hash)); + g_assert(!hash); } #endif #ifdef __NM_SETTING_PRIVATE_H__ static inline NMSetting * -nmtst_assert_setting_dbus_new (GType gtype, GVariant *variant) +nmtst_assert_setting_dbus_new(GType gtype, GVariant *variant) { - NMSetting *setting; - gs_free_error GError *error = NULL; + NMSetting * setting; + gs_free_error GError *error = NULL; - g_assert (g_type_is_a (gtype, NM_TYPE_SETTING)); - g_assert (gtype != NM_TYPE_SETTING); - g_assert (variant); - g_assert (g_variant_is_of_type (variant, NM_VARIANT_TYPE_SETTING)); + g_assert(g_type_is_a(gtype, NM_TYPE_SETTING)); + g_assert(gtype != NM_TYPE_SETTING); + g_assert(variant); + g_assert(g_variant_is_of_type(variant, NM_VARIANT_TYPE_SETTING)); - setting = _nm_setting_new_from_dbus (gtype, - variant, - NULL, - NM_SETTING_PARSE_FLAGS_STRICT, - &error); - nmtst_assert_success (setting, error); - return setting; + setting = + _nm_setting_new_from_dbus(gtype, variant, NULL, NM_SETTING_PARSE_FLAGS_STRICT, &error); + nmtst_assert_success(setting, error); + return setting; } static inline void -nmtst_assert_setting_dbus_roundtrip (gconstpointer /* const NMSetting * */ setting) +nmtst_assert_setting_dbus_roundtrip(gconstpointer /* const NMSetting * */ setting) { - gs_unref_object NMSetting *setting2 = NULL; - gs_unref_variant GVariant *variant = NULL; + gs_unref_object NMSetting *setting2 = NULL; + gs_unref_variant GVariant *variant = NULL; - g_assert (NM_IS_SETTING (setting)); + g_assert(NM_IS_SETTING(setting)); - variant = _nm_setting_to_dbus ((NMSetting *) setting, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL); - setting2 = nmtst_assert_setting_dbus_new (G_OBJECT_TYPE (setting), variant); - nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT); + variant = _nm_setting_to_dbus((NMSetting *) setting, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL); + setting2 = nmtst_assert_setting_dbus_new(G_OBJECT_TYPE(setting), variant); + nmtst_assert_setting_is_equal(setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT); } #endif #ifdef __NM_UTILS_H__ static inline void -nmtst_assert_hwaddr_equals (gconstpointer hwaddr1, gssize hwaddr1_len, const char *expected, const char *file, int line) -{ - guint8 buf2[NM_UTILS_HWADDR_LEN_MAX]; - gsize hwaddr2_len = 1; - const char *p; - gboolean success; - - g_assert (hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX); - - g_assert (expected); - for (p = expected; *p; p++) { - if (*p == ':' || *p == '-') - hwaddr2_len++; - } - g_assert (hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX); - g_assert (nm_utils_hwaddr_aton (expected, buf2, hwaddr2_len)); - - /* Manually check the entire hardware address instead of using - * nm_utils_hwaddr_matches() because that function doesn't compare - * entire InfiniBand addresses for various (legitimate) reasons. - */ - success = (hwaddr1_len == hwaddr2_len); - if (success) - success = !memcmp (hwaddr1, buf2, hwaddr1_len); - if (!success) { - g_error ("assert: %s:%d: hwaddr '%s' (%zd) expected, but got %s (%zd)", - file, line, expected, hwaddr2_len, nm_utils_hwaddr_ntoa (hwaddr1, hwaddr1_len), hwaddr1_len); - } -} -#define nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected) \ - nmtst_assert_hwaddr_equals (hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__) +nmtst_assert_hwaddr_equals(gconstpointer hwaddr1, + gssize hwaddr1_len, + const char * expected, + const char * file, + int line) +{ + guint8 buf2[NM_UTILS_HWADDR_LEN_MAX]; + gsize hwaddr2_len = 1; + const char *p; + gboolean success; + + g_assert(hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX); + + g_assert(expected); + for (p = expected; *p; p++) { + if (*p == ':' || *p == '-') + hwaddr2_len++; + } + g_assert(hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX); + g_assert(nm_utils_hwaddr_aton(expected, buf2, hwaddr2_len)); + + /* Manually check the entire hardware address instead of using + * nm_utils_hwaddr_matches() because that function doesn't compare + * entire InfiniBand addresses for various (legitimate) reasons. + */ + success = (hwaddr1_len == hwaddr2_len); + if (success) + success = !memcmp(hwaddr1, buf2, hwaddr1_len); + if (!success) { + g_error("assert: %s:%d: hwaddr '%s' (%zd) expected, but got %s (%zd)", + file, + line, + expected, + hwaddr2_len, + nm_utils_hwaddr_ntoa(hwaddr1, hwaddr1_len), + hwaddr1_len); + } +} + #define nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected) \ + nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__) #endif -#if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) && defined(__NM_KEYFILE_INTERNAL_H__) +#if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) \ + && defined(__NM_KEYFILE_INTERNAL_H__) static inline NMConnection * -nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *full_filename) +nmtst_create_connection_from_keyfile(const char *keyfile_str, const char *full_filename) { - gs_unref_keyfile GKeyFile *keyfile = NULL; - gs_free_error GError *error = NULL; - gboolean success; - NMConnection *con; - gs_free char *filename = g_path_get_basename (full_filename); - gs_free char *base_dir = g_path_get_dirname (full_filename); + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + gs_free_error GError *error = NULL; + gboolean success; + NMConnection * con; + gs_free char * filename = g_path_get_basename(full_filename); + gs_free char * base_dir = g_path_get_dirname(full_filename); - g_assert (keyfile_str); - g_assert (full_filename && full_filename[0] == '/'); + g_assert(keyfile_str); + g_assert(full_filename && full_filename[0] == '/'); - keyfile = g_key_file_new (); - success = g_key_file_load_from_data (keyfile, keyfile_str, strlen (keyfile_str), G_KEY_FILE_NONE, &error); - nmtst_assert_success (success, error); + keyfile = g_key_file_new(); + success = g_key_file_load_from_data(keyfile, + keyfile_str, + strlen(keyfile_str), + G_KEY_FILE_NONE, + &error); + nmtst_assert_success(success, error); - con = nm_keyfile_read (keyfile, base_dir, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); - nmtst_assert_success (NM_IS_CONNECTION (con), error); + con = nm_keyfile_read(keyfile, base_dir, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); + nmtst_assert_success(NM_IS_CONNECTION(con), error); - nm_keyfile_read_ensure_id (con, filename); - nm_keyfile_read_ensure_uuid (con, full_filename); + nm_keyfile_read_ensure_id(con, filename); + nm_keyfile_read_ensure_uuid(con, full_filename); - nmtst_connection_normalize (con); + nmtst_connection_normalize(con); - return con; + return con; } #endif @@ -2278,268 +2415,305 @@ nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *full_ #ifdef __NM_CONNECTION_H__ static inline GVariant * -_nmtst_variant_new_vardict (int dummy, ...) -{ - GVariantBuilder builder; - va_list ap; - const char *name; - GVariant *variant; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - - va_start (ap, dummy); - while ((name = va_arg (ap, const char *))) { - variant = va_arg (ap, GVariant *); - g_variant_builder_add (&builder, "{sv}", name, variant); - } - va_end (ap); - - return g_variant_builder_end (&builder); -} -#define nmtst_variant_new_vardict(...) _nmtst_variant_new_vardict (0, __VA_ARGS__, NULL) - -#define nmtst_assert_variant_is_of_type(variant, type) \ - G_STMT_START { \ - GVariant *_variantx = (variant); \ - \ - g_assert (_variantx); \ - g_assert (g_variant_is_of_type (_variantx, (type))); \ - } G_STMT_END - -#define nmtst_assert_variant_uint32(variant, val) \ - G_STMT_START { \ - GVariant *_variant = (variant); \ - \ - nmtst_assert_variant_is_of_type (_variant, G_VARIANT_TYPE_UINT32); \ - g_assert_cmpint (g_variant_get_uint32 (_variant), ==, (val)); \ - } G_STMT_END - -#define nmtst_assert_variant_string(variant, str) \ - G_STMT_START { \ - gsize _l; \ - GVariant *_variant = (variant); \ - const char *_str = (str); \ - \ - nmtst_assert_variant_is_of_type (_variant, G_VARIANT_TYPE_STRING); \ - g_assert (_str); \ - g_assert_cmpstr (g_variant_get_string (_variant, &_l), ==, _str); \ - g_assert_cmpint (_l, ==, strlen (_str)); \ - } G_STMT_END - -#ifdef __NM_SHARED_UTILS_H__ -#define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \ - G_STMT_START { \ - if (memcmp (_ptr2, _ptr, _len) != 0) { \ - gs_free char *_x1 = NULL; \ - gs_free char *_x2 = NULL; \ - const char *_xx1; \ - const char *_xx2; \ - \ - _xx1 = nm_utils_buf_utf8safe_escape (_ptr, _len, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &_x1); \ - _xx2 = nm_utils_buf_utf8safe_escape (_ptr2, _len, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &_x2); \ - g_assert_cmpstr (_xx1, ==, _xx2); \ - g_assert_not_reached (); \ - } \ - } G_STMT_END -#else -#define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) G_STMT_START { } G_STMT_END -#endif - -#define nmtst_assert_variant_bytestring(variant, ptr, len) \ - G_STMT_START { \ - GVariant *_variant = (variant); \ - gconstpointer _ptr = (ptr); \ - gconstpointer _ptr2; \ - gsize _len = (len); \ - gsize _len2; \ - \ - nmtst_assert_variant_is_of_type (_variant, G_VARIANT_TYPE_BYTESTRING); \ - _ptr2 = g_variant_get_fixed_array (_variant, &_len2, 1); \ - g_assert_cmpint (_len2, ==, _len); \ - if ( _len != 0 \ - && _ptr) { \ - _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len); \ - g_assert_cmpmem (_ptr2, _len2, _ptr, _len); \ - } \ - } G_STMT_END +_nmtst_variant_new_vardict(int dummy, ...) +{ + GVariantBuilder builder; + va_list ap; + const char * name; + GVariant * variant; + + g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); + + va_start(ap, dummy); + while ((name = va_arg(ap, const char *))) { + variant = va_arg(ap, GVariant *); + g_variant_builder_add(&builder, "{sv}", name, variant); + } + va_end(ap); + + return g_variant_builder_end(&builder); +} + #define nmtst_variant_new_vardict(...) _nmtst_variant_new_vardict(0, __VA_ARGS__, NULL) + + #define nmtst_assert_variant_is_of_type(variant, type) \ + G_STMT_START \ + { \ + GVariant *_variantx = (variant); \ + \ + g_assert(_variantx); \ + g_assert(g_variant_is_of_type(_variantx, (type))); \ + } \ + G_STMT_END + + #define nmtst_assert_variant_uint32(variant, val) \ + G_STMT_START \ + { \ + GVariant *_variant = (variant); \ + \ + nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_UINT32); \ + g_assert_cmpint(g_variant_get_uint32(_variant), ==, (val)); \ + } \ + G_STMT_END + + #define nmtst_assert_variant_string(variant, str) \ + G_STMT_START \ + { \ + gsize _l; \ + GVariant * _variant = (variant); \ + const char *_str = (str); \ + \ + nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_STRING); \ + g_assert(_str); \ + g_assert_cmpstr(g_variant_get_string(_variant, &_l), ==, _str); \ + g_assert_cmpint(_l, ==, strlen(_str)); \ + } \ + G_STMT_END + + #ifdef __NM_SHARED_UTILS_H__ + #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \ + G_STMT_START \ + { \ + if (memcmp(_ptr2, _ptr, _len) != 0) { \ + gs_free char *_x1 = NULL; \ + gs_free char *_x2 = NULL; \ + const char * _xx1; \ + const char * _xx2; \ + \ + _xx1 = nm_utils_buf_utf8safe_escape(_ptr, \ + _len, \ + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \ + &_x1); \ + _xx2 = nm_utils_buf_utf8safe_escape(_ptr2, \ + _len, \ + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \ + &_x2); \ + g_assert_cmpstr(_xx1, ==, _xx2); \ + g_assert_not_reached(); \ + } \ + } \ + G_STMT_END + #else + #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \ + G_STMT_START {} \ + G_STMT_END + #endif + + #define nmtst_assert_variant_bytestring(variant, ptr, len) \ + G_STMT_START \ + { \ + GVariant * _variant = (variant); \ + gconstpointer _ptr = (ptr); \ + gconstpointer _ptr2; \ + gsize _len = (len); \ + gsize _len2; \ + \ + nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_BYTESTRING); \ + _ptr2 = g_variant_get_fixed_array(_variant, &_len2, 1); \ + g_assert_cmpint(_len2, ==, _len); \ + if (_len != 0 && _ptr) { \ + _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len); \ + g_assert_cmpmem(_ptr2, _len2, _ptr, _len); \ + } \ + } \ + G_STMT_END typedef enum { - NMTST_VARIANT_EDITOR_CONNECTION, - NMTST_VARIANT_EDITOR_SETTING, - NMTST_VARIANT_EDITOR_PROPERTY + NMTST_VARIANT_EDITOR_CONNECTION, + NMTST_VARIANT_EDITOR_SETTING, + NMTST_VARIANT_EDITOR_PROPERTY } NmtstVariantEditorPhase; -#define NMTST_VARIANT_EDITOR(__connection_variant, __code) \ - G_STMT_START { \ - GVariantIter __connection_iter, *__setting_iter; \ - GVariantBuilder __connection_builder, __setting_builder; \ - const char *__cur_setting_name, *__cur_property_name; \ - GVariant *__property_val; \ - NmtstVariantEditorPhase __phase; \ - \ - g_variant_builder_init (&__connection_builder, NM_VARIANT_TYPE_CONNECTION); \ - g_variant_iter_init (&__connection_iter, __connection_variant); \ - \ - __phase = NMTST_VARIANT_EDITOR_CONNECTION; \ - __cur_setting_name = NULL; \ - __cur_property_name = NULL; \ - __code; \ - while (g_variant_iter_next (&__connection_iter, "{&sa{sv}}", &__cur_setting_name, &__setting_iter)) { \ - g_variant_builder_init (&__setting_builder, NM_VARIANT_TYPE_SETTING); \ - __phase = NMTST_VARIANT_EDITOR_SETTING; \ - __cur_property_name = NULL; \ - __code; \ - \ - while ( __cur_setting_name \ - && g_variant_iter_next (__setting_iter, "{&sv}", &__cur_property_name, &__property_val)) { \ - __phase = NMTST_VARIANT_EDITOR_PROPERTY; \ - __code; \ - \ - if (__cur_property_name) { \ - g_variant_builder_add (&__setting_builder, "{sv}", \ - __cur_property_name, \ - __property_val); \ - } \ - g_variant_unref (__property_val); \ - } \ - \ - if (__cur_setting_name) \ - g_variant_builder_add (&__connection_builder, "{sa{sv}}", __cur_setting_name, &__setting_builder); \ - else \ - g_variant_builder_clear (&__setting_builder); \ - g_variant_iter_free (__setting_iter); \ - } \ - \ - g_variant_unref (__connection_variant); \ - \ - __connection_variant = g_variant_builder_end (&__connection_builder); \ - } G_STMT_END; - -#define NMTST_VARIANT_ADD_SETTING(__setting_name, __setting_variant) \ - G_STMT_START { \ - if (__phase == NMTST_VARIANT_EDITOR_CONNECTION) \ - g_variant_builder_add (&__connection_builder, "{s@a{sv}}", __setting_name, __setting_variant); \ - } G_STMT_END - -#define NMTST_VARIANT_DROP_SETTING(__setting_name) \ - G_STMT_START { \ - if (__phase == NMTST_VARIANT_EDITOR_SETTING && __cur_setting_name) { \ - if (!strcmp (__cur_setting_name, __setting_name)) \ - __cur_setting_name = NULL; \ - } \ - } G_STMT_END - -#define NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value) \ - G_STMT_START { \ - if (__phase == NMTST_VARIANT_EDITOR_SETTING) { \ - if (!strcmp (__cur_setting_name, __setting_name)) { \ - g_variant_builder_add (&__setting_builder, "{sv}", __property_name, \ - g_variant_new (__format_string, __value)); \ - } \ - } \ - } G_STMT_END - -#define NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name) \ - G_STMT_START { \ - if (__phase == NMTST_VARIANT_EDITOR_PROPERTY && __cur_property_name) { \ - if ( !strcmp (__cur_setting_name, __setting_name) \ - && !strcmp (__cur_property_name, __property_name)) \ - __cur_property_name = NULL; \ - } \ - } G_STMT_END - -#define NMTST_VARIANT_CHANGE_PROPERTY(__setting_name, __property_name, __format_string, __value) \ - G_STMT_START { \ - NMTST_VARIANT_DROP_PROPERTY (__setting_name, __property_name); \ - NMTST_VARIANT_ADD_PROPERTY (__setting_name, __property_name, __format_string, __value); \ - } G_STMT_END + #define NMTST_VARIANT_EDITOR(__connection_variant, __code) \ + G_STMT_START \ + { \ + GVariantIter __connection_iter, *__setting_iter; \ + GVariantBuilder __connection_builder, __setting_builder; \ + const char * __cur_setting_name, *__cur_property_name; \ + GVariant * __property_val; \ + NmtstVariantEditorPhase __phase; \ + \ + g_variant_builder_init(&__connection_builder, NM_VARIANT_TYPE_CONNECTION); \ + g_variant_iter_init(&__connection_iter, __connection_variant); \ + \ + __phase = NMTST_VARIANT_EDITOR_CONNECTION; \ + __cur_setting_name = NULL; \ + __cur_property_name = NULL; \ + __code; \ + while (g_variant_iter_next(&__connection_iter, \ + "{&sa{sv}}", \ + &__cur_setting_name, \ + &__setting_iter)) { \ + g_variant_builder_init(&__setting_builder, NM_VARIANT_TYPE_SETTING); \ + __phase = NMTST_VARIANT_EDITOR_SETTING; \ + __cur_property_name = NULL; \ + __code; \ + \ + while (__cur_setting_name \ + && g_variant_iter_next(__setting_iter, \ + "{&sv}", \ + &__cur_property_name, \ + &__property_val)) { \ + __phase = NMTST_VARIANT_EDITOR_PROPERTY; \ + __code; \ + \ + if (__cur_property_name) { \ + g_variant_builder_add(&__setting_builder, \ + "{sv}", \ + __cur_property_name, \ + __property_val); \ + } \ + g_variant_unref(__property_val); \ + } \ + \ + if (__cur_setting_name) \ + g_variant_builder_add(&__connection_builder, \ + "{sa{sv}}", \ + __cur_setting_name, \ + &__setting_builder); \ + else \ + g_variant_builder_clear(&__setting_builder); \ + g_variant_iter_free(__setting_iter); \ + } \ + \ + g_variant_unref(__connection_variant); \ + \ + __connection_variant = g_variant_builder_end(&__connection_builder); \ + } \ + G_STMT_END; + + #define NMTST_VARIANT_ADD_SETTING(__setting_name, __setting_variant) \ + G_STMT_START \ + { \ + if (__phase == NMTST_VARIANT_EDITOR_CONNECTION) \ + g_variant_builder_add(&__connection_builder, \ + "{s@a{sv}}", \ + __setting_name, \ + __setting_variant); \ + } \ + G_STMT_END + + #define NMTST_VARIANT_DROP_SETTING(__setting_name) \ + G_STMT_START \ + { \ + if (__phase == NMTST_VARIANT_EDITOR_SETTING && __cur_setting_name) { \ + if (!strcmp(__cur_setting_name, __setting_name)) \ + __cur_setting_name = NULL; \ + } \ + } \ + G_STMT_END + + #define NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value) \ + G_STMT_START \ + { \ + if (__phase == NMTST_VARIANT_EDITOR_SETTING) { \ + if (!strcmp(__cur_setting_name, __setting_name)) { \ + g_variant_builder_add(&__setting_builder, \ + "{sv}", \ + __property_name, \ + g_variant_new(__format_string, __value)); \ + } \ + } \ + } \ + G_STMT_END + + #define NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name) \ + G_STMT_START \ + { \ + if (__phase == NMTST_VARIANT_EDITOR_PROPERTY && __cur_property_name) { \ + if (!strcmp(__cur_setting_name, __setting_name) \ + && !strcmp(__cur_property_name, __property_name)) \ + __cur_property_name = NULL; \ + } \ + } \ + G_STMT_END + + #define NMTST_VARIANT_CHANGE_PROPERTY(__setting_name, \ + __property_name, \ + __format_string, \ + __value) \ + G_STMT_START \ + { \ + NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name); \ + NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value); \ + } \ + G_STMT_END #endif /* __NM_CONNECTION_H__ */ static inline GVariant * -nmtst_variant_from_string (const GVariantType *variant_type, - const char *variant_str) +nmtst_variant_from_string(const GVariantType *variant_type, const char *variant_str) { - GVariant *variant; - GError *error = NULL; + GVariant *variant; + GError * error = NULL; - g_assert (variant_type); - g_assert (variant_str); + g_assert(variant_type); + g_assert(variant_str); - variant = g_variant_parse (variant_type, - variant_str, - NULL, - NULL, - &error); - nmtst_assert_success (variant, error); - return variant; + variant = g_variant_parse(variant_type, variant_str, NULL, NULL, &error); + nmtst_assert_success(variant, error); + return variant; } /*****************************************************************************/ static inline void -nmtst_keyfile_assert_data (GKeyFile *kf, const char *data, gssize data_len) +nmtst_keyfile_assert_data(GKeyFile *kf, const char *data, gssize data_len) { - gs_unref_keyfile GKeyFile *kf2 = NULL; - gs_free_error GError *error = NULL; - gs_free char *d1 = NULL; - gs_free char *d2 = NULL; - gboolean success; - gsize d1_len; - gsize d2_len; + nm_auto_unref_keyfile GKeyFile *kf2 = NULL; + gs_free_error GError *error = NULL; + gs_free char * d1 = NULL; + gs_free char * d2 = NULL; + gboolean success; + gsize d1_len; + gsize d2_len; - g_assert (kf); - g_assert (data || data_len == 0); - g_assert (data_len >= -1); + g_assert(kf); + g_assert(data || data_len == 0); + g_assert(data_len >= -1); - d1 = g_key_file_to_data (kf, &d1_len, &error); - nmtst_assert_success (d1, error); + d1 = g_key_file_to_data(kf, &d1_len, &error); + nmtst_assert_success(d1, error); - if (data_len == -1) { - g_assert_cmpint (strlen (d1), ==, d1_len); - data_len = strlen (data); - g_assert_cmpstr (d1, ==, data); - } + if (data_len == -1) { + g_assert_cmpint(strlen(d1), ==, d1_len); + data_len = strlen(data); + g_assert_cmpstr(d1, ==, data); + } - g_assert_cmpmem (d1, d1_len, data, (gsize) data_len); + g_assert_cmpmem(d1, d1_len, data, (gsize) data_len); - /* also check that we can re-generate the same keyfile from the data. */ + /* also check that we can re-generate the same keyfile from the data. */ - kf2 = g_key_file_new (); - success = g_key_file_load_from_data (kf2, - d1, - d1_len, - G_KEY_FILE_NONE, - &error); - nmtst_assert_success (success, error); + kf2 = g_key_file_new(); + success = g_key_file_load_from_data(kf2, d1, d1_len, G_KEY_FILE_NONE, &error); + nmtst_assert_success(success, error); - d2 = g_key_file_to_data (kf2, &d2_len, &error); - nmtst_assert_success (d2, error); + d2 = g_key_file_to_data(kf2, &d2_len, &error); + nmtst_assert_success(d2, error); - g_assert_cmpmem (d2, d2_len, d1, d1_len); + g_assert_cmpmem(d2, d2_len, d1, d1_len); } static inline gssize -nmtst_keyfile_get_num_keys (GKeyFile *keyfile, - const char *group_name) +nmtst_keyfile_get_num_keys(GKeyFile *keyfile, const char *group_name) { - gs_strfreev char **keys = NULL; - gs_free_error GError *error = NULL; - gsize l; + gs_strfreev char **keys = NULL; + gs_free_error GError *error = NULL; + gsize l; - g_assert (keyfile); - g_assert (group_name); + g_assert(keyfile); + g_assert(group_name); - if (!g_key_file_has_group (keyfile, group_name)) - return -1; + if (!g_key_file_has_group(keyfile, group_name)) + return -1; - keys = g_key_file_get_keys (keyfile, group_name, &l, &error); + keys = g_key_file_get_keys(keyfile, group_name, &l, &error); - nmtst_assert_success (keys, error); + nmtst_assert_success(keys, error); - g_assert_cmpint (NM_PTRARRAY_LEN (keys), ==, l); + g_assert_cmpint(NM_PTRARRAY_LEN(keys), ==, l); - return l; + return l; } /*****************************************************************************/ diff --git a/shared/nm-utils/nm-vpn-editor-plugin-call.h b/shared/nm-utils/nm-vpn-editor-plugin-call.h index b2c39e29..780ef193 100644 --- a/shared/nm-utils/nm-vpn-editor-plugin-call.h +++ b/shared/nm-utils/nm-vpn-editor-plugin-call.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2016 Red Hat, Inc. */ @@ -28,27 +28,26 @@ * add a new connection for the given service-type. **/ typedef enum { /*< skip >*/ - NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE = 0x00, - NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD = 0x01, + NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE = 0x00, + NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD = 0x01, } NMVpnEditorPluginServiceFlags; struct _NMVpnEditorPluginVT { - gboolean (*fcn_get_service_info) (NMVpnEditorPlugin *plugin, - const char *service_type, - char **out_short_name, - char **out_pretty_name, - char **out_description, - NMVpnEditorPluginServiceFlags *out_flags); - char **(*fcn_get_service_add_details) (NMVpnEditorPlugin *plugin, - const char *service_name); - gboolean (*fcn_get_service_add_detail) (NMVpnEditorPlugin *plugin, - const char *service_type, - const char *add_detail, - char **out_pretty_name, - char **out_description, - char **out_add_detail_key, - char **out_add_detail_val, - guint *out_flags); + gboolean (*fcn_get_service_info)(NMVpnEditorPlugin * plugin, + const char * service_type, + char ** out_short_name, + char ** out_pretty_name, + char ** out_description, + NMVpnEditorPluginServiceFlags *out_flags); + char **(*fcn_get_service_add_details)(NMVpnEditorPlugin *plugin, const char *service_name); + gboolean (*fcn_get_service_add_detail)(NMVpnEditorPlugin *plugin, + const char * service_type, + const char * add_detail, + char ** out_pretty_name, + char ** out_description, + char ** out_add_detail_key, + char ** out_add_detail_val, + guint * out_flags); }; /***************************************************************************** @@ -59,94 +58,93 @@ struct _NMVpnEditorPluginVT { *****************************************************************************/ static inline gboolean -nm_vpn_editor_plugin_get_service_info (NMVpnEditorPlugin *plugin, - const char *service_type, - char **out_short_name, - char **out_pretty_name, - char **out_description, - NMVpnEditorPluginServiceFlags *out_flags) +nm_vpn_editor_plugin_get_service_info(NMVpnEditorPlugin * plugin, + const char * service_type, + char ** out_short_name, + char ** out_pretty_name, + char ** out_description, + NMVpnEditorPluginServiceFlags *out_flags) { - NMVpnEditorPluginVT vt; - gs_free char *short_name_local = NULL; - gs_free char *pretty_name_local = NULL; - gs_free char *description_local = NULL; - guint flags_local = 0; - - g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE); - g_return_val_if_fail (service_type, FALSE); - - nm_vpn_editor_plugin_get_vt (plugin, &vt, sizeof (vt)); - if ( !vt.fcn_get_service_info - || !vt.fcn_get_service_info (plugin, - service_type, - out_short_name ? &short_name_local : NULL, - out_pretty_name ? &pretty_name_local : NULL, - out_description ? &description_local : NULL, - out_flags ? &flags_local : NULL)) - return FALSE; - NM_SET_OUT (out_short_name, g_steal_pointer (&short_name_local)); - NM_SET_OUT (out_pretty_name, g_steal_pointer (&pretty_name_local)); - NM_SET_OUT (out_description, g_steal_pointer (&description_local)); - NM_SET_OUT (out_flags, flags_local); - return TRUE; + NMVpnEditorPluginVT vt; + gs_free char * short_name_local = NULL; + gs_free char * pretty_name_local = NULL; + gs_free char * description_local = NULL; + guint flags_local = 0; + + g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), FALSE); + g_return_val_if_fail(service_type, FALSE); + + nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt)); + if (!vt.fcn_get_service_info + || !vt.fcn_get_service_info(plugin, + service_type, + out_short_name ? &short_name_local : NULL, + out_pretty_name ? &pretty_name_local : NULL, + out_description ? &description_local : NULL, + out_flags ? &flags_local : NULL)) + return FALSE; + NM_SET_OUT(out_short_name, g_steal_pointer(&short_name_local)); + NM_SET_OUT(out_pretty_name, g_steal_pointer(&pretty_name_local)); + NM_SET_OUT(out_description, g_steal_pointer(&description_local)); + NM_SET_OUT(out_flags, flags_local); + return TRUE; } static inline char ** -nm_vpn_editor_plugin_get_service_add_details (NMVpnEditorPlugin *plugin, - const char *service_name) +nm_vpn_editor_plugin_get_service_add_details(NMVpnEditorPlugin *plugin, const char *service_name) { - NMVpnEditorPluginVT vt; - char **details = NULL; - - g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), NULL); - g_return_val_if_fail (service_name, NULL); - - nm_vpn_editor_plugin_get_vt (plugin, &vt, sizeof (vt)); - if (vt.fcn_get_service_add_details) - details = vt.fcn_get_service_add_details (plugin, service_name); - if (!details) - return g_new0 (char *, 1); - return details; + NMVpnEditorPluginVT vt; + char ** details = NULL; + + g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), NULL); + g_return_val_if_fail(service_name, NULL); + + nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt)); + if (vt.fcn_get_service_add_details) + details = vt.fcn_get_service_add_details(plugin, service_name); + if (!details) + return g_new0(char *, 1); + return details; } static inline gboolean -nm_vpn_editor_plugin_get_service_add_detail (NMVpnEditorPlugin *plugin, - const char *service_type, - const char *add_detail, - char **out_pretty_name, - char **out_description, - char **out_add_detail_key, - char **out_add_detail_val, - guint *out_flags) +nm_vpn_editor_plugin_get_service_add_detail(NMVpnEditorPlugin *plugin, + const char * service_type, + const char * add_detail, + char ** out_pretty_name, + char ** out_description, + char ** out_add_detail_key, + char ** out_add_detail_val, + guint * out_flags) { - NMVpnEditorPluginVT vt; - gs_free char *pretty_name_local = NULL; - gs_free char *description_local = NULL; - gs_free char *add_detail_key_local = NULL; - gs_free char *add_detail_val_local = NULL; - guint flags_local = 0; - - g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (plugin), FALSE); - g_return_val_if_fail (service_type, FALSE); - g_return_val_if_fail (add_detail, FALSE); - - nm_vpn_editor_plugin_get_vt (plugin, &vt, sizeof (vt)); - if ( !vt.fcn_get_service_add_detail - || !vt.fcn_get_service_add_detail (plugin, - service_type, - add_detail, - out_pretty_name ? &pretty_name_local : NULL, - out_description ? &description_local : NULL, - out_add_detail_key ? &add_detail_key_local : NULL, - out_add_detail_val ? &add_detail_val_local : NULL, - out_flags ? &flags_local : NULL)) - return FALSE; - NM_SET_OUT (out_pretty_name, g_steal_pointer (&pretty_name_local)); - NM_SET_OUT (out_description, g_steal_pointer (&description_local)); - NM_SET_OUT (out_add_detail_key, g_steal_pointer (&add_detail_key_local)); - NM_SET_OUT (out_add_detail_val, g_steal_pointer (&add_detail_val_local)); - NM_SET_OUT (out_flags, flags_local); - return TRUE; + NMVpnEditorPluginVT vt; + gs_free char * pretty_name_local = NULL; + gs_free char * description_local = NULL; + gs_free char * add_detail_key_local = NULL; + gs_free char * add_detail_val_local = NULL; + guint flags_local = 0; + + g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), FALSE); + g_return_val_if_fail(service_type, FALSE); + g_return_val_if_fail(add_detail, FALSE); + + nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt)); + if (!vt.fcn_get_service_add_detail + || !vt.fcn_get_service_add_detail(plugin, + service_type, + add_detail, + out_pretty_name ? &pretty_name_local : NULL, + out_description ? &description_local : NULL, + out_add_detail_key ? &add_detail_key_local : NULL, + out_add_detail_val ? &add_detail_val_local : NULL, + out_flags ? &flags_local : NULL)) + return FALSE; + NM_SET_OUT(out_pretty_name, g_steal_pointer(&pretty_name_local)); + NM_SET_OUT(out_description, g_steal_pointer(&description_local)); + NM_SET_OUT(out_add_detail_key, g_steal_pointer(&add_detail_key_local)); + NM_SET_OUT(out_add_detail_val, g_steal_pointer(&add_detail_val_local)); + NM_SET_OUT(out_flags, flags_local); + return TRUE; } /***************************************************************************** @@ -155,19 +153,15 @@ nm_vpn_editor_plugin_get_service_add_detail (NMVpnEditorPlugin *plugin, * The following glue code can be used to implement calls in a VPN plugin. *****************************************************************************/ -#define NM_VPN_EDITOR_PLUGIN_VT_DEFINE(vt_name, get_vt, ...) \ -static const NMVpnEditorPluginVT vt_name = { \ - __VA_ARGS__ \ - }; \ -static const NMVpnEditorPluginVT * \ -get_vt (NMVpnEditorPlugin *plugin, \ - gsize *out_vt_size) \ -{ \ - nm_assert (NM_IS_VPN_EDITOR_PLUGIN (plugin)); \ - nm_assert (out_vt_size); \ - \ - *out_vt_size = sizeof (vt_name); \ - return &vt_name; \ -} +#define NM_VPN_EDITOR_PLUGIN_VT_DEFINE(vt_name, get_vt, ...) \ + static const NMVpnEditorPluginVT vt_name = {__VA_ARGS__}; \ + static const NMVpnEditorPluginVT *get_vt(NMVpnEditorPlugin *plugin, gsize *out_vt_size) \ + { \ + nm_assert(NM_IS_VPN_EDITOR_PLUGIN(plugin)); \ + nm_assert(out_vt_size); \ + \ + *out_vt_size = sizeof(vt_name); \ + return &vt_name; \ + } #endif /* __NM_VPN_EDITOR_PLUGIN_CALL_H__ */ diff --git a/shared/nm-utils/nm-vpn-plugin-macros.h b/shared/nm-utils/nm-vpn-plugin-macros.h index f154147f..2fec94e5 100644 --- a/shared/nm-utils/nm-vpn-plugin-macros.h +++ b/shared/nm-utils/nm-vpn-plugin-macros.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2016 Red Hat, Inc. */ @@ -9,50 +9,50 @@ #include <syslog.h> static inline int -nm_utils_syslog_coerce_from_nm (int syslog_level) +nm_utils_syslog_coerce_from_nm(int syslog_level) { - /* NetworkManager uses internally NMLogLevel levels. When spawning - * the VPN plugin, it maps those levels to syslog levels as follows: - * - * LOGL_INFO = LOG_NOTICE, - * LOGL_DEBUG = LOG_INFO, - * LOGL_TRACE = LOG_DEBUG, - * - * However, when actually printing to syslog, we don't want to print messages - * with LOGL_INFO level as LOG_NOTICE, because they are *not* to be highlighted. - * - * In other words: NetworkManager has 3 levels that should not require highlighting: - * LOGL_INFO, LOGL_DEBUG, LOGL_TRACE. syslog on the other hand has only LOG_INFO and LOG_DEBUG. - * - * So, coerce those values before printing to syslog. When you receive the syslog_level - * from NetworkManager, instead of calling - * syslog(syslog_level, ...) - * you should call - * syslog(nm_utils_syslog_coerce_from_nm(syslog_level), ...) - */ - switch (syslog_level) { - case LOG_INFO: - return LOG_DEBUG; - case LOG_NOTICE: - return LOG_INFO; - default: - return syslog_level; - } + /* NetworkManager uses internally NMLogLevel levels. When spawning + * the VPN plugin, it maps those levels to syslog levels as follows: + * + * LOGL_INFO = LOG_NOTICE, + * LOGL_DEBUG = LOG_INFO, + * LOGL_TRACE = LOG_DEBUG, + * + * However, when actually printing to syslog, we don't want to print messages + * with LOGL_INFO level as LOG_NOTICE, because they are *not* to be highlighted. + * + * In other words: NetworkManager has 3 levels that should not require highlighting: + * LOGL_INFO, LOGL_DEBUG, LOGL_TRACE. syslog on the other hand has only LOG_INFO and LOG_DEBUG. + * + * So, coerce those values before printing to syslog. When you receive the syslog_level + * from NetworkManager, instead of calling + * syslog(syslog_level, ...) + * you should call + * syslog(nm_utils_syslog_coerce_from_nm(syslog_level), ...) + */ + switch (syslog_level) { + case LOG_INFO: + return LOG_DEBUG; + case LOG_NOTICE: + return LOG_INFO; + default: + return syslog_level; + } } static inline const char * -nm_utils_syslog_to_str (int syslog_level) +nm_utils_syslog_to_str(int syslog_level) { - /* Maps the levels the same way as NetworkManager's nm-logging.c does */ - if (syslog_level >= LOG_DEBUG) - return "<trace>"; - if (syslog_level >= LOG_INFO) - return "<debug>"; - if (syslog_level >= LOG_NOTICE) - return "<info>"; - if (syslog_level >= LOG_WARNING) - return "<warn>"; - return "<error>"; + /* Maps the levels the same way as NetworkManager's nm-logging.c does */ + if (syslog_level >= LOG_DEBUG) + return "<trace>"; + if (syslog_level >= LOG_INFO) + return "<debug>"; + if (syslog_level >= LOG_NOTICE) + return "<info>"; + if (syslog_level >= LOG_WARNING) + return "<warn>"; + return "<error>"; } /*****************************************************************************/ @@ -60,18 +60,17 @@ nm_utils_syslog_to_str (int syslog_level) /* possibly missing defines from newer libnm API. */ #ifndef NM_VPN_PLUGIN_CONFIG_PROXY_PAC -#define NM_VPN_PLUGIN_CONFIG_PROXY_PAC "pac" + #define NM_VPN_PLUGIN_CONFIG_PROXY_PAC "pac" #endif #ifndef NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES -#define NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES "preserve-routes" + #define NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES "preserve-routes" #endif #ifndef NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES -#define NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES "preserve-routes" + #define NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES "preserve-routes" #endif /*****************************************************************************/ #endif /* __NM_VPN_PLUGIN_MACROS_H__ */ - diff --git a/shared/nm-utils/nm-vpn-plugin-utils.c b/shared/nm-utils/nm-vpn-plugin-utils.c index 8616ae5f..1af640da 100644 --- a/shared/nm-utils/nm-vpn-plugin-utils.c +++ b/shared/nm-utils/nm-vpn-plugin-utils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2016, 2018 Red Hat, Inc. */ @@ -12,125 +12,127 @@ /*****************************************************************************/ NMVpnEditor * -nm_vpn_plugin_utils_load_editor (const char *module_name, - const char *factory_name, - NMVpnPluginUtilsEditorFactory editor_factory, - NMVpnEditorPlugin *editor_plugin, - NMConnection *connection, - gpointer user_data, - GError **error) +nm_vpn_plugin_utils_load_editor(const char * module_name, + const char * factory_name, + NMVpnPluginUtilsEditorFactory editor_factory, + NMVpnEditorPlugin * editor_plugin, + NMConnection * connection, + gpointer user_data, + GError ** error) { - static struct { - gpointer factory; - void *dl_module; - char *module_name; - char *factory_name; - } cached = { 0 }; - NMVpnEditor *editor; - gs_free char *module_path = NULL; - gs_free char *dirname = NULL; - Dl_info plugin_info; + static struct { + gpointer factory; + void * dl_module; + char * module_name; + char * factory_name; + } cached = {0}; + NMVpnEditor * editor; + gs_free char *module_path = NULL; + gs_free char *dirname = NULL; + Dl_info plugin_info; - g_return_val_if_fail (module_name, NULL); - g_return_val_if_fail (factory_name && factory_name[0], NULL); - g_return_val_if_fail (editor_factory, NULL); - g_return_val_if_fail (NM_IS_VPN_EDITOR_PLUGIN (editor_plugin), NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (!error || !*error, NULL); + g_return_val_if_fail(module_name, NULL); + g_return_val_if_fail(factory_name && factory_name[0], NULL); + g_return_val_if_fail(editor_factory, NULL); + g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(editor_plugin), NULL); + g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL); + g_return_val_if_fail(!error || !*error, NULL); - if (!g_path_is_absolute (module_name)) { - /* - * Load an editor from the same directory this plugin is in. - * Ideally, we'd get our .so name from the NMVpnEditorPlugin if it - * would just have a property with it... - */ - if (!dladdr(nm_vpn_plugin_utils_load_editor, &plugin_info)) { - /* Really a "can not happen" scenario. */ - g_set_error (error, - NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_FAILED, - _("unable to get editor plugin name: %s"), dlerror ()); - } + if (!g_path_is_absolute(module_name)) { + /* + * Load an editor from the same directory this plugin is in. + * Ideally, we'd get our .so name from the NMVpnEditorPlugin if it + * would just have a property with it... + */ + if (!dladdr(nm_vpn_plugin_utils_load_editor, &plugin_info)) { + /* Really a "can not happen" scenario. */ + g_set_error(error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("unable to get editor plugin name: %s"), + dlerror()); + } - dirname = g_path_get_dirname (plugin_info.dli_fname); - module_path = g_build_filename (dirname, module_name, NULL); - } else { - module_path = g_strdup (module_name); - } + dirname = g_path_get_dirname(plugin_info.dli_fname); + module_path = g_build_filename(dirname, module_name, NULL); + } else { + module_path = g_strdup(module_name); + } - /* we really expect this function to be called with unchanging @module_name - * and @factory_name. And we only want to load the module once, hence it would - * be more complicated to accept changing @module_name/@factory_name arguments. - * - * The reason for only loading once is that due to glib types, we cannot create a - * certain type-name more then once, so loading the same module or another version - * of the same module will fail horribly as both try to create a GType with the same - * name. - * - * Only support loading once, any future calls will reuse the handle. To simplify - * that, we enforce that the @factory_name and @module_name is the same. */ - if (cached.factory) { - g_return_val_if_fail (cached.dl_module, NULL); - g_return_val_if_fail (cached.factory_name && nm_streq0 (cached.factory_name, factory_name), NULL); - g_return_val_if_fail (cached.module_name && nm_streq0 (cached.module_name, module_name), NULL); - } else { - gpointer factory; - void *dl_module; + /* we really expect this function to be called with unchanging @module_name + * and @factory_name. And we only want to load the module once, hence it would + * be more complicated to accept changing @module_name/@factory_name arguments. + * + * The reason for only loading once is that due to glib types, we cannot create a + * certain type-name more then once, so loading the same module or another version + * of the same module will fail horribly as both try to create a GType with the same + * name. + * + * Only support loading once, any future calls will reuse the handle. To simplify + * that, we enforce that the @factory_name and @module_name is the same. */ + if (cached.factory) { + g_return_val_if_fail(cached.dl_module, NULL); + g_return_val_if_fail(cached.factory_name && nm_streq0(cached.factory_name, factory_name), + NULL); + g_return_val_if_fail(cached.module_name && nm_streq0(cached.module_name, module_name), + NULL); + } else { + gpointer factory; + void * dl_module; - dl_module = dlopen (module_path, RTLD_LAZY | RTLD_LOCAL); - if (!dl_module) { - if (!g_file_test (module_path, G_FILE_TEST_EXISTS)) { - g_set_error (error, - G_FILE_ERROR, - G_FILE_ERROR_NOENT, - _("missing plugin file \"%s\""), module_path); - return NULL; - } - g_set_error (error, - NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_FAILED, - _("cannot load editor plugin: %s"), dlerror ()); - return NULL; - } + dl_module = dlopen(module_path, RTLD_LAZY | RTLD_LOCAL); + if (!dl_module) { + if (!g_file_test(module_path, G_FILE_TEST_EXISTS)) { + g_set_error(error, + G_FILE_ERROR, + G_FILE_ERROR_NOENT, + _("missing plugin file \"%s\""), + module_path); + return NULL; + } + g_set_error(error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("cannot load editor plugin: %s"), + dlerror()); + return NULL; + } - factory = dlsym (dl_module, factory_name); - if (!factory) { - g_set_error (error, - NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_FAILED, - _("cannot load factory %s from plugin: %s"), - factory_name, dlerror ()); - dlclose (dl_module); - return NULL; - } + factory = dlsym(dl_module, factory_name); + if (!factory) { + g_set_error(error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("cannot load factory %s from plugin: %s"), + factory_name, + dlerror()); + dlclose(dl_module); + return NULL; + } - /* we cannot ever unload the module because it creates glib types, which - * cannot be unregistered. - * - * Thus we just leak the dl_module handle indefinitely. */ - cached.factory = factory; - cached.dl_module = dl_module; - cached.module_name = g_strdup (module_name); - cached.factory_name = g_strdup (factory_name); - } + /* we cannot ever unload the module because it creates glib types, which + * cannot be unregistered. + * + * Thus we just leak the dl_module handle indefinitely. */ + cached.factory = factory; + cached.dl_module = dl_module; + cached.module_name = g_strdup(module_name); + cached.factory_name = g_strdup(factory_name); + } - editor = editor_factory (cached.factory, - editor_plugin, - connection, - user_data, - error); - if (!editor) { - if (error && !*error ) { - g_set_error_literal (error, - NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_FAILED, - _("unknown error creating editor instance")); - g_return_val_if_reached (NULL); - } - return NULL; - } + editor = editor_factory(cached.factory, editor_plugin, connection, user_data, error); + if (!editor) { + if (error && !*error) { + g_set_error_literal(error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("unknown error creating editor instance")); + g_return_val_if_reached(NULL); + } + return NULL; + } - g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), NULL); - return editor; + g_return_val_if_fail(NM_IS_VPN_EDITOR(editor), NULL); + return editor; } diff --git a/shared/nm-utils/nm-vpn-plugin-utils.h b/shared/nm-utils/nm-vpn-plugin-utils.h index 2a31b677..0e5e1dab 100644 --- a/shared/nm-utils/nm-vpn-plugin-utils.h +++ b/shared/nm-utils/nm-vpn-plugin-utils.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2016 Red Hat, Inc. */ @@ -8,19 +8,18 @@ #include <NetworkManager.h> -typedef NMVpnEditor *(NMVpnPluginUtilsEditorFactory) (gpointer factory, - NMVpnEditorPlugin *editor_plugin, - NMConnection *connection, - gpointer user_data, - GError **error); +typedef NMVpnEditor *(NMVpnPluginUtilsEditorFactory)(gpointer factory, + NMVpnEditorPlugin *editor_plugin, + NMConnection * connection, + gpointer user_data, + GError ** error); -NMVpnEditor *nm_vpn_plugin_utils_load_editor (const char *module_name, - const char *factory_name, - NMVpnPluginUtilsEditorFactory editor_factory, - NMVpnEditorPlugin *editor_plugin, - NMConnection *connection, - gpointer user_data, - GError **error); +NMVpnEditor *nm_vpn_plugin_utils_load_editor(const char * module_name, + const char * factory_name, + NMVpnPluginUtilsEditorFactory editor_factory, + NMVpnEditorPlugin * editor_plugin, + NMConnection * connection, + gpointer user_data, + GError ** error); #endif /* __NM_VPN_PLUGIN_UTILS_H__ */ - diff --git a/shared/nm-version-macros.h b/shared/nm-version-macros.h index 629f1e32..6ee83041 100644 --- a/shared/nm-version-macros.h +++ b/shared/nm-version-macros.h @@ -22,7 +22,7 @@ * Evaluates to the minor version number of NetworkManager which this source * is compiled against. */ -#define NM_MINOR_VERSION (26) +#define NM_MINOR_VERSION (27) /** * NM_MICRO_VERSION: @@ -30,7 +30,7 @@ * Evaluates to the micro version number of NetworkManager which this source * compiled against. */ -#define NM_MICRO_VERSION (2) +#define NM_MICRO_VERSION (90) /** * NM_CHECK_VERSION: @@ -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/nm-version-macros.h.in b/shared/nm-version-macros.h.in index 83da86ce..c4d6efbc 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-logging-stub.c b/shared/systemd/nm-logging-stub.c index 64a96daa..fa2328f3 100644 --- a/shared/systemd/nm-logging-stub.c +++ b/shared/systemd/nm-logging-stub.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -10,31 +10,27 @@ /*****************************************************************************/ gboolean -_nm_log_enabled_impl (gboolean mt_require_locking, - NMLogLevel level, - NMLogDomain domain) +_nm_log_enabled_impl(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain) { - return FALSE; + return FALSE; } void -_nm_log_impl (const char *file, - guint line, - const char *func, - gboolean mt_require_locking, - NMLogLevel level, - NMLogDomain domain, - int error, - const char *ifname, - const char *con_uuid, - const char *fmt, - ...) -{ -} +_nm_log_impl(const char *file, + guint line, + const char *func, + gboolean mt_require_locking, + NMLogLevel level, + NMLogDomain domain, + int error, + const char *ifname, + const char *con_uuid, + const char *fmt, + ...) +{} void -_nm_utils_monotonic_timestamp_initialized (const struct timespec *tp, - gint64 offset_sec, - gboolean is_boottime) -{ -} +_nm_utils_monotonic_timestamp_initialized(const struct timespec *tp, + gint64 offset_sec, + gboolean is_boottime) +{} diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c index 4fe82ca0..83c91af7 100644 --- a/shared/systemd/nm-sd-utils-shared.c +++ b/shared/systemd/nm-sd-utils-shared.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -22,32 +22,31 @@ const bool mempool_use_allowed = true; /*****************************************************************************/ gboolean -nm_sd_utils_path_equal (const char *a, const char *b) +nm_sd_utils_path_equal(const char *a, const char *b) { - return path_equal (a, b); + return path_equal(a, b); } char * -nm_sd_utils_path_simplify (char *path, gboolean kill_dots) +nm_sd_utils_path_simplify(char *path, gboolean kill_dots) { - return path_simplify (path, kill_dots); + return path_simplify(path, kill_dots); } const char * -nm_sd_utils_path_startswith (const char *path, const char *prefix) +nm_sd_utils_path_startswith(const char *path, const char *prefix) { - return path_startswith (path, prefix); + return path_startswith(path, prefix); } /*****************************************************************************/ int -nm_sd_utils_unbase64char (char ch, gboolean accept_padding_equal) +nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal) { - if ( ch == '=' - && accept_padding_equal) - return G_MAXINT; - return unbase64char (ch); + if (ch == '=' && accept_padding_equal) + return G_MAXINT; + return unbase64char(ch); } /** @@ -57,7 +56,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. * @@ -69,111 +68,105 @@ nm_sd_utils_unbase64char (char ch, gboolean accept_padding_equal) * function fail. */ int -nm_sd_utils_unbase64mem (const char *p, - size_t l, - gboolean secure, - guint8 **mem, - size_t *len) +nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len) { - return unbase64mem_full (p, l, secure, (void **) mem, len); + return unbase64mem_full(p, l, secure, (void **) mem, len); } -int nm_sd_dns_name_to_wire_format (const char *domain, - guint8 *buffer, - size_t len, - gboolean canonical) +int +nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical) { - return dns_name_to_wire_format (domain, buffer, len, canonical); + return dns_name_to_wire_format(domain, buffer, len, canonical); } -int nm_sd_dns_name_is_valid (const char *s) +int +nm_sd_dns_name_is_valid(const char *s) { - return dns_name_is_valid (s); + return dns_name_is_valid(s); } -gboolean nm_sd_hostname_is_valid (const char *s, bool allow_trailing_dot) +gboolean +nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot) { - return hostname_is_valid (s, allow_trailing_dot); + return hostname_is_valid(s, allow_trailing_dot); } /*****************************************************************************/ static gboolean -_http_url_is_valid (const char *url, gboolean only_https) +_http_url_is_valid(const char *url, gboolean only_https) { - if ( !url - || !url[0]) - return FALSE; - - if ( !only_https - && NM_STR_HAS_PREFIX (url, "http://")) - url += NM_STRLEN ("http://"); - else if (NM_STR_HAS_PREFIX (url, "https://")) - url += NM_STRLEN ("https://"); - else - return FALSE; - - if (!url[0]) - return FALSE; - - return !NM_STRCHAR_ANY (url, ch, (guchar) ch >= 128u); + if (!url || !url[0]) + return FALSE; + + if (!only_https && NM_STR_HAS_PREFIX(url, "http://")) + url += NM_STRLEN("http://"); + else if (NM_STR_HAS_PREFIX(url, "https://")) + url += NM_STRLEN("https://"); + else + return FALSE; + + if (!url[0]) + return FALSE; + + return !NM_STRCHAR_ANY(url, ch, (guchar) ch >= 128u); } gboolean -nm_sd_http_url_is_valid_https (const char *url) +nm_sd_http_url_is_valid_https(const char *url) { - /* We use this function to verify connection:mud-url property, it must thus - * not change behavior. - * - * Note that sd_dhcp_client_set_mud_url() and sd_dhcp6_client_set_request_mud_url() - * assert with http_url_is_valid() that the argument is valid. We thus must make - * sure to only pass URLs that are valid according to http_url_is_valid(). - * - * This is given, because our nm_sd_http_url_is_valid_https() is more strict - * than http_url_is_valid(). - * - * We only must make sure that this is also correct in the future, when we - * re-import systemd code. */ - nm_assert (_http_url_is_valid (url, FALSE) == http_url_is_valid (url)); - return _http_url_is_valid (url, TRUE); + /* We use this function to verify connection:mud-url property, it must thus + * not change behavior. + * + * Note that sd_dhcp_client_set_mud_url() and sd_dhcp6_client_set_request_mud_url() + * assert with http_url_is_valid() that the argument is valid. We thus must make + * sure to only pass URLs that are valid according to http_url_is_valid(). + * + * This is given, because our nm_sd_http_url_is_valid_https() is more strict + * than http_url_is_valid(). + * + * We only must make sure that this is also correct in the future, when we + * re-import systemd code. */ + nm_assert(_http_url_is_valid(url, FALSE) == http_url_is_valid(url)); + return _http_url_is_valid(url, TRUE); } /*****************************************************************************/ int -nmtst_systemd_extract_first_word_all (const char *str, char ***out_strv) +nmtst_systemd_extract_first_word_all(const char *str, char ***out_strv) { - gs_unref_ptrarray GPtrArray *arr = NULL; + gs_unref_ptrarray GPtrArray *arr = NULL; - /* we implement a str split function to parse `/proc/cmdline`. This - * code should behave like systemd, which uses extract_first_word() - * for that. - * - * As we want to unit-test our implementation to match systemd, - * expose this function for testing. */ + /* we implement a str split function to parse `/proc/cmdline`. This + * code should behave like systemd, which uses extract_first_word() + * for that. + * + * As we want to unit-test our implementation to match systemd, + * expose this function for testing. */ - g_assert (out_strv); - g_assert (!*out_strv); + g_assert(out_strv); + g_assert(!*out_strv); - if (!str) - return 0; + if (!str) + return 0; - arr = g_ptr_array_new_with_free_func (g_free); + arr = g_ptr_array_new_with_free_func(g_free); - for (;;) { - gs_free char *word = NULL; - int r; + for (;;) { + gs_free char *word = NULL; + int r; - r = extract_first_word (&str, &word, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX); - if (r < 0) - return r; - if (r == 0) - break; - g_ptr_array_add (arr, g_steal_pointer (&word)); - } + r = extract_first_word(&str, &word, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX); + if (r < 0) + return r; + if (r == 0) + break; + g_ptr_array_add(arr, g_steal_pointer(&word)); + } - g_ptr_array_add (arr, NULL); + g_ptr_array_add(arr, NULL); - *out_strv = (char **) g_ptr_array_free (g_steal_pointer (&arr), FALSE); - return 1; + *out_strv = (char **) g_ptr_array_free(g_steal_pointer(&arr), FALSE); + return 1; } diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h index 75e38b84..b871fc29 100644 --- a/shared/systemd/nm-sd-utils-shared.h +++ b/shared/systemd/nm-sd-utils-shared.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -8,38 +8,32 @@ /*****************************************************************************/ -gboolean nm_sd_utils_path_equal (const char *a, const char *b); +gboolean nm_sd_utils_path_equal(const char *a, const char *b); -char *nm_sd_utils_path_simplify (char *path, gboolean kill_dots); +char *nm_sd_utils_path_simplify(char *path, gboolean kill_dots); -const char *nm_sd_utils_path_startswith (const char *path, const char *prefix); +const char *nm_sd_utils_path_startswith(const char *path, const char *prefix); /*****************************************************************************/ -int nm_sd_utils_unbase64char (char ch, gboolean accept_padding_equal); +int nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal); -int nm_sd_utils_unbase64mem (const char *p, - size_t l, - gboolean secure, - guint8 **mem, - size_t *len); +int nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len); /*****************************************************************************/ -int nm_sd_dns_name_to_wire_format (const char *domain, - guint8 *buffer, - size_t len, - gboolean canonical); +int +nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical); -int nm_sd_dns_name_is_valid (const char *s); +int nm_sd_dns_name_is_valid(const char *s); gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot); /*****************************************************************************/ -gboolean nm_sd_http_url_is_valid_https (const char *url); +gboolean nm_sd_http_url_is_valid_https(const char *url); /*****************************************************************************/ -int nmtst_systemd_extract_first_word_all (const char *str, char ***out_strv); +int nmtst_systemd_extract_first_word_all(const char *str, char ***out_strv); #endif /* __NM_SD_UTILS_SHARED_H__ */ 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 e2378c5b..a937a889 100644 --- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h +++ b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: LGPL-2.1+ +/* SPDX-License-Identifier: LGPL-2.1+ */ /* * Copyright (C) 2014 - 2018 Red Hat, Inc. */ @@ -13,7 +13,7 @@ /*****************************************************************************/ /* strerror() is not thread-safe. Patch systemd-sources via a define. */ -#define strerror(errsv) nm_strerror_native (errsv) +#define strerror(errsv) nm_strerror_native(errsv) /*****************************************************************************/ @@ -29,49 +29,91 @@ /*****************************************************************************/ static inline int -_nm_log_get_max_level_realm (void) +_nm_log_get_max_level_realm(void) { - /* inline function, to avoid coverity warning about constant expression. */ - return 7 /* LOG_DEBUG */; + /* inline function, to avoid coverity warning about constant expression. */ + return 7 /* LOG_DEBUG */; } -#define log_get_max_level_realm(realm) _nm_log_get_max_level_realm () - -#define log_internal_realm(level, error, file, line, func, format, ...) \ -({ \ - const int _nm_e = (error); \ - const NMLogLevel _nm_l = nm_log_level_from_syslog (LOG_PRI (level)); \ - \ - if (_nm_log_enabled_impl (!(NM_THREAD_SAFE_ON_MAIN_THREAD), _nm_l, LOGD_SYSTEMD)) { \ - const char *_nm_location = strrchr ((""file), '/'); \ - \ - _nm_log_impl (_nm_location ? _nm_location + 1 : (""file), (line), (func), !(NM_THREAD_SAFE_ON_MAIN_THREAD), _nm_l, LOGD_SYSTEMD, _nm_e, NULL, NULL, ("%s"format), "libsystemd: ", ## __VA_ARGS__); \ - } \ - (_nm_e > 0 ? -_nm_e : _nm_e); \ -}) - -#define log_assert_failed(text, file, line, func) \ -G_STMT_START { \ - log_internal (LOG_CRIT, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.", text, file, line, func); \ - g_assert_not_reached (); \ -} G_STMT_END - -#define log_assert_failed_unreachable(text, file, line, func) \ -G_STMT_START { \ - log_internal (LOG_CRIT, 0, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", text, file, line, func); \ - g_assert_not_reached (); \ -} G_STMT_END - -#define log_assert_failed_return(text, file, line, func) \ -({ \ - log_internal (LOG_DEBUG, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", text, file, line, func); \ - g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, text); \ - (void) 0; \ -}) +#define log_get_max_level_realm(realm) _nm_log_get_max_level_realm() + +#define log_internal_realm(level, error, file, line, func, format, ...) \ + ({ \ + const int _nm_e = (error); \ + const NMLogLevel _nm_l = nm_log_level_from_syslog(LOG_PRI(level)); \ + \ + if (_nm_log_enabled_impl(!(NM_THREAD_SAFE_ON_MAIN_THREAD), _nm_l, LOGD_SYSTEMD)) { \ + const char *_nm_location = strrchr(("" file), '/'); \ + \ + _nm_log_impl(_nm_location ? _nm_location + 1 : ("" file), \ + (line), \ + (func), \ + !(NM_THREAD_SAFE_ON_MAIN_THREAD), \ + _nm_l, \ + LOGD_SYSTEMD, \ + _nm_e, \ + NULL, \ + NULL, \ + ("%s" format), \ + "libsystemd: ", \ + ##__VA_ARGS__); \ + } \ + (_nm_e > 0 ? -_nm_e : _nm_e); \ + }) + +#define log_assert_failed(text, file, line, func) \ + G_STMT_START \ + { \ + log_internal(LOG_CRIT, \ + 0, \ + file, \ + line, \ + func, \ + "Assertion '%s' failed at %s:%u, function %s(). Aborting.", \ + text, \ + file, \ + line, \ + func); \ + g_assert_not_reached(); \ + } \ + G_STMT_END + +#define log_assert_failed_unreachable(text, file, line, func) \ + G_STMT_START \ + { \ + log_internal(LOG_CRIT, \ + 0, \ + file, \ + line, \ + func, \ + "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", \ + text, \ + file, \ + line, \ + func); \ + g_assert_not_reached(); \ + } \ + G_STMT_END + +#define log_assert_failed_return(text, file, line, func) \ + ({ \ + log_internal(LOG_DEBUG, \ + 0, \ + file, \ + line, \ + func, \ + "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", \ + text, \ + file, \ + line, \ + func); \ + g_return_if_fail_warning(G_LOG_DOMAIN, G_STRFUNC, text); \ + (void) 0; \ + }) /*****************************************************************************/ #ifndef VALGRIND -#define VALGRIND 0 + #define VALGRIND 0 #endif #define ENABLE_DEBUG_HASHMAP 0 @@ -83,66 +125,71 @@ G_STMT_START { \ #if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD -#include <sys/syscall.h> -#include <sys/ioctl.h> + #include <sys/syscall.h> + #include <sys/ioctl.h> -#define ENABLE_GSHADOW FALSE + #define ENABLE_GSHADOW FALSE + + #define HAVE_SECCOMP 0 /*****************************************************************************/ /* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular - * in combintation with assert_cc(). */ -NM_PRAGMA_WARNING_DISABLE ("-Wdeclaration-after-statement") + * in combination with assert_cc(). */ +NM_PRAGMA_WARNING_DISABLE("-Wdeclaration-after-statement") /*****************************************************************************/ static inline pid_t -raw_getpid (void) { -#if defined(__alpha__) - return (pid_t) syscall (__NR_getxpid); -#else - return (pid_t) syscall (__NR_getpid); -#endif +raw_getpid(void) +{ + #if defined(__alpha__) + return (pid_t) syscall(__NR_getxpid); + #else + return (pid_t) syscall(__NR_getpid); + #endif } -static inline pid_t _nm_gettid(void) { - return (pid_t) syscall(SYS_gettid); +static inline pid_t +_nm_gettid(void) +{ + return (pid_t) syscall(SYS_gettid); } -#define gettid() _nm_gettid () - -/* we build with C11 and thus <uchar.h> provides char32_t,char16_t. */ -#define HAVE_CHAR32_T 1 -#define HAVE_CHAR16_T 1 - -#if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1 -#define HAVE_REALLOCARRAY 1 -#else -#define HAVE_REALLOCARRAY 0 -#endif - -#if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1 -#define HAVE_EXPLICIT_BZERO 1 -#else -#define HAVE_EXPLICIT_BZERO 0 -#endif - -#if defined(HAVE_DECL_PIDFD_OPEN) && HAVE_DECL_PIDFD_OPEN == 1 -#define HAVE_PIDFD_OPEN 1 -#else -#define HAVE_PIDFD_OPEN 0 -#endif - -#if defined(HAVE_DECL_PIDFD_SEND_SIGNAL) && HAVE_DECL_PIDFD_SEND_SIGNAL == 1 -#define HAVE_PIDFD_SEND_SIGNAL 1 -#else -#define HAVE_PIDFD_SEND_SIGNAL 0 -#endif - -#if defined(HAVE_DECL_RT_SIGQUEUEINFO) && HAVE_DECL_RT_SIGQUEUEINFO == 1 -#define HAVE_RT_SIGQUEUEINFO 1 -#else -#define HAVE_RT_SIGQUEUEINFO 0 -#endif + #define gettid() _nm_gettid() + + /* we build with C11 and thus <uchar.h> provides char32_t,char16_t. */ + #define HAVE_CHAR32_T 1 + #define HAVE_CHAR16_T 1 + + #if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1 + #define HAVE_REALLOCARRAY 1 + #else + #define HAVE_REALLOCARRAY 0 + #endif + + #if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1 + #define HAVE_EXPLICIT_BZERO 1 + #else + #define HAVE_EXPLICIT_BZERO 0 + #endif + + #if defined(HAVE_DECL_PIDFD_OPEN) && HAVE_DECL_PIDFD_OPEN == 1 + #define HAVE_PIDFD_OPEN 1 + #else + #define HAVE_PIDFD_OPEN 0 + #endif + + #if defined(HAVE_DECL_PIDFD_SEND_SIGNAL) && HAVE_DECL_PIDFD_SEND_SIGNAL == 1 + #define HAVE_PIDFD_SEND_SIGNAL 1 + #else + #define HAVE_PIDFD_SEND_SIGNAL 0 + #endif + + #if defined(HAVE_DECL_RT_SIGQUEUEINFO) && HAVE_DECL_RT_SIGQUEUEINFO == 1 + #define HAVE_RT_SIGQUEUEINFO 1 + #else + #define HAVE_RT_SIGQUEUEINFO 0 + #endif #endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */ diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c index 30ee135a..1e93f18e 100644 --- a/shared/systemd/src/basic/env-file.c +++ b/shared/systemd/src/basic/env-file.c @@ -211,17 +211,21 @@ static int parse_env_file_internal( case DOUBLE_QUOTE_VALUE_ESCAPE: state = DOUBLE_QUOTE_VALUE; - if (c == '"') { + if (strchr(SHELL_NEED_ESCAPE, c)) { + /* If this is a char that needs escaping, just unescape it. */ if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; - value[n_value++] = '"'; - } else if (!strchr(NEWLINE, c)) { + value[n_value++] = c; + } else if (c != '\n') { + /* If other char than what needs escaping, keep the "\" in place, like the + * real shell does. */ if (!GREEDY_REALLOC(value, value_alloc, n_value+3)) return -ENOMEM; value[n_value++] = '\\'; value[n_value++] = c; } + /* Escaped newlines (aka "continuation lines") are eaten up entirely */ break; case COMMENT: diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c index d16890d9..11f4b29b 100644 --- a/shared/systemd/src/basic/env-util.c +++ b/shared/systemd/src/basic/env-util.c @@ -690,7 +690,7 @@ char **replace_env_argv(char **argv, char **env) { if (e) { int r; - r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE); + r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE); if (r < 0) { ret[k] = NULL; strv_free(ret); @@ -744,7 +744,6 @@ int getenv_bool(const char *p) { return parse_boolean(e); } -#if 0 /* NM_IGNORED */ int getenv_bool_secure(const char *p) { const char *e; @@ -754,4 +753,3 @@ int getenv_bool_secure(const char *p) { return parse_boolean(e); } -#endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/escape.c b/shared/systemd/src/basic/escape.c index 1ea0b6a6..1261fd48 100644 --- a/shared/systemd/src/basic/escape.c +++ b/shared/systemd/src/basic/escape.c @@ -77,7 +77,7 @@ int cescape_char(char c, char *buf) { return buf - buf_old; } -char *cescape_length(const char *s, size_t n) { +char* cescape_length(const char *s, size_t n) { const char *f; char *r, *t; @@ -98,7 +98,7 @@ char *cescape_length(const char *s, size_t n) { return r; } -char *cescape(const char *s) { +char* cescape(const char *s) { assert(s); return cescape_length(s, strlen(s)); @@ -363,7 +363,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return t - r; } -char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) { +char* xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) { char *ans, *t, *prev, *prev2; const char *f; @@ -430,7 +430,7 @@ char *xescape_full(const char *s, const char *bad, size_t console_width, bool ei return ans; } -char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) { +char* escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) { if (eight_bit) return xescape_full(str, "", console_width, true); else @@ -438,7 +438,7 @@ char *escape_non_printable_full(const char *str, size_t console_width, bool eigh } #endif /* NM_IGNORED */ -char *octescape(const char *s, size_t len) { +char* octescape(const char *s, size_t len) { char *r, *t; const char *f; @@ -466,7 +466,7 @@ char *octescape(const char *s, size_t len) { } -static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) { +static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) { assert(bad); for (; *s; s++) { @@ -485,7 +485,7 @@ static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad, b return t; } -char *shell_escape(const char *s, const char *bad) { +char* shell_escape(const char *s, const char *bad) { char *r, *t; r = new(char, strlen(s)*2+1); diff --git a/shared/systemd/src/basic/escape.h b/shared/systemd/src/basic/escape.h index 0b00b116..fa267813 100644 --- a/shared/systemd/src/basic/escape.h +++ b/shared/systemd/src/basic/escape.h @@ -43,8 +43,8 @@ typedef enum EscapeStyle { * syntax (a string enclosed in $'') instead of plain quotes. */ } EscapeStyle; -char *cescape(const char *s); -char *cescape_length(const char *s, size_t n); +char* cescape(const char *s); +char* cescape_length(const char *s, size_t n); int cescape_char(char c, char *buf); int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); @@ -56,12 +56,12 @@ static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) { } int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul); -char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits); -static inline char *xescape(const char *s, const char *bad) { +char* xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits); +static inline char* xescape(const char *s, const char *bad) { return xescape_full(s, bad, SIZE_MAX, false); } -char *octescape(const char *s, size_t len); -char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit); +char* octescape(const char *s, size_t len); +char* escape_non_printable_full(const char *str, size_t console_width, bool eight_bit); -char *shell_escape(const char *s, const char *bad); +char* shell_escape(const char *s, const char *bad); char* shell_maybe_quote(const char *s, EscapeStyle style); diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c index 62f015f3..e32b4c7f 100644 --- a/shared/systemd/src/basic/extract-word.c +++ b/shared/systemd/src/basic/extract-word.c @@ -16,6 +16,7 @@ #include "log.h" #include "macro.h" #include "string-util.h" +#include "strv.h" #include "utf8.h" int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { @@ -88,25 +89,30 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra return -EINVAL; } - if (flags & EXTRACT_CUNESCAPE) { + if (flags & (EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS)) { bool eight_bit = false; char32_t u; - r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false); - if (r < 0) { - if (flags & EXTRACT_CUNESCAPE_RELAX) { - s[sz++] = '\\'; - s[sz++] = c; - } else - return -EINVAL; - } else { + if ((flags & EXTRACT_CUNESCAPE) && + (r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false)) >= 0) { + /* A valid escaped sequence */ + assert(r >= 1); + (*p) += r - 1; if (eight_bit) s[sz++] = u; else sz += utf8_encode_unichar(s + sz, u); - } + } else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) && + strchr(separators, **p)) + /* An escaped separator char */ + s[sz++] = c; + else if (flags & EXTRACT_CUNESCAPE_RELAX) { + s[sz++] = '\\'; + s[sz++] = c; + } else + return -EINVAL; } else s[sz++] = c; diff --git a/shared/systemd/src/basic/extract-word.h b/shared/systemd/src/basic/extract-word.h index e2d43389..f028577c 100644 --- a/shared/systemd/src/basic/extract-word.h +++ b/shared/systemd/src/basic/extract-word.h @@ -7,9 +7,10 @@ typedef enum ExtractFlags { EXTRACT_RELAX = 1 << 0, EXTRACT_CUNESCAPE = 1 << 1, EXTRACT_CUNESCAPE_RELAX = 1 << 2, - EXTRACT_UNQUOTE = 1 << 3, - EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 4, - EXTRACT_RETAIN_ESCAPE = 1 << 5, + EXTRACT_UNESCAPE_SEPARATORS = 1 << 3, + EXTRACT_UNQUOTE = 1 << 4, + EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, + EXTRACT_RETAIN_ESCAPE = 1 << 6, } ExtractFlags; int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c index a401663e..525d3828 100644 --- a/shared/systemd/src/basic/fd-util.c +++ b/shared/systemd/src/basic/fd-util.c @@ -379,6 +379,7 @@ bool fdname_is_valid(const char *s) { return p - s < 256; } +#if 0 /* NM_IGNORED */ int fd_get_path(int fd, char **ret) { char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; int r; @@ -389,18 +390,15 @@ int fd_get_path(int fd, char **ret) { /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make * things debuggable and distinguish the two. */ - if (access("/proc/self/fd/", F_OK) < 0) - /* /proc is not available or not set up properly, we're most likely in some chroot - * environment. */ - return errno == ENOENT ? -EOPNOTSUPP : -errno; - + if (proc_mounted() == 0) + return -ENOSYS; /* /proc is not available or not set up properly, we're most likely in some chroot + * environment. */ return -EBADF; /* The directory exists, hence it's the fd that doesn't. */ } return r; } -#if 0 /* NM_IGNORED */ int move_fd(int from, int to, int cloexec) { int r; @@ -736,8 +734,7 @@ int fd_duplicate_data_fd(int fd) { if (f != 0) return -errno; - safe_close(copy_fd); - copy_fd = TAKE_FD(tmp_fd); + CLOSE_AND_REPLACE(copy_fd, tmp_fd); remains = mfree(remains); remains_size = 0; @@ -872,8 +869,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_ goto finish; } - safe_close(null_fd); - null_fd = copy; + CLOSE_AND_REPLACE(null_fd, copy); } } @@ -983,7 +979,7 @@ int read_nr_open(void) { return v; } - /* If we fail, fallback to the hard-coded kernel limit of 1024 * 1024. */ + /* If we fail, fall back to the hard-coded kernel limit of 1024 * 1024. */ return 1024 * 1024; } #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h index e490753c..93ce95cd 100644 --- a/shared/systemd/src/basic/fd-util.h +++ b/shared/systemd/src/basic/fd-util.h @@ -93,6 +93,16 @@ static inline int make_null_stdio(void) { _fd_; \ }) +/* Like free_and_replace(), but for file descriptors */ +#define CLOSE_AND_REPLACE(a, b) \ + ({ \ + int *_fdp_ = &(a); \ + safe_close(*_fdp_); \ + *_fdp_ = TAKE_FD(b); \ + 0; \ + }) + + int fd_reopen(int fd, int flags); int read_nr_open(void); diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c index 30903263..664b894a 100644 --- a/shared/systemd/src/basic/fileio.c +++ b/shared/systemd/src/basic/fileio.c @@ -24,6 +24,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "socket-util.h" #include "stdio-util.h" #include "string-util.h" #include "tmpfile-util.h" @@ -486,13 +487,12 @@ int read_full_stream_full( assert(f); assert(ret_contents); assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)); - assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size); n_next = LINE_MAX; /* Start size */ fd = fileno(f); - if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's - * optimize our buffering) */ + if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's + * optimize our buffering */ if (fstat(fd, &st) < 0) return -errno; @@ -509,7 +509,7 @@ int read_full_stream_full( if (st.st_size > 0) n_next = st.st_size + 1; - if (flags & READ_FULL_FILE_SECURE) + if (flags & READ_FULL_FILE_WARN_WORLD_READABLE) (void) warn_file_is_world_accessible(filename, &st, NULL, 0); } } @@ -539,21 +539,18 @@ int read_full_stream_full( errno = 0; k = fread(buf + l, 1, n - l, f); - if (k > 0) - l += k; + + assert(k <= n - l); + l += k; if (ferror(f)) { r = errno_or_else(EIO); goto finalize; } - if (feof(f)) break; - /* We aren't expecting fread() to return a short read outside - * of (error && eof), assert buffer is full and enlarge buffer. - */ - assert(l == n); + assert(k > 0); /* we can't have read zero bytes because that would have been EOF */ /* Safety check */ if (n >= READ_FULL_BYTES_MAX) { @@ -565,12 +562,21 @@ int read_full_stream_full( } if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) { + _cleanup_free_ void *decoded = NULL; + size_t decoded_size; + buf[l++] = 0; if (flags & READ_FULL_FILE_UNBASE64) - r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size); + r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size); else - r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size); - goto finalize; + r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size); + if (r < 0) + goto finalize; + + if (flags & READ_FULL_FILE_SECURE) + explicit_bzero_safe(buf, n); + free_and_replace(buf, decoded); + n = l = decoded_size; } if (!ret_size) { @@ -607,8 +613,54 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag assert(contents); r = xfopenat(dir_fd, filename, "re", 0, &f); - if (r < 0) - return r; + if (r < 0) { + _cleanup_close_ int dfd = -1, sk = -1; + union sockaddr_union sa; + + /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */ + if (r != -ENXIO) + return r; + + /* If this is enabled, let's try to connect to it */ + if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET)) + return -ENXIO; + + if (dir_fd == AT_FDCWD) + r = sockaddr_un_set_path(&sa.un, filename); + else { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + /* If we shall operate relative to some directory, then let's use O_PATH first to + * open the socket inode, and then connect to it via /proc/self/fd/. We have to do + * this since there's not connectat() that takes a directory fd as first arg. */ + + dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC); + if (dfd < 0) + return -errno; + + xsprintf(procfs_path, "/proc/self/fd/%i", dfd); + r = sockaddr_un_set_path(&sa.un, procfs_path); + } + if (r < 0) + return r; + + sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (sk < 0) + return -errno; + + if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) + return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is + * not a socket after all */ + + if (shutdown(sk, SHUT_WR) < 0) + return -errno; + + f = fdopen(sk, "r"); + if (!f) + return -errno; + + TAKE_FD(sk); + } (void) __fsetlocking(f, FSETLOCKING_BYCALLER); @@ -894,6 +946,42 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root return search_and_fopen_internal(path, mode, root, s, _f); } + +int chase_symlinks_and_fopen_unlocked( + const char *path, + const char *root, + unsigned chase_flags, + const char *open_flags, + FILE **ret_file, + char **ret_path) { + + _cleanup_close_ int fd = -1; + _cleanup_free_ char *final_path = NULL; + int mode_flags, r; + FILE *f; + + assert(path); + assert(open_flags); + assert(ret_file); + + mode_flags = mode_to_flags(open_flags); + if (mode_flags < 0) + return mode_flags; + + fd = chase_symlinks_and_open(path, root, chase_flags, mode_flags, ret_path ? &final_path : NULL); + if (fd < 0) + return fd; + + r = fdopen_unlocked(fd, open_flags, &f); + if (r < 0) + return r; + TAKE_FD(fd); + + *ret_file = f; + if (ret_path) + *ret_path = TAKE_PTR(final_path); + return 0; +} #endif /* NM_IGNORED */ int fflush_and_check(FILE *f) { diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h index e2830b79..9cba5a90 100644 --- a/shared/systemd/src/basic/fileio.h +++ b/shared/systemd/src/basic/fileio.h @@ -32,9 +32,11 @@ typedef enum { } WriteStringFileFlags; typedef enum { - READ_FULL_FILE_SECURE = 1 << 0, - READ_FULL_FILE_UNBASE64 = 1 << 1, - READ_FULL_FILE_UNHEX = 1 << 2, + READ_FULL_FILE_SECURE = 1 << 0, /* erase any buffers we employ internally, after use */ + READ_FULL_FILE_UNBASE64 = 1 << 1, /* base64 decode what we read */ + READ_FULL_FILE_UNHEX = 1 << 2, /* hex decode what we read */ + READ_FULL_FILE_WARN_WORLD_READABLE = 1 << 3, /* if regular file, log at LOG_WARNING level if access mode above 0700 */ + READ_FULL_FILE_CONNECT_SOCKET = 1 << 4, /* if socket inode, connect to it and read off it */ } ReadFullFileFlags; int fopen_unlocked(const char *path, const char *options, FILE **ret); @@ -79,6 +81,14 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); +int chase_symlinks_and_fopen_unlocked( + const char *path, + const char *root, + unsigned chase_flags, + const char *open_flags, + FILE **ret_file, + char **ret_path); + int fflush_and_check(FILE *f); int fflush_sync_and_check(FILE *f); diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c index 75df913a..e50252cb 100644 --- a/shared/systemd/src/basic/fs-util.c +++ b/shared/systemd/src/basic/fs-util.c @@ -123,7 +123,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */ return -errno; - /* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fallback to the racy TOCTOU + /* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fall back to the racy TOCTOU * vulnerable accessat(F_OK) check followed by classic, replacing renameat(), we have nothing better. */ if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) @@ -234,6 +234,7 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { bool do_chown, do_chmod; struct stat st; + int r; /* Change ownership and access mode of the specified fd. Tries to do so safely, ensuring that at no * point in time the access mode is above the old access mode under the old ownership or the new @@ -264,65 +265,23 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { if (do_chown && do_chmod) { mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */ - if (((minimal ^ st.st_mode) & 07777) != 0) - if (fchmod_opath(fd, minimal & 07777) < 0) - return -errno; + if (((minimal ^ st.st_mode) & 07777) != 0) { + r = fchmod_opath(fd, minimal & 07777); + if (r < 0) + return r; + } } if (do_chown) if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0) return -errno; - if (do_chmod) - if (fchmod_opath(fd, mode & 07777) < 0) - return -errno; - - return do_chown || do_chmod; -} - -int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid) { - bool do_chown, do_chmod; - struct stat st; - - assert(path); - - /* Change ownership and access mode of the specified path, see description of fchmod_and_chown(). - * Should only be used on trusted paths. */ - - if (lstat(path, &st) < 0) - return -errno; - - do_chown = - (uid != UID_INVALID && st.st_uid != uid) || - (gid != GID_INVALID && st.st_gid != gid); - - do_chmod = - !S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */ - ((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) || - do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown() - * modifies the access mode too */ - - if (mode == MODE_INVALID) - mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */ - else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0) - return -EINVAL; /* insist on the right file type if it was specified */ - - if (do_chown && do_chmod) { - mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */ - - if (((minimal ^ st.st_mode) & 07777) != 0) - if (chmod(path, minimal & 07777) < 0) - return -errno; + if (do_chmod) { + r = fchmod_opath(fd, mode & 07777); + if (r < 0) + return r; } - if (do_chown) - if (lchown(path, uid, gid) < 0) - return -errno; - - if (do_chmod) - if (chmod(path, mode & 07777) < 0) - return -errno; - return do_chown || do_chmod; } @@ -358,6 +317,25 @@ int fchmod_opath(int fd, mode_t m) { return 0; } +int futimens_opath(int fd, const struct timespec ts[2]) { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + /* Similar to fchmod_path() but for futimens() */ + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + if (utimensat(AT_FDCWD, procfs_path, ts, 0) < 0) { + if (errno != ENOENT) + return -errno; + + if (proc_mounted() == 0) + return -ENOSYS; /* if we have no /proc/, the concept is not implementable */ + + return -ENOENT; + } + + return 0; +} + int stat_warn_permissions(const char *path, const struct stat *st) { assert(path); assert(st); @@ -771,7 +749,7 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK), "Detected unsafe path transition %s %s %s during canonicalization of %s.", - n1, special_glyph(SPECIAL_GLYPH_ARROW), n2, path); + strna(n1), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), path); } static int log_autofs_mount_point(int fd, const char *path, unsigned flags) { @@ -784,7 +762,7 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) { return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE), "Detected autofs mount point %s during canonicalization of %s.", - n1, path); + strna(n1), path); } int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) { @@ -1304,16 +1282,25 @@ int chase_symlinks_and_stat( int access_fd(int fd, int mode) { char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; - int r; /* Like access() but operates on an already open fd */ xsprintf(p, "/proc/self/fd/%i", fd); - r = access(p, mode); - if (r < 0) - return -errno; + if (access(p, mode) < 0) { + if (errno != ENOENT) + return -errno; - return r; + /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's + * make things debuggable and distinguish the two. */ + + if (proc_mounted() == 0) + return -ENOSYS; /* /proc is not available or not set up properly, we're most likely in some chroot + * environment. */ + + return -EBADF; /* The directory exists, hence it's the fd that doesn't. */ + } + + return 0; } void unlink_tempfilep(char (*p)[]) { @@ -1434,6 +1421,7 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) { return 0; } +#if 0 /* NM_IGNORED */ int fsync_directory_of_file(int fd) { _cleanup_free_ char *path = NULL; _cleanup_close_ int dfd = -1; @@ -1447,9 +1435,9 @@ int fsync_directory_of_file(int fd) { if (r < 0) { log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m", fd, - r == -EOPNOTSUPP ? ", ignoring" : ""); + r == -ENOSYS ? ", ignoring" : ""); - if (r == -EOPNOTSUPP) + if (r == -ENOSYS) /* If /proc is not available, we're most likely running in some * chroot environment, and syncing the directory is not very * important in that case. Let's just silently do nothing. */ @@ -1470,6 +1458,7 @@ int fsync_directory_of_file(int fd) { return 0; } +#endif /* NM_IGNORED */ int fsync_full(int fd) { int r, q; @@ -1587,7 +1576,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) { d = opendir(p); if (!d) { - if (errno == ENOENT) /* Doesn't have slaves */ + if (errno == ENOENT) /* Doesn't have underlying devices */ return false; return -errno; @@ -1603,7 +1592,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) { if (errno != 0) return -errno; - break; /* No more slaves */ + break; /* No more underlying devices */ } q = path_join(p, de->d_name); diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h index b184570f..241cc6ef 100644 --- a/shared/systemd/src/basic/fs-util.h +++ b/shared/systemd/src/basic/fs-util.h @@ -34,11 +34,12 @@ int readlink_and_make_absolute(const char *p, char **r); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid); -int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid); int fchmod_umask(int fd, mode_t mode); int fchmod_opath(int fd, mode_t m); +int futimens_opath(int fd, const struct timespec ts[2]); + int fd_warn_permissions(const char *path, int fd); int stat_warn_permissions(const char *path, const struct stat *st); @@ -80,7 +81,7 @@ enum { CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */ CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */ CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */ - CHASE_SAFE = 1 << 3, /* Return EPERM if we ever traverse from unprivileged to privileged files or directories */ + CHASE_SAFE = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */ CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */ CHASE_STEP = 1 << 5, /* Just execute a single step of the normalization */ CHASE_NOFOLLOW = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c index c0296bde..b57814e6 100644 --- a/shared/systemd/src/basic/hashmap.c +++ b/shared/systemd/src/basic/hashmap.c @@ -3,6 +3,7 @@ #include "nm-sd-adapt-shared.h" #include <errno.h> +#include <pthread.h> #include <stdint.h> #include <stdlib.h> @@ -21,7 +22,6 @@ #include "strv.h" #if ENABLE_DEBUG_HASHMAP -#include <pthread.h> #include "list.h" #endif @@ -191,7 +191,6 @@ assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3)); * a handful of directly stored entries in a hashmap. When a hashmap * outgrows direct storage, it gets its own key for indirect storage. */ static uint8_t shared_hash_key[HASH_KEY_SIZE]; -static bool shared_hash_key_initialized; /* Fields that all hashmap/set types must have */ struct HashmapBase { @@ -325,12 +324,12 @@ static void n_entries_dec(HashmapBase *h) { h->n_direct_entries--; } -static void *storage_ptr(HashmapBase *h) { +static void* storage_ptr(HashmapBase *h) { return h->has_indirect ? h->indirect.storage : h->direct.storage; } -static uint8_t *hash_key(HashmapBase *h) { +static uint8_t* hash_key(HashmapBase *h) { return h->has_indirect ? h->indirect.hash_key : shared_hash_key; } @@ -373,16 +372,16 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { memcpy(hash_key, current, sizeof(current)); } -static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { +static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) { return (struct hashmap_base_entry*) ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); } -static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { +static struct plain_hashmap_entry* plain_bucket_at(Hashmap *h, unsigned idx) { return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); } -static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) { +static struct ordered_hashmap_entry* ordered_bucket_at(OrderedHashmap *h, unsigned idx) { return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); } @@ -390,13 +389,13 @@ static struct set_entry *set_bucket_at(Set *h, unsigned idx) { return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx); } -static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) { +static struct ordered_hashmap_entry* bucket_at_swap(struct swap_entries *swap, unsigned idx) { return &swap->e[idx - _IDX_SWAP_BEGIN]; } /* Returns a pointer to the bucket at index idx. * Understands real indexes and swap indexes, hence "_virtual". */ -static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap, +static struct hashmap_base_entry* bucket_at_virtual(HashmapBase *h, struct swap_entries *swap, unsigned idx) { if (idx < _IDX_SWAP_BEGIN) return bucket_at(h, idx); @@ -407,7 +406,7 @@ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_ assert_not_reached("Invalid index"); } -static dib_raw_t *dib_raw_ptr(HashmapBase *h) { +static dib_raw_t* dib_raw_ptr(HashmapBase *h) { return (dib_raw_t*) ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); } @@ -505,7 +504,7 @@ static unsigned prev_idx(HashmapBase *h, unsigned idx) { return (n_buckets(h) + idx - 1U) % n_buckets(h); } -static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) { +static void* entry_value(HashmapBase *h, struct hashmap_base_entry *e) { switch (h->type) { case HASHMAP_TYPE_PLAIN: @@ -732,16 +731,12 @@ bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **ke return true; } -bool set_iterate(const Set *s, Iterator *i, void **value) { - return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL); -} - #define HASHMAP_FOREACH_IDX(idx, h, i) \ for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \ (idx != IDX_NIL); \ (idx) = hashmap_iterate_entry((h), &(i))) -IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h) { +IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h) { IteratedCache *cache; assert(h); @@ -770,7 +765,11 @@ static void reset_direct_storage(HashmapBase *h) { memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); } -static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { +static void shared_hash_key_initialize(void) { + random_bytes(shared_hash_key, sizeof(shared_hash_key)); +} + +static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; bool up; @@ -792,10 +791,8 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu reset_direct_storage(h); - if (!shared_hash_key_initialized) { - random_bytes(shared_hash_key, sizeof(shared_hash_key)); - shared_hash_key_initialized= true; - } + static pthread_once_t once = PTHREAD_ONCE_INIT; + assert_se(pthread_once(&once, shared_hash_key_initialize) == 0); #if ENABLE_DEBUG_HASHMAP h->debug.func = func; @@ -810,19 +807,19 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu } Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); + return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); } OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); + return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); } Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); + return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); } static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops, - enum HashmapType type HASHMAP_DEBUG_PARAMS) { + enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *q; assert(h); @@ -830,7 +827,7 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops if (*h) return 0; - q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); + q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); if (!q) return -ENOMEM; @@ -839,15 +836,25 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops } int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); } int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); } int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); +} + +int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS) { + int r; + + r = _ordered_hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS); + if (r < 0) + return r; + + return ordered_hashmap_put(*h, key, value); } static void hashmap_free_no_clear(HashmapBase *h) { @@ -868,7 +875,7 @@ static void hashmap_free_no_clear(HashmapBase *h) { free(h); } -HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) { +HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) { if (h) { _hashmap_clear(h, default_free_key, default_free_value); hashmap_free_no_clear(h); @@ -1249,6 +1256,30 @@ int set_put(Set *s, const void *key) { return hashmap_put_boldly(s, hash, &swap, true); } +int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS) { + int r; + + r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS); + if (r < 0) + return r; + + return set_put(*s, key); +} + +int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS) { + int r; + + r = _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_PASS_ARGS); + if (r <= 0) { + if (hash_ops && hash_ops->free_key) + hash_ops->free_key(key); + else + free(key); + } + + return r; +} + int hashmap_replace(Hashmap *h, const void *key, void *value) { struct swap_entries swap; struct plain_hashmap_entry *e; @@ -1301,7 +1332,7 @@ int hashmap_update(Hashmap *h, const void *key, void *value) { return 0; } -void *_hashmap_get(HashmapBase *h, const void *key) { +void* _hashmap_get(HashmapBase *h, const void *key) { struct hashmap_base_entry *e; unsigned hash, idx; @@ -1317,7 +1348,7 @@ void *_hashmap_get(HashmapBase *h, const void *key) { return entry_value(h, e); } -void *hashmap_get2(Hashmap *h, const void *key, void **key2) { +void* hashmap_get2(Hashmap *h, const void *key, void **key2) { struct plain_hashmap_entry *e; unsigned hash, idx; @@ -1346,7 +1377,7 @@ bool _hashmap_contains(HashmapBase *h, const void *key) { return bucket_scan(h, hash, key) != IDX_NIL; } -void *_hashmap_remove(HashmapBase *h, const void *key) { +void* _hashmap_remove(HashmapBase *h, const void *key) { struct hashmap_base_entry *e; unsigned hash, idx; void *data; @@ -1366,7 +1397,7 @@ void *_hashmap_remove(HashmapBase *h, const void *key) { return data; } -void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) { +void* hashmap_remove2(Hashmap *h, const void *key, void **rkey) { struct plain_hashmap_entry *e; unsigned hash, idx; void *data; @@ -1484,7 +1515,7 @@ int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_ return 0; } -void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value) { +void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value) { struct hashmap_base_entry *e; unsigned hash, idx; @@ -1514,7 +1545,7 @@ static unsigned find_first_entry(HashmapBase *h) { return hashmap_iterate_entry(h, &i); } -void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) { +void* _hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) { struct hashmap_base_entry *e; void *key, *data; unsigned idx; @@ -1689,13 +1720,13 @@ int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) { return 0; } -HashmapBase *_hashmap_copy(HashmapBase *h) { +HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) { HashmapBase *copy; int r; assert(h); - copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); + copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_PASS_ARGS); if (!copy) return NULL; @@ -1711,15 +1742,13 @@ HashmapBase *_hashmap_copy(HashmapBase *h) { assert_not_reached("Unknown hashmap type"); } - if (r < 0) { - _hashmap_free(copy, false, false); - return NULL; - } + if (r < 0) + return _hashmap_free(copy, false, false); return copy; } -char **_hashmap_get_strv(HashmapBase *h) { +char** _hashmap_get_strv(HashmapBase *h) { char **sv; Iterator i; unsigned idx, n; @@ -1736,7 +1765,7 @@ char **_hashmap_get_strv(HashmapBase *h) { return sv; } -void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { +void* ordered_hashmap_next(OrderedHashmap *h, const void *key) { struct ordered_hashmap_entry *e; unsigned hash, idx; @@ -1768,10 +1797,10 @@ int set_consume(Set *s, void *value) { } #if 0 /* NM_IGNORED */ -int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) { +int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) { int r; - r = hashmap_ensure_allocated(h, &string_hash_ops_free_free); + r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1803,14 +1832,14 @@ int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) { } #endif /* NM_IGNORED */ -int set_put_strdup(Set **s, const char *p) { +int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) { char *c; int r; assert(s); assert(p); - r = set_ensure_allocated(s, &string_hash_ops_free); + r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1824,14 +1853,14 @@ int set_put_strdup(Set **s, const char *p) { return set_consume(*s, c); } -int set_put_strdupv(Set **s, char **l) { +int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) { int n = 0, r; char **i; assert(s); STRV_FOREACH(i, l) { - r = set_put_strdup(s, *i); + r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1943,7 +1972,7 @@ int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void return 0; } -IteratedCache *iterated_cache_free(IteratedCache *cache) { +IteratedCache* iterated_cache_free(IteratedCache *cache) { if (cache) { free(cache->keys.ptr); free(cache->values.ptr); diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h index 230d3222..890f90a9 100644 --- a/shared/systemd/src/basic/hashmap.h +++ b/shared/systemd/src/basic/hashmap.h @@ -83,8 +83,8 @@ typedef struct { # define HASHMAP_DEBUG_PASS_ARGS #endif -Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); -OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +Hashmap* _hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) @@ -96,56 +96,55 @@ OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE 0; \ }) -HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); -static inline Hashmap *hashmap_free(Hashmap *h) { +HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); +static inline Hashmap* hashmap_free(Hashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); } -static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) { +static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); } -static inline Hashmap *hashmap_free_free(Hashmap *h) { +static inline Hashmap* hashmap_free_free(Hashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); } -static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) { +static inline OrderedHashmap* ordered_hashmap_free_free(OrderedHashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); } -static inline Hashmap *hashmap_free_free_key(Hashmap *h) { +static inline Hashmap* hashmap_free_free_key(Hashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); } -static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) { +static inline OrderedHashmap* ordered_hashmap_free_free_key(OrderedHashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); } -static inline Hashmap *hashmap_free_free_free(Hashmap *h) { +static inline Hashmap* hashmap_free_free_free(Hashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); } -static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) { +static inline OrderedHashmap* ordered_hashmap_free_free_free(OrderedHashmap *h) { return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); } -IteratedCache *iterated_cache_free(IteratedCache *cache); +IteratedCache* iterated_cache_free(IteratedCache *cache); int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries); -HashmapBase *_hashmap_copy(HashmapBase *h); -static inline Hashmap *hashmap_copy(Hashmap *h) { - return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h)); -} -static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) { - return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h)); -} +HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS); +#define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) +#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) -IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h); -static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) { +int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); +#define ordered_hashmap_ensure_put(s, ops, key, value) _ordered_hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) + +IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h); +static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) { return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); } -static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) { +static inline IteratedCache* ordered_hashmap_iterated_cache_new(OrderedHashmap *h) { return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); } @@ -154,7 +153,8 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void * return hashmap_put(PLAIN_HASHMAP(h), key, value); } -int hashmap_put_strdup(Hashmap **h, const char *k, const char *v); +int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS); +#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS) int hashmap_update(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { @@ -166,7 +166,7 @@ static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, vo return hashmap_replace(PLAIN_HASHMAP(h), key, value); } -void *_hashmap_get(HashmapBase *h, const void *key); +void* _hashmap_get(HashmapBase *h, const void *key); static inline void *hashmap_get(Hashmap *h, const void *key) { return _hashmap_get(HASHMAP_BASE(h), key); } @@ -174,7 +174,7 @@ static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) { return _hashmap_get(HASHMAP_BASE(h), key); } -void *hashmap_get2(Hashmap *h, const void *key, void **rkey); +void* hashmap_get2(Hashmap *h, const void *key, void **rkey); static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) { return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); } @@ -187,7 +187,7 @@ static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) return _hashmap_contains(HASHMAP_BASE(h), key); } -void *_hashmap_remove(HashmapBase *h, const void *key); +void* _hashmap_remove(HashmapBase *h, const void *key); static inline void *hashmap_remove(Hashmap *h, const void *key) { return _hashmap_remove(HASHMAP_BASE(h), key); } @@ -195,17 +195,17 @@ static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) { return _hashmap_remove(HASHMAP_BASE(h), key); } -void *hashmap_remove2(Hashmap *h, const void *key, void **rkey); +void* hashmap_remove2(Hashmap *h, const void *key, void **rkey); static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) { return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); } -void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value); +void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value); static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) { return _hashmap_remove_value(HASHMAP_BASE(h), key, value); } -static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { +static inline void* ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); } @@ -391,13 +391,13 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) { }) /* no hashmap_next */ -void *ordered_hashmap_next(OrderedHashmap *h, const void *key); +void* ordered_hashmap_next(OrderedHashmap *h, const void *key); -char **_hashmap_get_strv(HashmapBase *h); -static inline char **hashmap_get_strv(Hashmap *h) { +char** _hashmap_get_strv(HashmapBase *h); +static inline char** hashmap_get_strv(Hashmap *h) { return _hashmap_get_strv(HASHMAP_BASE(h)); } -static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { +static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) { return _hashmap_get_strv(HASHMAP_BASE(h)); } @@ -407,17 +407,25 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { * the entries were inserted. * It is safe to remove the current entry. */ -#define HASHMAP_FOREACH(e, h, i) \ - for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); ) - -#define ORDERED_HASHMAP_FOREACH(e, h, i) \ - for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); ) - -#define HASHMAP_FOREACH_KEY(e, k, h, i) \ - for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); ) - -#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \ - for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); ) +#define _HASHMAP_FOREACH(e, h, i) \ + for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), NULL); ) +#define HASHMAP_FOREACH(e, h) \ + _HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ)) + +#define _ORDERED_HASHMAP_FOREACH(e, h, i) \ + for (Iterator i = ITERATOR_FIRST; ordered_hashmap_iterate((h), &i, (void**)&(e), NULL); ) +#define ORDERED_HASHMAP_FOREACH(e, h) \ + _ORDERED_HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ)) + +#define _HASHMAP_FOREACH_KEY(e, k, h, i) \ + for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); ) +#define HASHMAP_FOREACH_KEY(e, k, h) \ + _HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ)) + +#define _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \ + for (Iterator i = ITERATOR_FIRST; ordered_hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); ) +#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h) \ + _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ)) DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c index cddc269f..1ea3e7ff 100644 --- a/shared/systemd/src/basic/in-addr-util.c +++ b/shared/systemd/src/basic/in-addr-util.c @@ -16,6 +16,7 @@ #include "macro.h" #include "parse-util.h" #include "random-util.h" +#include "string-util.h" #include "strxcpyx.h" #include "util.h" @@ -55,6 +56,16 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) { return -EAFNOSUPPORT; } +bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) { + assert(a); + + /* ff02::1 */ + return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) && + a->s6_addr32[1] == 0 && + a->s6_addr32[2] == 0 && + be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001); +} + int in_addr_is_multicast(int family, const union in_addr_union *u) { assert(u); @@ -67,6 +78,12 @@ int in_addr_is_multicast(int family, const union in_addr_union *u) { return -EAFNOSUPPORT; } +bool in4_addr_is_local_multicast(const struct in_addr *a) { + assert(a); + + return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000); +} + bool in4_addr_is_localhost(const struct in_addr *a) { assert(a); @@ -109,11 +126,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_ return in4_addr_equal(&a->in, &b->in); if (family == AF_INET6) - return - a->in6.s6_addr32[0] == b->in6.s6_addr32[0] && - a->in6.s6_addr32[1] == b->in6.s6_addr32[1] && - a->in6.s6_addr32[2] == b->in6.s6_addr32[2] && - a->in6.s6_addr32[3] == b->in6.s6_addr32[3]; + return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6); return -EAFNOSUPPORT; } @@ -411,44 +424,59 @@ int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned } #endif /* NM_IGNORED */ -int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { - _cleanup_free_ char *x = NULL; - size_t l; +int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) { + _cleanup_free_ char *ip_str = NULL, *x = NULL; int r; + assert(IN_SET(family, AF_INET, AF_INET6)); assert(u); assert(ret); /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly * handle IPv6 link-local addresses. */ - if (family != AF_INET6) - goto fallback; - if (ifindex <= 0) - goto fallback; - - r = in_addr_is_link_local(family, u); + r = in_addr_to_string(family, u, &ip_str); if (r < 0) return r; - if (r == 0) - goto fallback; - l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1; - x = new(char, l); - if (!x) - return -ENOMEM; + if (family == AF_INET6) { + r = in_addr_is_link_local(family, u); + if (r < 0) + return r; + if (r == 0) + ifindex = 0; + } else + ifindex = 0; /* For IPv4 address, ifindex is always ignored. */ - errno = 0; - if (!inet_ntop(family, u, x, l)) - return errno_or_else(EINVAL); + if (port == 0 && ifindex == 0 && isempty(server_name)) { + *ret = TAKE_PTR(ip_str); + return 0; + } - sprintf(strchr(x, 0), "%%%i", ifindex); + const char *separator = isempty(server_name) ? "" : "#"; + server_name = strempty(server_name); + + if (port > 0) { + if (family == AF_INET6) { + if (ifindex > 0) + r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name); + else + r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name); + } else + r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name); + } else { + if (ifindex > 0) + r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name); + else { + x = strjoin(ip_str, separator, server_name); + r = x ? 0 : -ENOMEM; + } + } + if (r < 0) + return -ENOMEM; *ret = TAKE_PTR(x); return 0; - -fallback: - return in_addr_to_string(family, u, ret); } int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { @@ -750,13 +778,13 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func); -static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) { +void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) { assert(addr); siphash24_compress(addr, sizeof(*addr), state); } -static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) { +int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) { return memcmp(a, b, sizeof(*a)); } diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h index 90d79a5e..45c93a00 100644 --- a/shared/systemd/src/basic/in-addr-util.h +++ b/shared/systemd/src/basic/in-addr-util.h @@ -12,6 +12,7 @@ union in_addr_union { struct in_addr in; struct in6_addr in6; + uint8_t bytes[CONST_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; }; struct in_addr_data { @@ -26,10 +27,12 @@ int in_addr_is_multicast(int family, const union in_addr_union *u); bool in4_addr_is_link_local(const struct in_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); +bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a); bool in4_addr_is_localhost(const struct in_addr *a); int in_addr_is_localhost(int family, const union in_addr_union *u); +bool in4_addr_is_local_multicast(const struct in_addr *a); bool in4_addr_is_non_local(const struct in_addr *a); bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b); @@ -40,7 +43,13 @@ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, u int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); -int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); +int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); +static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { + return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret); +} +static inline int in_addr_port_to_string(int family, const union in_addr_union *u, uint16_t port, char **ret) { + return in_addr_port_ifindex_name_to_string(family, u, port, 0, NULL, ret); +} int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret); @@ -73,5 +82,8 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) { * See also oss-fuzz#11344. */ #define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} }) +void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state); +int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b); + extern const struct hash_ops in_addr_data_hash_ops; extern const struct hash_ops in6_addr_hash_ops; diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c index f1df3fac..8b0e354a 100644 --- a/shared/systemd/src/basic/io-util.c +++ b/shared/systemd/src/basic/io-util.c @@ -158,10 +158,8 @@ int pipe_eof(int fd) { int r; r = fd_wait_for_event(fd, POLLIN, 0); - if (r < 0) + if (r <= 0) return r; - if (r == 0) - return 0; return !!(r & POLLHUP); } diff --git a/shared/systemd/src/basic/list.h b/shared/systemd/src/basic/list.h index f7f97000..b62c3749 100644 --- a/shared/systemd/src/basic/list.h +++ b/shared/systemd/src/basic/list.h @@ -169,3 +169,18 @@ #define LIST_IS_EMPTY(head) \ (!(head)) + +/* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */ +#define LIST_JOIN(name,a,b) \ + do { \ + assert(b); \ + if (!(a)) \ + (a) = (b); \ + else { \ + typeof(*(a)) *_head = (b), *_tail; \ + LIST_FIND_TAIL(name, (a), _tail); \ + _tail->name##_next = _head; \ + _head->name##_prev = _tail; \ + } \ + (b) = NULL; \ + } while (false) diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h index 3725b08f..c2ffbb5d 100644 --- a/shared/systemd/src/basic/log.h +++ b/shared/systemd/src/basic/log.h @@ -30,7 +30,7 @@ typedef enum LogTarget{ LOG_TARGET_JOURNAL_OR_KMSG, LOG_TARGET_SYSLOG, LOG_TARGET_SYSLOG_OR_KMSG, - LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ + LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */ LOG_TARGET_NULL, _LOG_TARGET_MAX, _LOG_TARGET_INVALID = -1 @@ -61,10 +61,13 @@ void log_show_location(bool b); bool log_get_show_location(void) _pure_; void log_show_time(bool b); bool log_get_show_time(void) _pure_; +void log_show_tid(bool b); +bool log_get_show_tid(void) _pure_; int log_show_color_from_string(const char *e); int log_show_location_from_string(const char *e); int log_show_time_from_string(const char *e); +int log_show_tid_from_string(const char *e); LogTarget log_get_target(void) _pure_; #if 0 /* NM_IGNORED */ @@ -89,8 +92,11 @@ void log_close(void); void log_forget_fds(void); void log_parse_environment_realm(LogRealm realm); +void log_parse_environment_cli_realm(LogRealm realm); #define log_parse_environment() \ log_parse_environment_realm(LOG_REALM) +#define log_parse_environment_cli() \ + log_parse_environment_cli_realm(LOG_REALM) #if 0 /* NM_IGNORED */ int log_dispatch_internal( @@ -245,12 +251,12 @@ void log_assert_failed_return_realm( #define log_full_errno(level, error, ...) \ log_full_errno_realm(LOG_REALM, (level), (error), __VA_ARGS__) -#define log_full(level, ...) log_full_errno((level), 0, __VA_ARGS__) +#define log_full(level, ...) (void) log_full_errno((level), 0, __VA_ARGS__) int log_emergency_level(void); /* Normal logging */ -#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) +#define log_debug(...) log_full_errno(LOG_DEBUG, 0, __VA_ARGS__) #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) @@ -359,3 +365,4 @@ int log_syntax_invalid_utf8_internal( #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) void log_setup_service(void); +void log_setup_cli(void); diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h index 0c2eb894..f872d41f 100644 --- a/shared/systemd/src/basic/macro.h +++ b/shared/systemd/src/basic/macro.h @@ -295,6 +295,15 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define CONST_MIN(_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 MIN3(x, y, z) \ ({ \ const typeof(x) _c = MIN(x, y); \ @@ -538,6 +547,15 @@ static inline int __coverity_check_and_return__(int condition) { (y) = (_t); \ } while (false) +#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) +#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) + +/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */ +#define FOREACH_POINTER(p, x, ...) \ + for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \ + p != (typeof(p)) (void*) -1; \ + p = *(++_l)) + /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h index a6a2ccdb..4f596cff 100644 --- a/shared/systemd/src/basic/memory-util.h +++ b/shared/systemd/src/basic/memory-util.h @@ -13,6 +13,7 @@ size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) #define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1)) +#define PAGE_OFFSET(l) ((l) & (page_size() - 1)) /* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ static inline void memcpy_safe(void *dst, const void *src, size_t n) { diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h index 647e56f1..fe4d35bd 100644 --- a/shared/systemd/src/basic/missing_socket.h +++ b/shared/systemd/src/basic/missing_socket.h @@ -65,6 +65,10 @@ struct sockaddr_vm { #define IP_TRANSPARENT 19 #endif +#ifndef IPV6_FREEBIND +#define IPV6_FREEBIND 78 +#endif + /* linux/sockios.h */ #ifndef SIOCGSKNS #define SIOCGSKNS 0x894C diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h index 7d89a7bb..5d59a214 100644 --- a/shared/systemd/src/basic/missing_stat.h +++ b/shared/systemd/src/basic/missing_stat.h @@ -9,45 +9,129 @@ #include <linux/stat.h> #endif -/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +/* Thew newest definition we are aware of (fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60; 5.8) */ +#define STATX_DEFINITION { \ + __u32 stx_mask; \ + __u32 stx_blksize; \ + __u64 stx_attributes; \ + __u32 stx_nlink; \ + __u32 stx_uid; \ + __u32 stx_gid; \ + __u16 stx_mode; \ + __u16 __spare0[1]; \ + __u64 stx_ino; \ + __u64 stx_size; \ + __u64 stx_blocks; \ + __u64 stx_attributes_mask; \ + struct statx_timestamp stx_atime; \ + struct statx_timestamp stx_btime; \ + struct statx_timestamp stx_ctime; \ + struct statx_timestamp stx_mtime; \ + __u32 stx_rdev_major; \ + __u32 stx_rdev_minor; \ + __u32 stx_dev_major; \ + __u32 stx_dev_minor; \ + __u64 stx_mnt_id; \ + __u64 __spare2; \ + __u64 __spare3[12]; \ +} + #if !HAVE_STRUCT_STATX struct statx_timestamp { __s64 tv_sec; __u32 tv_nsec; __s32 __reserved; }; -struct statx { - __u32 stx_mask; - __u32 stx_blksize; - __u64 stx_attributes; - __u32 stx_nlink; - __u32 stx_uid; - __u32 stx_gid; - __u16 stx_mode; - __u16 __spare0[1]; - __u64 stx_ino; - __u64 stx_size; - __u64 stx_blocks; - __u64 stx_attributes_mask; - struct statx_timestamp stx_atime; - struct statx_timestamp stx_btime; - struct statx_timestamp stx_ctime; - struct statx_timestamp stx_mtime; - __u32 stx_rdev_major; - __u32 stx_rdev_minor; - __u32 stx_dev_major; - __u32 stx_dev_minor; - __u64 __spare2[14]; -}; + +struct statx STATX_DEFINITION; #endif + +/* Always define the newest version we are aware of as a distinct type, so that we can use it even if glibc + * defines an older definition */ +struct new_statx STATX_DEFINITION; #endif /* NM_IGNORED */ /* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ -#ifndef STATX_BTIME -#define STATX_BTIME 0x00000800U +#ifndef AT_STATX_SYNC_AS_STAT +#define AT_STATX_SYNC_AS_STAT 0x0000 +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef AT_STATX_FORCE_SYNC +#define AT_STATX_FORCE_SYNC 0x2000 #endif /* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ #ifndef AT_STATX_DONT_SYNC #define AT_STATX_DONT_SYNC 0x4000 #endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_TYPE +#define STATX_TYPE 0x00000001U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_MODE +#define STATX_MODE 0x00000002U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_NLINK +#define STATX_NLINK 0x00000004U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_UID +#define STATX_UID 0x00000008U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_GID +#define STATX_GID 0x00000010U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_ATIME +#define STATX_ATIME 0x00000020U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_MTIME +#define STATX_MTIME 0x00000040U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_CTIME +#define STATX_CTIME 0x00000080U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_INO +#define STATX_INO 0x00000100U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_SIZE +#define STATX_SIZE 0x00000200U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_BLOCKS +#define STATX_BLOCKS 0x00000400U +#endif + +/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */ +#ifndef STATX_BTIME +#define STATX_BTIME 0x00000800U +#endif + +/* fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60 (5.8) */ +#ifndef STATX_MNT_ID +#define STATX_MNT_ID 0x00001000U +#endif + +/* 80340fe3605c0e78cfe496c3b3878be828cfdbfe (5.8) */ +#ifndef STATX_ATTR_MOUNT_ROOT +#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */ +#endif diff --git a/shared/systemd/src/basic/missing_syscall.h b/shared/systemd/src/basic/missing_syscall.h index 4c42e665..4aed6e7c 100644 --- a/shared/systemd/src/basic/missing_syscall.h +++ b/shared/systemd/src/basic/missing_syscall.h @@ -35,39 +35,49 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old) /* ======================================================================= */ -#if !HAVE_MEMFD_CREATE +#if defined __x86_64__ +# define systemd_NR_memfd_create 319 +#elif defined __arm__ +# define systemd_NR_memfd_create 385 +#elif defined __aarch64__ +# define systemd_NR_memfd_create 279 +#elif defined(__powerpc__) +# define systemd_NR_memfd_create 360 +#elif defined __s390__ +# define systemd_NR_memfd_create 350 +#elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_memfd_create 4354 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_memfd_create 5314 +# endif +#elif defined __i386__ +# define systemd_NR_memfd_create 356 +#elif defined __arc__ +# define systemd_NR_memfd_create 279 +#else +# warning "memfd_create() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_memfd_create && __NR_memfd_create >= 0) -# if defined __NR_memfd_create -# undef __NR_memfd_create -# endif -# if defined __x86_64__ -# define __NR_memfd_create 319 -# elif defined __arm__ -# define __NR_memfd_create 385 -# elif defined __aarch64__ -# define __NR_memfd_create 279 -# elif defined __s390__ -# define __NR_memfd_create 350 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_memfd_create 4354 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_memfd_create 6318 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_memfd_create 5314 -# endif -# elif defined __i386__ -# define __NR_memfd_create 356 -# elif defined __arc__ -# define __NR_memfd_create 279 -# else -# warning "__NR_memfd_create unknown for your architecture" -# endif +#if defined __NR_memfd_create && __NR_memfd_create >= 0 +# if defined systemd_NR_memfd_create +assert_cc(__NR_memfd_create == systemd_NR_memfd_create); +# endif +#else +# if defined __NR_memfd_create +# undef __NR_memfd_create # endif +# if defined systemd_NR_memfd_create +# define __NR_memfd_create systemd_NR_memfd_create +# endif +#endif +#if !HAVE_MEMFD_CREATE static inline int missing_memfd_create(const char *name, unsigned int flags) { # ifdef __NR_memfd_create return syscall(__NR_memfd_create, name, flags); @@ -82,45 +92,53 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) { /* ======================================================================= */ -#if !HAVE_GETRANDOM +#if defined __x86_64__ +# define systemd_NR_getrandom 318 +#elif defined(__i386__) +# define systemd_NR_getrandom 355 +#elif defined(__arm__) +# define systemd_NR_getrandom 384 +#elif defined(__aarch64__) +# define systemd_NR_getrandom 278 +#elif defined(__ia64__) +# define systemd_NR_getrandom 1339 +#elif defined(__m68k__) +# define systemd_NR_getrandom 352 +#elif defined(__s390x__) +# define systemd_NR_getrandom 349 +#elif defined(__powerpc__) +# define systemd_NR_getrandom 359 +#elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_getrandom 4353 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_getrandom 6317 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_getrandom 5313 +# endif +#elif defined(__arc__) +# define systemd_NR_getrandom 278 +#else +# warning "getrandom() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_getrandom && __NR_getrandom >= 0) -# if defined __NR_getrandom -# undef __NR_getrandom -# endif -# if defined __x86_64__ -# define __NR_getrandom 318 -# elif defined(__i386__) -# define __NR_getrandom 355 -# elif defined(__arm__) -# define __NR_getrandom 384 -# elif defined(__aarch64__) -# define __NR_getrandom 278 -# elif defined(__ia64__) -# define __NR_getrandom 1339 -# elif defined(__m68k__) -# define __NR_getrandom 352 -# elif defined(__s390x__) -# define __NR_getrandom 349 -# elif defined(__powerpc__) -# define __NR_getrandom 359 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_getrandom 4353 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_getrandom 6317 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_getrandom 5313 -# endif -# elif defined(__arc__) -# define __NR_getrandom 278 -# else -# warning "__NR_getrandom unknown for your architecture" -# endif +#if defined __NR_getrandom && __NR_getrandom >= 0 +# if defined systemd_NR_getrandom +assert_cc(__NR_getrandom == systemd_NR_getrandom); +# endif +#else +# if defined __NR_getrandom +# undef __NR_getrandom +# endif +# if defined systemd_NR_getrandom +# define __NR_getrandom systemd_NR_getrandom # endif +#endif +#if !HAVE_GETRANDOM static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) { # ifdef __NR_getrandom return syscall(__NR_getrandom, buffer, count, flags); @@ -135,9 +153,14 @@ static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) /* ======================================================================= */ +/* The syscall has been defined since forever, but the glibc wrapper was missing. */ #if !HAVE_GETTID static inline pid_t missing_gettid(void) { +# if defined __NR_gettid && __NR_gettid >= 0 return (pid_t) syscall(__NR_gettid); +# else +# error "__NR_gettid not defined" +# endif } # define gettid missing_gettid @@ -145,27 +168,39 @@ static inline pid_t missing_gettid(void) { /* ======================================================================= */ -#if !HAVE_NAME_TO_HANDLE_AT +#if defined(__x86_64__) +# define systemd_NR_name_to_handle_at 303 +#elif defined(__i386__) +# define systemd_NR_name_to_handle_at 341 +#elif defined(__arm__) +# define systemd_NR_name_to_handle_at 370 +#elif defined __aarch64__ +# define systemd_NR_name_to_handle_at 264 +#elif defined(__powerpc__) +# define systemd_NR_name_to_handle_at 345 +#elif defined __s390__ || defined __s390x__ +# define systemd_NR_name_to_handle_at 335 +#elif defined(__arc__) +# define systemd_NR_name_to_handle_at 264 +#else +# warning "name_to_handle_at number is not defined" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0) -# if defined __NR_name_to_handle_at -# undef __NR_name_to_handle_at -# endif -# if defined(__x86_64__) -# define __NR_name_to_handle_at 303 -# elif defined(__i386__) -# define __NR_name_to_handle_at 341 -# elif defined(__arm__) -# define __NR_name_to_handle_at 370 -# elif defined(__powerpc__) -# define __NR_name_to_handle_at 345 -# elif defined(__arc__) -# define __NR_name_to_handle_at 264 -# else -# error "__NR_name_to_handle_at is not defined" -# endif +#if defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0 +# if defined systemd_NR_name_to_handle_at +assert_cc(__NR_name_to_handle_at == systemd_NR_name_to_handle_at); # endif +#else +# if defined __NR_name_to_handle_at +# undef __NR_name_to_handle_at +# endif +# if defined systemd_NR_name_to_handle_at +# define __NR_name_to_handle_at systemd_NR_name_to_handle_at +# endif +#endif +#if !HAVE_NAME_TO_HANDLE_AT struct file_handle { unsigned int handle_bytes; int handle_type; @@ -186,23 +221,39 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil /* ======================================================================= */ -#if !HAVE_SETNS +#if defined __aarch64__ +# define systemd_NR_setns 268 +#elif defined __arm__ +# define systemd_NR_setns 375 +#elif defined(__x86_64__) +# define systemd_NR_setns 308 +#elif defined(__i386__) +# define systemd_NR_setns 346 +#elif defined(__powerpc__) +# define systemd_NR_setns 350 +#elif defined __s390__ || defined __s390x__ +# define systemd_NR_setns 339 +#elif defined(__arc__) +# define systemd_NR_setns 268 +#else +# warning "setns() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_setns && __NR_setns >= 0) -# if defined __NR_setns -# undef __NR_setns -# endif -# if defined(__x86_64__) -# define __NR_setns 308 -# elif defined(__i386__) -# define __NR_setns 346 -# elif defined(__arc__) -# define __NR_setns 268 -# else -# error "__NR_setns is not defined" -# endif +#if defined __NR_setns && __NR_setns >= 0 +# if defined systemd_NR_setns +assert_cc(__NR_setns == systemd_NR_setns); # endif +#else +# if defined __NR_setns +# undef __NR_setns +# endif +# if defined systemd_NR_setns +# define __NR_setns systemd_NR_setns +# endif +#endif +#if !HAVE_SETNS static inline int missing_setns(int fd, int nstype) { # ifdef __NR_setns return syscall(__NR_setns, fd, nstype); @@ -227,41 +278,49 @@ static inline pid_t raw_getpid(void) { /* ======================================================================= */ -#if !HAVE_RENAMEAT2 +#if defined __x86_64__ +# define systemd_NR_renameat2 316 +#elif defined __arm__ +# define systemd_NR_renameat2 382 +#elif defined __aarch64__ +# define systemd_NR_renameat2 276 +#elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_renameat2 5311 +# endif +#elif defined __i386__ +# define systemd_NR_renameat2 353 +#elif defined __powerpc64__ +# define systemd_NR_renameat2 357 +#elif defined __s390__ || defined __s390x__ +# define systemd_NR_renameat2 347 +#elif defined __arc__ +# define systemd_NR_renameat2 276 +#else +# warning "renameat2() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_renameat2 && __NR_renameat2 >= 0) -# if defined __NR_renameat2 -# undef __NR_renameat2 -# endif -# if defined __x86_64__ -# define __NR_renameat2 316 -# elif defined __arm__ -# define __NR_renameat2 382 -# elif defined __aarch64__ -# define __NR_renameat2 276 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_renameat2 4351 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_renameat2 6315 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_renameat2 5311 -# endif -# elif defined __i386__ -# define __NR_renameat2 353 -# elif defined __powerpc64__ -# define __NR_renameat2 357 -# elif defined __s390__ || defined __s390x__ -# define __NR_renameat2 347 -# elif defined __arc__ -# define __NR_renameat2 276 -# else -# warning "__NR_renameat2 unknown for your architecture" -# endif +#if defined __NR_renameat2 && __NR_renameat2 >= 0 +# if defined systemd_NR_renameat2 +assert_cc(__NR_renameat2 == systemd_NR_renameat2); # endif +#else +# if defined __NR_renameat2 +# undef __NR_renameat2 +# endif +# if defined systemd_NR_renameat2 +# define __NR_renameat2 systemd_NR_renameat2 +# endif +#endif +#if !HAVE_RENAMEAT2 static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { # ifdef __NR_renameat2 return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); @@ -328,31 +387,39 @@ static inline key_serial_t missing_request_key(const char *type, const char *des /* ======================================================================= */ -#if !HAVE_COPY_FILE_RANGE +#if defined(__x86_64__) +# define systemd_NR_copy_file_range 326 +#elif defined(__i386__) +# define systemd_NR_copy_file_range 377 +#elif defined __s390__ +# define systemd_NR_copy_file_range 375 +#elif defined __arm__ +# define systemd_NR_copy_file_range 391 +#elif defined __aarch64__ +# define systemd_NR_copy_file_range 285 +#elif defined __powerpc__ +# define systemd_NR_copy_file_range 379 +#elif defined __arc__ +# define systemd_NR_copy_file_range 285 +#else +# warning "copy_file_range() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_copy_file_range && __NR_copy_file_range >= 0) -# if defined __NR_copy_file_range -# undef __NR_copy_file_range -# endif -# if defined(__x86_64__) -# define __NR_copy_file_range 326 -# elif defined(__i386__) -# define __NR_copy_file_range 377 -# elif defined __s390__ -# define __NR_copy_file_range 375 -# elif defined __arm__ -# define __NR_copy_file_range 391 -# elif defined __aarch64__ -# define __NR_copy_file_range 285 -# elif defined __powerpc__ -# define __NR_copy_file_range 379 -# elif defined __arc__ -# define __NR_copy_file_range 285 -# else -# warning "__NR_copy_file_range not defined for your architecture" -# endif +#if defined __NR_copy_file_range && __NR_copy_file_range >= 0 +# if defined systemd_NR_copy_file_range +assert_cc(__NR_copy_file_range == systemd_NR_copy_file_range); # endif +#else +# if defined __NR_copy_file_range +# undef __NR_copy_file_range +# endif +# if defined systemd_NR_copy_file_range +# define __NR_copy_file_range systemd_NR_copy_file_range +# endif +#endif +#if !HAVE_COPY_FILE_RANGE static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, @@ -370,31 +437,41 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, /* ======================================================================= */ -#if !HAVE_BPF +#if defined __i386__ +# define systemd_NR_bpf 357 +#elif defined __x86_64__ +# define systemd_NR_bpf 321 +#elif defined __aarch64__ +# define systemd_NR_bpf 280 +#elif defined __arm__ +# define systemd_NR_bpf 386 +#elif defined(__powerpc__) +# define systemd_NR_bpf 361 +#elif defined __sparc__ +# define systemd_NR_bpf 349 +#elif defined __s390__ +# define systemd_NR_bpf 351 +#elif defined __tilegx__ +# define systemd_NR_bpf 280 +#else +# warning "bpf() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_bpf && __NR_bpf >= 0) -# if defined __NR_bpf -# undef __NR_bpf -# endif -# if defined __i386__ -# define __NR_bpf 357 -# elif defined __x86_64__ -# define __NR_bpf 321 -# elif defined __aarch64__ -# define __NR_bpf 280 -# elif defined __arm__ -# define __NR_bpf 386 -# elif defined __sparc__ -# define __NR_bpf 349 -# elif defined __s390__ -# define __NR_bpf 351 -# elif defined __tilegx__ -# define __NR_bpf 280 -# else -# warning "__NR_bpf not defined for your architecture" -# endif +#if defined __NR_bpf && __NR_bpf >= 0 +# if defined systemd_NR_bpf +assert_cc(__NR_bpf == systemd_NR_bpf); +# endif +#else +# if defined __NR_bpf +# undef __NR_bpf # endif +# if defined systemd_NR_bpf +# define __NR_bpf systemd_NR_bpf +# endif +#endif +#if !HAVE_BPF union bpf_attr; static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { @@ -412,69 +489,84 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { /* ======================================================================= */ #ifndef __IGNORE_pkey_mprotect +# if defined __i386__ +# define systemd_NR_pkey_mprotect 380 +# elif defined __x86_64__ +# define systemd_NR_pkey_mprotect 329 +# elif defined __aarch64__ +# define systemd_NR_pkey_mprotect 288 +# elif defined __arm__ +# define systemd_NR_pkey_mprotect 394 +# elif defined __powerpc__ +# define systemd_NR_pkey_mprotect 386 +# elif defined __s390__ +# define systemd_NR_pkey_mprotect 384 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_pkey_mprotect 4363 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_pkey_mprotect 6327 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_pkey_mprotect 5323 +# endif +# else +# warning "pkey_mprotect() syscall number unknown for your architecture" +# endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0) +# if defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0 +# if defined systemd_NR_pkey_mprotect +assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect); +# endif +# else # if defined __NR_pkey_mprotect # undef __NR_pkey_mprotect # endif -# if defined __i386__ -# define __NR_pkey_mprotect 380 -# elif defined __x86_64__ -# define __NR_pkey_mprotect 329 -# elif defined __arm__ -# define __NR_pkey_mprotect 394 -# elif defined __aarch64__ -# define __NR_pkey_mprotect 394 -# elif defined __powerpc__ -# define __NR_pkey_mprotect 386 -# elif defined __s390__ -# define __NR_pkey_mprotect 384 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_pkey_mprotect 4363 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_pkey_mprotect 6327 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_pkey_mprotect 5323 -# endif -# else -# warning "__NR_pkey_mprotect not defined for your architecture" +# if defined systemd_NR_pkey_mprotect +# define __NR_pkey_mprotect systemd_NR_pkey_mprotect # endif # endif #endif /* ======================================================================= */ -#if !HAVE_STATX +#if defined __aarch64__ +# define systemd_NR_statx 291 +#elif defined __arm__ +# define systemd_NR_statx 397 +#elif defined __alpha__ +# define systemd_NR_statx 522 +#elif defined __i386__ || defined __powerpc64__ +# define systemd_NR_statx 383 +#elif defined __s390__ || defined __s390x__ +# define systemd_NR_statx 379 +#elif defined __sparc__ +# define systemd_NR_statx 360 +#elif defined __x86_64__ +# define systemd_NR_statx 332 +#else +# warning "statx() syscall number unknown for your architecture" +#endif + /* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_statx && __NR_statx >= 0) -# if defined __NR_statx -# undef __NR_statx -# endif -# if defined __aarch64__ || defined __arm__ -# define __NR_statx 397 -# elif defined __alpha__ -# define __NR_statx 522 -# elif defined __i386__ || defined __powerpc64__ -# define __NR_statx 383 -# elif defined __sparc__ -# define __NR_statx 360 -# elif defined __x86_64__ -# define __NR_statx 332 -# else -# warning "__NR_statx not defined for your architecture" -# endif +#if defined __NR_statx && __NR_statx >= 0 +# if defined systemd_NR_statx +assert_cc(__NR_statx == systemd_NR_statx); +# endif +#else +# if defined __NR_statx +# undef __NR_statx +# endif +# if defined systemd_NR_statx +# define __NR_statx systemd_NR_statx # endif - -struct statx; #endif -/* This typedef is supposed to be always defined. */ -typedef struct statx struct_statx; - #if !HAVE_STATX +struct statx; + static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) { # ifdef __NR_statx return syscall(__NR_statx, dfd, filename, flags, mask, buffer); @@ -483,12 +575,18 @@ static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flag return -1; # endif } +#endif -# define statx missing_statx +/* This typedef is supposed to be always defined. */ +typedef struct statx struct_statx; + +#if !HAVE_STATX +# define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer) #endif -#if !HAVE_SET_MEMPOLICY +/* ======================================================================= */ +#if !HAVE_SET_MEMPOLICY enum { MPOL_DEFAULT, MPOL_PREFERRED, @@ -517,7 +615,7 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags) { long i; -# ifdef __NR_get_mempolicy +# if defined __NR_get_mempolicy && __NR_get_mempolicy >= 0 i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags); # else errno = ENOSYS; @@ -526,49 +624,87 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, return i; } -#define get_mempolicy missing_get_mempolicy +# define get_mempolicy missing_get_mempolicy #endif #endif /* NM_IGNORED */ -#if !HAVE_PIDFD_OPEN -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_pidfd_open && __NR_pidfd_open >= 0) -# if defined __NR_pidfd_open -# undef __NR_pidfd_open -# endif -# define __NR_pidfd_open 434 +/* ======================================================================= */ + +/* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */ +#if defined(__alpha__) +# define systemd_NR_pidfd_send_signal 534 +#else +# define systemd_NR_pidfd_send_signal 424 #endif -static inline int pidfd_open(pid_t pid, unsigned flags) { -#ifdef __NR_pidfd_open - return syscall(__NR_pidfd_open, pid, flags); + +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +#if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0 +# if defined systemd_NR_pidfd_send_signal +assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal); +# endif #else +# if defined __NR_pidfd_send_signal +# undef __NR_pidfd_send_signal +# endif +# define __NR_pidfd_send_signal systemd_NR_pidfd_send_signal +#endif + +#if !HAVE_PIDFD_SEND_SIGNAL +static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) { +# ifdef __NR_pidfd_open + return syscall(__NR_pidfd_send_signal, fd, sig, info, flags); +# else errno = ENOSYS; return -1; -#endif +# endif } + +# define pidfd_send_signal missing_pidfd_send_signal #endif -#if !HAVE_PIDFD_SEND_SIGNAL -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if ! (defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0) -# if defined __NR_pidfd_send_signal -# undef __NR_pidfd_send_signal -# endif -# define __NR_pidfd_send_signal 424 +/* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */ +#if defined(__alpha__) +# define systemd_NR_pidfd_open 544 +#else +# define systemd_NR_pidfd_open 434 #endif -static inline int pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) { -#ifdef __NR_pidfd_open - return syscall(__NR_pidfd_send_signal, fd, sig, info, flags); + +/* may be (invalid) negative number due to libseccomp, see PR 13319 */ +#if defined __NR_pidfd_open && __NR_pidfd_open >= 0 +# if defined systemd_NR_pidfd_open +assert_cc(__NR_pidfd_open == systemd_NR_pidfd_open); +# endif #else +# if defined __NR_pidfd_open +# undef __NR_pidfd_open +# endif +# define __NR_pidfd_open systemd_NR_pidfd_open +#endif + +#if !HAVE_PIDFD_OPEN +static inline int missing_pidfd_open(pid_t pid, unsigned flags) { +# ifdef __NR_pidfd_open + return syscall(__NR_pidfd_open, pid, flags); +# else errno = ENOSYS; return -1; -#endif +# endif } + +# define pidfd_open missing_pidfd_open #endif +/* ======================================================================= */ + #if !HAVE_RT_SIGQUEUEINFO -static inline int rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) { +static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) { +# if defined __NR_rt_sigqueueinfo && __NR_rt_sigqueueinfo >= 0 return syscall(__NR_rt_sigqueueinfo, tgid, sig, info); +# else +# error "__NR_rt_sigqueueinfo not defined" +# endif } + +# define rt_sigqueueinfo missing_rt_sigqueueinfo #endif diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c index 0b343b2a..6b47317a 100644 --- a/shared/systemd/src/basic/parse-util.c +++ b/shared/systemd/src/basic/parse-util.c @@ -18,6 +18,9 @@ #include "missing_network.h" #include "parse-util.h" #include "process-util.h" +#if HAVE_SECCOMP +#include "seccomp-util.h" +#endif #include "stat-util.h" #include "string-util.h" #include "strv.h" @@ -317,6 +320,7 @@ int parse_errno(const char *t) { return e; } +#if HAVE_SECCOMP int parse_syscall_and_errno(const char *in, char **name, int *error) { _cleanup_free_ char *n = NULL; char *p; @@ -335,7 +339,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) { p = strchr(in, ':'); if (p) { - e = parse_errno(p + 1); + e = seccomp_parse_errno_or_action(p + 1); if (e < 0) return e; @@ -354,6 +358,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) { return 0; } +#endif #endif /* NM_IGNORED */ static const char *mangle_base(const char *s, unsigned *base) { diff --git a/shared/systemd/src/basic/parse-util.h b/shared/systemd/src/basic/parse-util.h index 9a516ce5..2cee65c4 100644 --- a/shared/systemd/src/basic/parse-util.h +++ b/shared/systemd/src/basic/parse-util.h @@ -19,7 +19,9 @@ int parse_mtu(int family, const char *s, uint32_t *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); int parse_errno(const char *t); +#if HAVE_SECCOMP int parse_syscall_and_errno(const char *in, char **name, int *error); +#endif #define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30) #define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29) diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c index 45477bc2..644829b2 100644 --- a/shared/systemd/src/basic/path-util.c +++ b/shared/systemd/src/basic/path-util.c @@ -16,6 +16,7 @@ #include "alloc-util.h" #include "extract-word.h" +#include "fd-util.h" #include "fs-util.h" #include "glob-util.h" #include "log.h" @@ -29,15 +30,7 @@ #include "time-util.h" #include "utf8.h" -bool path_is_absolute(const char *p) { - return p[0] == '/'; -} - #if 0 /* NM_IGNORED */ -bool is_path(const char *p) { - return !!strchr(p, '/'); -} - int path_split_and_make_absolute(const char *p, char ***ret) { char **l; int r; @@ -601,9 +594,9 @@ char* path_join_internal(const char *first, ...) { } #if 0 /* NM_IGNORED */ -int find_binary(const char *name, char **ret) { +int find_executable_full(const char *name, bool use_path_envvar, char **ret) { int last_error, r; - const char *p; + const char *p = NULL; assert(name); @@ -620,11 +613,10 @@ int find_binary(const char *name, char **ret) { return 0; } - /** - * Plain getenv, not secure_getenv, because we want - * to actually allow the user to pick the binary. - */ - p = getenv("PATH"); + if (use_path_envvar) + /* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the + * binary. */ + p = getenv("PATH"); if (!p) p = DEFAULT_PATH; @@ -647,14 +639,24 @@ int find_binary(const char *name, char **ret) { return -ENOMEM; if (access(j, X_OK) >= 0) { - /* Found it! */ + _cleanup_free_ char *with_dash; - if (ret) { - *ret = path_simplify(j, false); - j = NULL; - } + with_dash = strjoin(j, "/"); + if (!with_dash) + return -ENOMEM; - return 0; + /* If this passes, it must be a directory, and so should be skipped. */ + if (access(with_dash, X_OK) >= 0) + continue; + + /* We can't just `continue` inverting this case, since we need to update last_error. */ + if (errno == ENOTDIR) { + /* Found it! */ + if (ret) + *ret = path_simplify(TAKE_PTR(j), false); + + return 0; + } } /* PATH entries which we don't have access to are ignored, as per tradition. */ @@ -700,18 +702,17 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd return changed; } -static int binary_is_good(const char *binary) { +static int executable_is_good(const char *executable) { _cleanup_free_ char *p = NULL, *d = NULL; int r; - r = find_binary(binary, &p); + r = find_executable(executable, &p); if (r == -ENOENT) return 0; if (r < 0) return r; - /* An fsck that is linked to /bin/true is a non-existent - * fsck */ + /* An fsck that is linked to /bin/true is a non-existent fsck */ r = readlink_malloc(p, &d); if (r == -EINVAL) /* not a symlink */ @@ -734,19 +735,7 @@ int fsck_exists(const char *fstype) { return -EINVAL; checker = strjoina("fsck.", fstype); - return binary_is_good(checker); -} - -int mkfs_exists(const char *fstype) { - const char *mkfs; - - assert(fstype); - - if (streq(fstype, "auto")) - return -EINVAL; - - mkfs = strjoina("mkfs.", fstype); - return binary_is_good(mkfs); + return executable_is_good(checker); } int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) { @@ -1154,4 +1143,10 @@ bool prefixed_path_strv_contains(char **l, const char *path) { return false; } + +bool credential_name_valid(const char *s) { + /* We want that credential names are both valid in filenames (since that's our primary way to pass + * them around) and as fdnames (which is how we might want to pass them around eventually) */ + return filename_is_valid(s) && fdname_is_valid(s); +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h index aba8ad00..6c265519 100644 --- a/shared/systemd/src/basic/path-util.h +++ b/shared/systemd/src/basic/path-util.h @@ -44,9 +44,17 @@ # define DEFAULT_USER_PATH DEFAULT_PATH #endif -bool is_path(const char *p) _pure_; +static inline bool is_path(const char *p) { + assert(p); + return strchr(p, '/'); +} + +static inline bool path_is_absolute(const char *p) { + assert(p); + return p[0] == '/'; +} + int path_split_and_make_absolute(const char *p, char ***ret); -bool path_is_absolute(const char *p) _pure_; char* path_make_absolute(const char *p, const char *prefix); int safe_getcwd(char **ret); int path_make_absolute_cwd(const char *p, char **ret); @@ -82,12 +90,14 @@ int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *root); char** path_strv_resolve_uniq(char **l, const char *root); -int find_binary(const char *name, char **filename); +int find_executable_full(const char *name, bool use_path_envvar, char **ret); +static inline int find_executable(const char *name, char **ret) { + return find_executable_full(name, true, ret); +} bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); int fsck_exists(const char *fstype); -int mkfs_exists(const char *fstype); /* Iterates through the path prefixes of the specified path, going up * the tree, to root. Also returns "" (and not "/"!) for the root @@ -176,3 +186,5 @@ static inline const char *empty_to_root(const char *path) { bool path_strv_contains(char **l, const char *path); bool prefixed_path_strv_contains(char **l, const char *path); + +bool credential_name_valid(const char *s); diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index 6dcb26fb..03ca04e1 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/process-util.h b/shared/systemd/src/basic/process-util.h index 05012377..314a8de1 100644 --- a/shared/systemd/src/basic/process-util.h +++ b/shared/systemd/src/basic/process-util.h @@ -20,14 +20,16 @@ #define procfs_file_alloca(pid, field) \ ({ \ pid_t _pid_ = (pid); \ - const char *_r_; \ + const char *_field_ = (field); \ + char *_r_; \ if (_pid_ == 0) { \ - _r_ = ("/proc/self/" field); \ + _r_ = newa(char, STRLEN("/proc/self/") + strlen(_field_) + 1); \ + strcpy(stpcpy(_r_, "/proc/self/"), _field_); \ } else { \ - _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ - sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ + _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + strlen(_field_) + 1); \ + sprintf(_r_, "/proc/" PID_FMT "/%s", _pid_, _field_); \ } \ - _r_; \ + (const char*) _r_; \ }) typedef enum ProcessCmdlineFlags { diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c index 512e7af9..9551e762 100644 --- a/shared/systemd/src/basic/random-util.c +++ b/shared/systemd/src/basic/random-util.c @@ -9,11 +9,13 @@ #include <elf.h> #include <errno.h> #include <fcntl.h> +#include <linux/random.h> #include <pthread.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <sys/ioctl.h> #include <sys/time.h> #if HAVE_SYS_AUXV_H @@ -21,6 +23,7 @@ #endif #include "alloc-util.h" +#include "env-util.h" #include "errno-util.h" #include "fd-util.h" #include "fileio.h" @@ -77,7 +80,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. * @@ -116,6 +119,15 @@ int rdrand(unsigned long *ret) { #endif have_rdrand = !!(ecx & bit_RDRND); + + if (have_rdrand > 0) { + /* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0 + If it is unset getenv_bool_secure will return a negative value. */ + if (getenv_bool_secure("SYSTEMD_RDRAND") == 0) { + have_rdrand = false; + return -EOPNOTSUPP; + } + } } if (have_rdrand == 0) @@ -448,4 +460,37 @@ size_t random_pool_size(void) { /* Use the minimum as default, if we can't retrieve the correct value */ return RANDOM_POOL_SIZE_MIN; } + +int random_write_entropy(int fd, const void *seed, size_t size, bool credit) { + int r; + + assert(fd >= 0); + assert(seed && size > 0); + + if (credit) { + _cleanup_free_ struct rand_pool_info *info = NULL; + + /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any + * chance for confusion here. */ + if (size > INT_MAX / 8) + return -EOVERFLOW; + + info = malloc(offsetof(struct rand_pool_info, buf) + size); + if (!info) + return -ENOMEM; + + info->entropy_count = size * 8; + info->buf_size = size; + memcpy(info->buf, seed, size); + + if (ioctl(fd, RNDADDENTROPY, info) < 0) + return -errno; + } else { + r = loop_write(fd, seed, size, false); + if (r < 0) + return r; + } + + return 0; +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/random-util.h b/shared/systemd/src/basic/random-util.h index d8e067d9..7824ffac 100644 --- a/shared/systemd/src/basic/random-util.h +++ b/shared/systemd/src/basic/random-util.h @@ -38,3 +38,5 @@ int rdrand(unsigned long *ret); #define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U) size_t random_pool_size(void); + +int random_write_entropy(int fd, const void *seed, size_t size, bool credit); diff --git a/shared/systemd/src/basic/set.h b/shared/systemd/src/basic/set.h index 621e83bf..7170eea8 100644 --- a/shared/systemd/src/basic/set.h +++ b/shared/systemd/src/basic/set.h @@ -13,22 +13,20 @@ 0; \ }) -Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +Set* _set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS) -static inline Set *set_free(Set *s) { +static inline Set* set_free(Set *s) { return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL); } -static inline Set *set_free_free(Set *s) { +static inline Set* set_free_free(Set *s) { return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL); } /* no set_free_free_free */ -static inline Set *set_copy(Set *s) { - return (Set*) _hashmap_copy(HASHMAP_BASE(s)); -} +#define set_copy(s) ((Set*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) @@ -36,7 +34,7 @@ int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG int set_put(Set *s, const void *key); /* no set_update */ /* no set_replace */ -static inline void *set_get(const Set *s, void *key) { +static inline void *set_get(const Set *s, const void *key) { return _hashmap_get(HASHMAP_BASE((Set *) s), key); } /* no set_get2 */ @@ -79,7 +77,9 @@ static inline unsigned set_buckets(const Set *s) { return _hashmap_buckets(HASHMAP_BASE((Set *) s)); } -bool set_iterate(const Set *s, Iterator *i, void **value); +static inline bool set_iterate(const Set *s, Iterator *i, void **value) { + return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL); +} static inline void set_clear(Set *s) { _hashmap_clear(HASHMAP_BASE(s), NULL, NULL); @@ -120,13 +120,25 @@ static inline char **set_get_strv(Set *s) { return _hashmap_get_strv(HASHMAP_BASE(s)); } +int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS); +#define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS) + +int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS); +#define set_ensure_consume(s, hash_ops, key) _set_ensure_consume(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS) + int set_consume(Set *s, void *value); -int set_put_strdup(Set **s, const char *p); -int set_put_strdupv(Set **s, char **l); + +int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS); +#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS) +int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS); +#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS) + int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags); -#define SET_FOREACH(e, s, i) \ - for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) +#define _SET_FOREACH(e, s, i) \ + for (Iterator i = ITERATOR_FIRST; set_iterate((s), &i, (void**)&(e)); ) +#define SET_FOREACH(e, s) \ + _SET_FOREACH(e, s, UNIQ_T(i, UNIQ)) #define SET_FOREACH_MOVE(e, d, s) \ for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); ) diff --git a/shared/systemd/src/basic/siphash24.h b/shared/systemd/src/basic/siphash24.h index c4e919df..474d9c9d 100644 --- a/shared/systemd/src/basic/siphash24.h +++ b/shared/systemd/src/basic/siphash24.h @@ -6,6 +6,8 @@ #include <string.h> #include <sys/types.h> +#include "time-util.h" + #if 0 /* NM_IGNORED */ struct siphash { uint64_t v0; @@ -17,39 +19,55 @@ struct siphash { }; #else /* NM_IGNORED */ struct siphash { - CSipHash _csiphash; + CSipHash _csiphash; }; static inline void siphash24_init (struct siphash *state, const uint8_t k[16]) { - c_siphash_init ((CSipHash *) state, k); + c_siphash_init ((CSipHash *) state, k); } static inline void siphash24_compress (const void *in, size_t inlen, struct siphash *state) { - c_siphash_append ((CSipHash *) state, in, inlen); + c_siphash_append ((CSipHash *) state, in, inlen); } static inline uint64_t siphash24_finalize (struct siphash *state) { - return c_siphash_finalize ((CSipHash *) state); + return c_siphash_finalize ((CSipHash *) state); } static inline uint64_t siphash24 (const void *in, size_t inlen, const uint8_t k[16]) { - return c_siphash_hash (k, in, inlen); + return c_siphash_hash (k, in, inlen); } #endif /* NM_IGNORED */ void siphash24_init(struct siphash *state, const uint8_t k[static 16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); -void siphash24_compress_boolean(bool in, struct siphash *state); #define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) +static inline void siphash24_compress_boolean(bool in, struct siphash *state) { + uint8_t i = in; + + siphash24_compress(&i, sizeof i, state); +} + +static inline void siphash24_compress_usec_t(usec_t in, struct siphash *state) { + siphash24_compress(&in, sizeof in, state); +} + +static inline void siphash24_compress_string(const char *in, struct siphash *state) { + if (!in) + return; + + siphash24_compress(in, strlen(in), state); +} + uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]); diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c index 9ced3a12..01dce3ab 100644 --- a/shared/systemd/src/basic/socket-util.c +++ b/shared/systemd/src/basic/socket-util.c @@ -30,6 +30,7 @@ #include "macro.h" #include "memory-util.h" #include "missing_socket.h" +#include "missing_network.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -73,7 +74,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) { if (a->sockaddr.in.sin_port == 0) return -EINVAL; - if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM)) + if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM)) return -EINVAL; return 0; @@ -85,7 +86,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) { if (a->sockaddr.in6.sin6_port == 0) return -EINVAL; - if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM)) + if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM)) return -EINVAL; return 0; @@ -110,7 +111,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.)*/ @@ -119,7 +120,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) { } } - if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET)) + if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET)) return -EINVAL; return 0; @@ -129,7 +130,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) { if (a->size != sizeof(struct sockaddr_nl)) return -EINVAL; - if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM)) + if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM)) return -EINVAL; return 0; @@ -138,7 +139,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) { if (a->size != sizeof(struct sockaddr_vm)) return -EINVAL; - if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM)) + if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM)) return -EINVAL; return 0; @@ -404,19 +405,23 @@ int sockaddr_pretty( if (r < 0) return -ENOMEM; } else { - char a[INET6_ADDRSTRLEN]; + char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1]; inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)); + if (sa->in6.sin6_scope_id != 0) + format_ifname_full(sa->in6.sin6_scope_id, ifname, FORMAT_IFNAME_IFINDEX); if (include_port) { r = asprintf(&p, - "[%s]:%u", + "[%s]:%u%s%s", a, - be16toh(sa->in6.sin6_port)); + be16toh(sa->in6.sin6_port), + sa->in6.sin6_scope_id != 0 ? "%" : "", + sa->in6.sin6_scope_id != 0 ? ifname : ""); if (r < 0) return -ENOMEM; } else { - p = strdup(a); + p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a); if (!p) return -ENOMEM; } @@ -622,40 +627,64 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b return false; } -int fd_inc_sndbuf(int fd, size_t n) { +int fd_set_sndbuf(int fd, size_t n, bool increase) { int r, value; socklen_t l = sizeof(value); + if (n > INT_MAX) + return -ERANGE; + r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) return 0; - /* If we have the privileges we will ignore the kernel limit. */ + /* First, try to set the buffer size with SO_SNDBUF. */ + r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n); + if (r < 0) + return r; - if (setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n) < 0) { - r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n); - if (r < 0) - return r; - } + /* SO_SNDBUF above may set to the kernel limit, instead of the requested size. + * So, we need to check the actual buffer size here. */ + l = sizeof(value); + r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) + return 1; + + /* If we have the privileges we will ignore the kernel limit. */ + r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n); + if (r < 0) + return r; return 1; } -int fd_inc_rcvbuf(int fd, size_t n) { +int fd_set_rcvbuf(int fd, size_t n, bool increase) { int r, value; socklen_t l = sizeof(value); + if (n > INT_MAX) + return -ERANGE; + r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) return 0; - /* If we have the privileges we will ignore the kernel limit. */ + /* First, try to set the buffer size with SO_RCVBUF. */ + r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n); + if (r < 0) + return r; - if (setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n) < 0) { - r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n); - if (r < 0) - return r; - } + /* SO_RCVBUF above may set to the kernel limit, instead of the requested size. + * So, we need to check the actual buffer size here. */ + l = sizeof(value); + r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) + return 1; + + /* If we have the privileges we will ignore the kernel limit. */ + r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n); + if (r < 0) + return r; return 1; } @@ -669,17 +698,19 @@ static const char* const ip_tos_table[] = { DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); -bool ifname_valid_full(const char *p, bool alternative) { +bool ifname_valid_full(const char *p, IfnameValidFlags flags) { bool numeric = true; /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */ + assert(!(flags & ~_IFNAME_VALID_ALL)); + if (isempty(p)) return false; - if (alternative) { + if (flags & IFNAME_VALID_ALTERNATIVE) { if (strlen(p) >= ALTIFNAMSIZ) return false; } else { @@ -690,22 +721,27 @@ bool ifname_valid_full(const char *p, bool alternative) { if (dot_or_dot_dot(p)) return false; - while (*p) { - if ((unsigned char) *p >= 127U) + for (const char *t = p; *t; t++) { + if ((unsigned char) *t >= 127U) return false; - if ((unsigned char) *p <= 32U) + if ((unsigned char) *t <= 32U) return false; - if (IN_SET(*p, ':', '/')) + if (IN_SET(*t, ':', '/')) return false; - numeric = numeric && (*p >= '0' && *p <= '9'); - p++; + numeric = numeric && (*t >= '0' && *t <= '9'); } - if (numeric) - return false; + if (numeric) { + if (!(flags & IFNAME_VALID_NUMERIC)) + return false; + + /* Verify that the number is well-formatted and in range. */ + if (parse_ifindex(p) < 0) + return false; + } return true; } @@ -1081,6 +1117,7 @@ int sockaddr_un_unlink(const struct sockaddr_un *sa) { return 1; } +#endif /* NM_IGNORED */ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { size_t l; @@ -1094,12 +1131,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { * reference paths in the abstract namespace that include NUL bytes in the name. */ l = strlen(path); - if (l == 0) + if (l < 2) return -EINVAL; if (!IN_SET(path[0], '/', '@')) return -EINVAL; - if (path[1] == 0) - return -EINVAL; /* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than * the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket @@ -1125,7 +1160,6 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */ } } -#endif /* NM_IGNORED */ int socket_bind_to_ifname(int fd, const char *ifname) { assert(fd >= 0); @@ -1140,6 +1174,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) { int socket_bind_to_ifindex(int fd, int ifindex) { char ifname[IF_NAMESIZE + 1]; + int r; assert(fd >= 0); @@ -1151,10 +1186,9 @@ int socket_bind_to_ifindex(int fd, int ifindex) { return 0; } - if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0) - return 0; - if (errno != ENOPROTOOPT) - return -errno; + r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex); + if (r != -ENOPROTOOPT) + return r; /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */ if (!format_ifname(ifindex, ifname)) @@ -1183,13 +1217,28 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) { return n; } -int socket_pass_pktinfo(int fd, bool b) { +int socket_get_family(int fd, int *ret) { int af; socklen_t sl = sizeof(af); if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &af, &sl) < 0) return -errno; + if (sl != sizeof(af)) + return -EINVAL; + + return af; +} + +int socket_set_recvpktinfo(int fd, int af, bool b) { + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + switch (af) { case AF_INET: @@ -1205,3 +1254,142 @@ int socket_pass_pktinfo(int fd, bool b) { return -EAFNOSUPPORT; } } + +int socket_set_recverr(int fd, int af, bool b) { + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + return setsockopt_int(fd, IPPROTO_IP, IP_RECVERR, b); + + case AF_INET6: + return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVERR, b); + + default: + return -EAFNOSUPPORT; + } +} + +int socket_set_recvttl(int fd, int af, bool b) { + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, b); + + case AF_INET6: + return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, b); + + default: + return -EAFNOSUPPORT; + } +} + +int socket_set_ttl(int fd, int af, int ttl) { + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + return setsockopt_int(fd, IPPROTO_IP, IP_TTL, ttl); + + case AF_INET6: + return setsockopt_int(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ttl); + + default: + return -EAFNOSUPPORT; + } +} + +int socket_set_unicast_if(int fd, int af, int ifi) { + be32_t ifindex_be = htobe32(ifi); + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + if (setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0) + return -errno; + + return 0; + + case AF_INET6: + if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0) + return -errno; + + return 0; + + default: + return -EAFNOSUPPORT; + } +} + +int socket_set_freebind(int fd, int af, bool b) { + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + return setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, b); + + case AF_INET6: + return setsockopt_int(fd, IPPROTO_IPV6, IPV6_FREEBIND, b); + + default: + return -EAFNOSUPPORT; + } +} + +int socket_set_transparent(int fd, int af, bool b) { + int r; + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: + return setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, b); + + case AF_INET6: + return setsockopt_int(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, b); + + default: + return -EAFNOSUPPORT; + } +} diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h index 5e5cf731..1ece9118 100644 --- a/shared/systemd/src/basic/socket-util.h +++ b/shared/systemd/src/basic/socket-util.h @@ -120,15 +120,26 @@ int netlink_family_from_string(const char *s) _pure_; bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b); -int fd_inc_sndbuf(int fd, size_t n); -int fd_inc_rcvbuf(int fd, size_t n); +int fd_set_sndbuf(int fd, size_t n, bool increase); +static inline int fd_inc_sndbuf(int fd, size_t n) { + return fd_set_sndbuf(fd, n, true); +} +int fd_set_rcvbuf(int fd, size_t n, bool increase); +static inline int fd_inc_rcvbuf(int fd, size_t n) { + return fd_set_rcvbuf(fd, n, true); +} int ip_tos_to_string_alloc(int i, char **s); int ip_tos_from_string(const char *s); -bool ifname_valid_full(const char *p, bool alternative); +typedef enum { + IFNAME_VALID_ALTERNATIVE = 1 << 0, + IFNAME_VALID_NUMERIC = 1 << 1, + _IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC, +} IfnameValidFlags; +bool ifname_valid_full(const char *p, IfnameValidFlags flags); static inline bool ifname_valid(const char *p) { - return ifname_valid_full(p, false); + return ifname_valid_full(p, 0); } bool address_label_valid(const char *p); @@ -207,6 +218,35 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \ }) +#define SOCKADDR_LEN(sa) \ + ({ \ + const union sockaddr_union *__sa = &(sa); \ + size_t _len; \ + switch(__sa->sa.sa_family) { \ + case AF_INET: \ + _len = sizeof(struct sockaddr_in); \ + break; \ + case AF_INET6: \ + _len = sizeof(struct sockaddr_in6); \ + break; \ + case AF_UNIX: \ + _len = SOCKADDR_UN_LEN(__sa->un); \ + break; \ + case AF_PACKET: \ + _len = SOCKADDR_LL_LEN(__sa->ll); \ + break; \ + case AF_NETLINK: \ + _len = sizeof(struct sockaddr_nl); \ + break; \ + case AF_VSOCK: \ + _len = sizeof(struct sockaddr_vm); \ + break; \ + default: \ + assert_not_reached("invalid socket family"); \ + } \ + _len; \ + }) + int socket_ioctl_fd(void); int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path); @@ -223,4 +263,11 @@ int socket_bind_to_ifindex(int fd, int ifindex); ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); -int socket_pass_pktinfo(int fd, bool b); +int socket_get_family(int fd, int *ret); +int socket_set_recvpktinfo(int fd, int af, bool b); +int socket_set_recverr(int fd, int af, bool b); +int socket_set_recvttl(int fd, int af, bool b); +int socket_set_ttl(int fd, int af, int ttl); +int socket_set_unicast_if(int fd, int af, int ifi); +int socket_set_freebind(int fd, int af, bool b); +int socket_set_transparent(int fd, int af, bool b); diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c index 5c51e13a..6d393041 100644 --- a/shared/systemd/src/basic/stat-util.c +++ b/shared/systemd/src/basic/stat-util.c @@ -17,6 +17,7 @@ #include "macro.h" #include "missing_fs.h" #include "missing_magic.h" +#include "missing_syscall.h" #include "parse-util.h" #include "stat-util.h" #include "string-util.h" @@ -420,4 +421,60 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) { a->st_ino == b->st_ino && (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */ } + +int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) { + static bool avoid_statx = false; + struct stat st; + + if (!avoid_statx) { + if (statx(dfd, path, flags, mask, sx) < 0) { + if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EPERM) + return -errno; + + /* If statx() is not supported or if we see EPERM (which might indicate seccomp + * filtering or so), let's do a fallback. Not that on EACCES we'll not fall back, + * since that is likely an indication of fs access issues, which we should + * propagate */ + } else + return 0; + + avoid_statx = true; + } + + /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are + * OK to ignore */ + if ((flags & ~(AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW| + AT_STATX_SYNC_AS_STAT|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC)) != 0) + return -EOPNOTSUPP; + + if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0) + return -errno; + + *sx = (struct statx) { + .stx_mask = STATX_TYPE|STATX_MODE| + STATX_NLINK|STATX_UID|STATX_GID| + STATX_ATIME|STATX_MTIME|STATX_CTIME| + STATX_INO|STATX_SIZE|STATX_BLOCKS, + .stx_blksize = st.st_blksize, + .stx_nlink = st.st_nlink, + .stx_uid = st.st_uid, + .stx_gid = st.st_gid, + .stx_mode = st.st_mode, + .stx_ino = st.st_ino, + .stx_size = st.st_size, + .stx_blocks = st.st_blocks, + .stx_rdev_major = major(st.st_rdev), + .stx_rdev_minor = minor(st.st_rdev), + .stx_dev_major = major(st.st_dev), + .stx_dev_minor = minor(st.st_dev), + .stx_atime.tv_sec = st.st_atim.tv_sec, + .stx_atime.tv_nsec = st.st_atim.tv_nsec, + .stx_mtime.tv_sec = st.st_mtim.tv_sec, + .stx_mtime.tv_nsec = st.st_mtim.tv_nsec, + .stx_ctime.tv_sec = st.st_ctim.tv_sec, + .stx_ctime.tv_nsec = st.st_ctim.tv_nsec, + }; + + return 0; +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h index 59aedcb7..26ecd635 100644 --- a/shared/systemd/src/basic/stat-util.h +++ b/shared/systemd/src/basic/stat-util.h @@ -10,6 +10,7 @@ #include <sys/vfs.h> #include "macro.h" +#include "missing_stat.h" int is_symlink(const char *path); int is_dir(const char *path, bool follow); @@ -91,3 +92,24 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret int proc_mounted(void); bool stat_inode_unmodified(const struct stat *a, const struct stat *b); + +int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx); + +#if HAS_FEATURE_MEMORY_SANITIZER +# warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this." +# define STRUCT_STATX_DEFINE(var) \ + struct statx var = {} +# define STRUCT_NEW_STATX_DEFINE(var) \ + union { \ + struct statx sx; \ + struct new_statx nsx; \ + } var = {} +#else +# define STRUCT_STATX_DEFINE(var) \ + struct statx var +# define STRUCT_NEW_STATX_DEFINE(var) \ + union { \ + struct statx sx; \ + struct new_statx nsx; \ + } var +#endif diff --git a/shared/systemd/src/basic/string-table.c b/shared/systemd/src/basic/string-table.c index 14ae6308..46014b18 100644 --- a/shared/systemd/src/basic/string-table.c +++ b/shared/systemd/src/basic/string-table.c @@ -6,12 +6,10 @@ #include "string-util.h" ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { - size_t i; - if (!key) return -1; - for (i = 0; i < len; ++i) + for (size_t i = 0; i < len; ++i) if (streq_ptr(table[i], key)) return (ssize_t) i; diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c index c30e88c5..aea13dcb 100644 --- a/shared/systemd/src/basic/string-util.c +++ b/shared/systemd/src/basic/string-util.c @@ -10,12 +10,14 @@ #include "alloc-util.h" #include "escape.h" +#include "extract-word.h" #include "fileio.h" #include "gunicode.h" #include "locale-util.h" #include "macro.h" #include "memory-util.h" #include "string-util.h" +#include "strv.h" #include "terminal-util.h" #include "utf8.h" #include "util.h" @@ -112,83 +114,6 @@ char* first_word(const char *s, const char *word) { return (char*) p; } -static size_t strcspn_escaped(const char *s, const char *reject) { - bool escaped = false; - int n; - - for (n = 0; s[n] != '\0'; n++) { - if (escaped) - escaped = false; - else if (s[n] == '\\') - escaped = true; - else if (strchr(reject, s[n])) - break; - } - - return n; -} - -/* Split a string into words. */ -const char* split( - const char **state, - size_t *l, - const char *separator, - SplitFlags flags) { - - const char *current; - - assert(state); - assert(l); - - if (!separator) - separator = WHITESPACE; - - current = *state; - - if (*current == '\0') /* already at the end? */ - return NULL; - - current += strspn(current, separator); /* skip leading separators */ - if (*current == '\0') { /* at the end now? */ - *state = current; - return NULL; - } - - if (FLAGS_SET(flags, SPLIT_QUOTES)) { - - if (strchr(QUOTES, *current)) { - /* We are looking at a quote */ - *l = strcspn_escaped(current + 1, CHAR_TO_STR(*current)); - if (current[*l + 1] != *current || - (current[*l + 2] != 0 && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end */ - if (FLAGS_SET(flags, SPLIT_RELAX)) { - *state = current + *l + 1 + (current[*l + 1] != '\0'); - return current + 1; - } - *state = current; - return NULL; - } - *state = current++ + *l + 2; - - } else { - /* We are looking at a something that is not a quote */ - *l = strcspn_escaped(current, separator); - if (current[*l] && !strchr(separator, current[*l]) && !FLAGS_SET(flags, SPLIT_RELAX)) { - /* unfinished escape */ - *state = current; - return NULL; - } - *state = current + *l; - } - } else { - *l = strcspn(current, separator); - *state = current + *l; - } - - return current; -} - char *strnappend(const char *s, const char *suffix, size_t b) { size_t a; char *r; @@ -1216,4 +1141,31 @@ int string_extract_line(const char *s, size_t i, char **ret) { c++; } } + +int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word) { + /* In the default mode with no separators specified, we split on whitespace and + * don't coalesce separators. */ + const ExtractFlags flags = separators ? EXTRACT_DONT_COALESCE_SEPARATORS : 0; + + const char *found = NULL; + + for (const char *p = string;;) { + _cleanup_free_ char *w = NULL; + int r; + + r = extract_first_word(&p, &w, separators, flags); + if (r < 0) + return r; + if (r == 0) + break; + + found = strv_find(words, w); + if (found) + break; + } + + if (ret_word) + *ret_word = found; + return !!found; +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h index 09131455..cefbda35 100644 --- a/shared/systemd/src/basic/string-util.h +++ b/shared/systemd/src/basic/string-util.h @@ -108,24 +108,6 @@ char *endswith_no_case(const char *s, const char *postfix) _pure_; char *first_word(const char *s, const char *word) _pure_; -typedef enum SplitFlags { - SPLIT_QUOTES = 0x01 << 0, - SPLIT_RELAX = 0x01 << 1, -} SplitFlags; - -/* Smelly. Do not use this anymore. Use extract_first_word() instead! */ -const char* split(const char **state, size_t *l, const char *separator, SplitFlags flags); - -/* Similar, don't use this anymore */ -#define FOREACH_WORD(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, 0, state) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - _FOREACH_WORD(word, length, s, separator, 0, state) - -#define _FOREACH_WORD(word, length, s, separator, flags, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (flags)); (word); (word) = split(&(state), &(length), (separator), (flags))) - char *strnappend(const char *s, const char *suffix, size_t length); char *strjoin_real(const char *x, ...) _sentinel_; @@ -135,8 +117,8 @@ char *strjoin_real(const char *x, ...) _sentinel_; ({ \ const char *_appendees_[] = { a, __VA_ARGS__ }; \ char *_d_, *_p_; \ - size_t _len_ = 0; \ - size_t _i_; \ + size_t _len_ = 0; \ + size_t _i_; \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _len_ += strlen(_appendees_[_i_]); \ _p_ = _d_ = newa(char, _len_ + 1); \ @@ -152,7 +134,6 @@ char *delete_trailing_chars(char *s, const char *bad); char *truncate_nl(char *s); static inline char *skip_leading_chars(const char *s, const char *bad) { - if (!s) return NULL; @@ -231,11 +212,9 @@ REENABLE_WARNING; /* Like startswith(), but operates on arbitrary memory blocks */ static inline void *memory_startswith(const void *p, size_t sz, const char *token) { - size_t n; - assert(token); - n = strlen(token); + size_t n = strlen(token); if (sz < n) return NULL; @@ -251,20 +230,17 @@ static inline void *memory_startswith(const void *p, size_t sz, const char *toke * It works only for ASCII strings. */ static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) { - size_t n, i; - assert(token); - n = strlen(token); + size_t n = strlen(token); if (sz < n) return NULL; assert(p); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i])) return NULL; - } return (uint8_t*) p + n; } @@ -286,3 +262,8 @@ char* string_erase(char *x); int string_truncate_lines(const char *s, size_t n_lines, char **ret); int string_extract_line(const char *s, size_t i, char **ret); + +int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word); +static inline int string_contains_word(const char *string, const char *separators, const char *word) { + return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL); +} diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c index 6f812139..30d3af46 100644 --- a/shared/systemd/src/basic/strv.c +++ b/shared/systemd/src/basic/strv.c @@ -260,44 +260,6 @@ int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) { } #endif /* NM_IGNORED */ -char **strv_split_full(const char *s, const char *separator, SplitFlags flags) { - const char *word, *state; - size_t l; - size_t n, i; - char **r; - - assert(s); - - if (!separator) - separator = WHITESPACE; - - s += strspn(s, separator); - if (isempty(s)) - return new0(char*, 1); - - n = 0; - _FOREACH_WORD(word, l, s, separator, flags, state) - n++; - - r = new(char*, n+1); - if (!r) - return NULL; - - i = 0; - _FOREACH_WORD(word, l, s, separator, flags, state) { - r[i] = strndup(word, l); - if (!r[i]) { - strv_free(r); - return NULL; - } - - i++; - } - - r[i] = NULL; - return r; -} - char **strv_split_newlines(const char *s) { char **l; size_t n; @@ -321,8 +283,7 @@ char **strv_split_newlines(const char *s) { return l; } -#if 0 /* NM_IGNORED */ -int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { +int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) { _cleanup_strv_free_ char **l = NULL; size_t n = 0, allocated = 0; int r; @@ -357,9 +318,62 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract return (int) n; } + +#if 0 /* NM_IGNORED */ +int strv_split_colon_pairs(char ***t, const char *s) { + _cleanup_strv_free_ char **l = NULL; + size_t n = 0, allocated = 0; + int r; + + assert(t); + assert(s); + + for (;;) { + _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL; + + r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r < 0) + return r; + if (r == 0) + break; + + const char *p = tuple; + r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, + &first, &second, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + /* Enforce that at most 2 colon-separated words are contained in each group */ + if (!isempty(p)) + return -EINVAL; + + second_or_empty = strdup(strempty(second)); + if (!second_or_empty) + return -ENOMEM; + + if (!GREEDY_REALLOC(l, allocated, n + 3)) + return -ENOMEM; + + l[n++] = TAKE_PTR(first); + l[n++] = TAKE_PTR(second_or_empty); + + l[n] = NULL; + } + + if (!l) { + l = new0(char*, 1); + if (!l) + return -ENOMEM; + } + + *t = TAKE_PTR(l); + + return (int) n; +} #endif /* NM_IGNORED */ -char *strv_join_prefix(char * const *l, const char *separator, const char *prefix) { +char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) { char * const *s; char *r, *e; size_t n, k, m; @@ -370,11 +384,17 @@ char *strv_join_prefix(char * const *l, const char *separator, const char *prefi k = strlen(separator); m = strlen_ptr(prefix); + if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */ + assert(k == 1); + n = 0; STRV_FOREACH(s, l) { if (s != l) n += k; - n += m + strlen(*s); + + bool needs_escaping = unescape_separators && strchr(*s, separator[0]); + + n += m + strlen(*s) * (1 + needs_escaping); } r = new(char, n+1); @@ -389,7 +409,16 @@ char *strv_join_prefix(char * const *l, const char *separator, const char *prefi if (prefix) e = stpcpy(e, prefix); - e = stpcpy(e, *s); + bool needs_escaping = unescape_separators && strchr(*s, separator[0]); + + if (needs_escaping) + for (size_t i = 0; (*s)[i]; i++) { + if ((*s)[i] == separator[0]) + *(e++) = '\\'; + *(e++) = (*s)[i]; + } + else + e = stpcpy(e, *s); } *e = 0; diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h index 2ad927bc..919fabf7 100644 --- a/shared/systemd/src/basic/strv.h +++ b/shared/systemd/src/basic/strv.h @@ -72,17 +72,28 @@ static inline bool strv_isempty(char * const *l) { return !l || !*l; } -char **strv_split_full(const char *s, const char *separator, SplitFlags flags); -static inline char **strv_split(const char *s, const char *separator) { - return strv_split_full(s, separator, 0); -} char **strv_split_newlines(const char *s); -int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); +int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags); +static inline char **strv_split(const char *s, const char *separators) { + char **ret; + int r; + + r = strv_split_full(&ret, s, separators, 0); + if (r < 0) + return NULL; + + return ret; +} -char *strv_join_prefix(char * const *l, const char *separator, const char *prefix); +/* Given a string containing white-space separated tuples of words themselves separated by ':', + * returns a vector of strings. If the second element in a tuple is missing, the corresponding + * string in the vector is an empty string. */ +int strv_split_colon_pairs(char ***t, const char *s); + +char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor); static inline char *strv_join(char * const *l, const char *separator) { - return strv_join_prefix(l, separator, NULL); + return strv_join_full(l, separator, NULL, false); } char **strv_parse_nulstr(const char *s, size_t l); @@ -118,10 +129,6 @@ bool strv_overlap(char * const *a, char * const *b) _pure_; char **strv_sort(char **l); void strv_print(char * const *l); -#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) - -#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) - #define strv_from_stdarg_alloca(first) \ ({ \ char **_l; \ diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c index 71af4f21..0fac79a7 100644 --- a/shared/systemd/src/basic/time-util.c +++ b/shared/systemd/src/basic/time-util.c @@ -25,6 +25,7 @@ #include "path-util.h" #include "process-util.h" #include "stat-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -84,43 +85,82 @@ triple_timestamp* triple_timestamp_get(triple_timestamp *ts) { return ts; } +static usec_t map_clock_usec_internal(usec_t from, usec_t from_base, usec_t to_base) { + + /* Maps the time 'from' between two clocks, based on a common reference point where the first clock + * is at 'from_base' and the second clock at 'to_base'. Basically calculates: + * + * from - from_base + to_base + * + * But takes care of overflows/underflows and avoids signed operations. */ + + if (from >= from_base) { /* In the future */ + usec_t delta = from - from_base; + + if (to_base >= USEC_INFINITY - delta) /* overflow? */ + return USEC_INFINITY; + + return to_base + delta; + + } else { /* In the past */ + usec_t delta = from_base - from; + + if (to_base <= delta) /* underflow? */ + return 0; + + return to_base - delta; + } +} + +usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) { + + /* Try to avoid any inaccuracy needlessly added in case we convert from effectively the same clock + * onto itself */ + if (map_clock_id(from_clock) == map_clock_id(to_clock)) + return from; + + /* Keep infinity as is */ + if (from == USEC_INFINITY) + return from; + + return map_clock_usec_internal(from, now(from_clock), now(to_clock)); +} + dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { - int64_t delta; assert(ts); - if (u == USEC_INFINITY || u <= 0) { + if (u == USEC_INFINITY || u == 0) { ts->realtime = ts->monotonic = u; return ts; } ts->realtime = u; - - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta); - + ts->monotonic = map_clock_usec(u, CLOCK_REALTIME, CLOCK_MONOTONIC); return ts; } triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) { - int64_t delta; + usec_t nowr; assert(ts); - if (u == USEC_INFINITY || u <= 0) { + if (u == USEC_INFINITY || u == 0) { ts->realtime = ts->monotonic = ts->boottime = u; return ts; } + nowr = now(CLOCK_REALTIME); + ts->realtime = u; - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta); - ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY; + ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC)); + ts->boottime = clock_boottime_supported() ? + map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME)) : + USEC_INFINITY; return ts; } dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { - int64_t delta; assert(ts); if (u == USEC_INFINITY) { @@ -129,25 +169,28 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { } ts->monotonic = u; - delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u; - ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta); - + ts->realtime = map_clock_usec(u, CLOCK_MONOTONIC, CLOCK_REALTIME); return ts; } dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) { - int64_t delta; + clockid_t cid; + usec_t nowm; if (u == USEC_INFINITY) { ts->realtime = ts->monotonic = USEC_INFINITY; return ts; } - dual_timestamp_get(ts); - delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u; - ts->realtime = usec_sub_signed(ts->realtime, delta); - ts->monotonic = usec_sub_signed(ts->monotonic, delta); + cid = clock_boottime_or_monotonic(); + nowm = now(cid); + + if (cid == CLOCK_MONOTONIC) + ts->monotonic = u; + else + ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC)); + ts->realtime = map_clock_usec_internal(u, nowm, now(CLOCK_REALTIME)); return ts; } @@ -203,12 +246,28 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u) { if (u == USEC_INFINITY || u / USEC_PER_SEC >= TIME_T_MAX) { ts->tv_sec = (time_t) -1; - ts->tv_nsec = (long) -1; + ts->tv_nsec = -1L; return ts; } ts->tv_sec = (time_t) (u / USEC_PER_SEC); - ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); + ts->tv_nsec = (long) ((u % USEC_PER_SEC) * NSEC_PER_USEC); + + return ts; +} + +struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n) { + assert(ts); + + if (n == NSEC_INFINITY || + n / NSEC_PER_SEC >= TIME_T_MAX) { + ts->tv_sec = (time_t) -1; + ts->tv_nsec = -1L; + return ts; + } + + ts->tv_sec = (time_t) (n / NSEC_PER_SEC); + ts->tv_nsec = (long) (n % NSEC_PER_SEC); return ts; } @@ -243,12 +302,11 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) { return tv; } -static char *format_timestamp_internal( +char *format_timestamp_style( char *buf, size_t l, usec_t t, - bool utc, - bool us) { + TimestampStyle style) { /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our * generated timestamps may be parsed with parse_timestamp(), and always read the same. */ @@ -265,9 +323,27 @@ static char *format_timestamp_internal( struct tm tm; time_t sec; size_t n; + bool utc = false, us = false; assert(buf); + switch (style) { + case TIMESTAMP_PRETTY: + break; + case TIMESTAMP_US: + us = true; + break; + case TIMESTAMP_UTC: + utc = true; + break; + case TIMESTAMP_US_UTC: + us = true; + utc = true; + break; + default: + return NULL; + } + if (l < (size_t) (3 + /* week day */ 1 + 10 + /* space and date */ 1 + 8 + /* space and time */ @@ -341,22 +417,6 @@ static char *format_timestamp_internal( return buf; } -char *format_timestamp(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, false, false); -} - -char *format_timestamp_utc(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, true, false); -} - -char *format_timestamp_us(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, false, true); -} - -char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, true, true); -} - char *format_timestamp_relative(char *buf, size_t l, usec_t t) { const char *s; usec_t n, d; @@ -1533,4 +1593,28 @@ int time_change_fd(void) { return -errno; } + +static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = { + [TIMESTAMP_PRETTY] = "pretty", + [TIMESTAMP_US] = "us", + [TIMESTAMP_UTC] = "utc", + [TIMESTAMP_US_UTC] = "us+utc", +}; + +/* Use the macro for enum → string to allow for aliases */ +_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,); + +/* For the string → enum mapping we use the generic implementation, but also support two aliases */ +TimestampStyle timestamp_style_from_string(const char *s) { + TimestampStyle t; + + t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s); + if (t >= 0) + return t; + if (streq_ptr(s, "µs")) + return TIMESTAMP_US; + if (streq_ptr(s, "µs+uts")) + return TIMESTAMP_US_UTC; + return t; +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h index 4c371257..cecd5efa 100644 --- a/shared/systemd/src/basic/time-util.h +++ b/shared/systemd/src/basic/time-util.h @@ -29,8 +29,17 @@ typedef struct triple_timestamp { usec_t boottime; } triple_timestamp; -#define USEC_INFINITY ((usec_t) -1) -#define NSEC_INFINITY ((nsec_t) -1) +typedef enum TimestampStyle { + TIMESTAMP_PRETTY, + TIMESTAMP_US, + TIMESTAMP_UTC, + TIMESTAMP_US_UTC, + _TIMESTAMP_STYLE_MAX, + _TIMESTAMP_STYLE_INVALID = -1, +} TimestampStyle; + +#define USEC_INFINITY ((usec_t) UINT64_MAX) +#define NSEC_INFINITY ((nsec_t) UINT64_MAX) #define MSEC_PER_SEC 1000ULL #define USEC_PER_SEC ((usec_t) 1000000ULL) @@ -67,6 +76,8 @@ typedef struct triple_timestamp { usec_t now(clockid_t clock); nsec_t now_nsec(clockid_t clock); +usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock); + dual_timestamp* dual_timestamp_get(dual_timestamp *ts); dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); @@ -101,17 +112,19 @@ usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock); usec_t timespec_load(const struct timespec *ts) _pure_; nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; struct timespec *timespec_store(struct timespec *ts, usec_t u); +struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n); usec_t timeval_load(const struct timeval *tv) _pure_; struct timeval *timeval_store(struct timeval *tv, usec_t u); -char *format_timestamp(char *buf, size_t l, usec_t t); -char *format_timestamp_utc(char *buf, size_t l, usec_t t); -char *format_timestamp_us(char *buf, size_t l, usec_t t); -char *format_timestamp_us_utc(char *buf, size_t l, usec_t t); +char *format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style); char *format_timestamp_relative(char *buf, size_t l, usec_t t); char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); +static inline char *format_timestamp(char *buf, size_t l, usec_t t) { + return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY); +} + int parse_timestamp(const char *t, usec_t *usec); int parse_sec(const char *t, usec_t *usec); @@ -183,3 +196,6 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { #endif int time_change_fd(void); + +const char* timestamp_style_to_string(TimestampStyle t) _const_; +TimestampStyle timestamp_style_from_string(const char *s) _pure_; diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c index 8bbd12b0..9b3621ba 100644 --- a/shared/systemd/src/basic/tmpfile-util.c +++ b/shared/systemd/src/basic/tmpfile-util.c @@ -262,7 +262,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { assert((flags & O_EXCL) == 0); /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in - * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in + * which case "ret_path" will be returned as NULL. If not possible the temporary path name used is returned in * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */ fd = open_parent(target, O_TMPFILE|flags, 0640); diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c index f2e27b68..8159b187 100644 --- a/shared/systemd/src/basic/utf8.c +++ b/shared/systemd/src/basic/utf8.c @@ -125,7 +125,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) { return 0; } -bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { +bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) { const char *p; assert(str); @@ -142,7 +142,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { r = utf8_encoded_to_unichar(p, &val); if (r < 0 || unichar_is_control(val) || - (!newline && val == '\n')) + (!allow_newline && val == '\n')) return false; length -= encoded_len; @@ -152,18 +152,22 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { return true; } -char *utf8_is_valid(const char *str) { - const char *p; +char *utf8_is_valid_n(const char *str, size_t len_bytes) { + /* Check if the string is composed of valid utf8 characters. If length len_bytes is given, stop after + * len_bytes. Otherwise, stop at NUL. */ assert(str); - p = str; - while (*p) { + for (const char *p = str; len_bytes != (size_t) -1 ? (size_t) (p - str) < len_bytes : *p != '\0'; ) { int len; - len = utf8_encoded_valid_unichar(p, (size_t) -1); - if (len < 0) - return NULL; + if (_unlikely_(*p == '\0') && len_bytes != (size_t) -1) + return NULL; /* embedded NUL */ + + len = utf8_encoded_valid_unichar(p, + len_bytes != (size_t) -1 ? len_bytes - (p - str) : (size_t) -1); + if (_unlikely_(len < 0)) + return NULL; /* invalid character */ p += len; } diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h index 62e99b72..f315ea0f 100644 --- a/shared/systemd/src/basic/utf8.h +++ b/shared/systemd/src/basic/utf8.h @@ -14,11 +14,14 @@ bool unichar_is_valid(char32_t c); -char *utf8_is_valid(const char *s) _pure_; +char *utf8_is_valid_n(const char *str, size_t len_bytes) _pure_; +static inline char *utf8_is_valid(const char *s) { + return utf8_is_valid_n(s, (size_t) -1); +} char *ascii_is_valid(const char *s) _pure_; char *ascii_is_valid_n(const char *str, size_t len); -bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; +bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_; #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) char *utf8_escape_invalid(const char *s); diff --git a/shared/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c index 9bba7359..6d60eb58 100644 --- a/shared/systemd/src/shared/dns-domain.c +++ b/shared/systemd/src/shared/dns-domain.c @@ -45,8 +45,9 @@ int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags f /* Trailing dash */ return -EINVAL; - if (*n == '.') + if (n[0] == '.' && (n[1] != 0 || !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT))) n++; + break; } @@ -143,7 +144,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags f return -EINVAL; /* More than one trailing dot? */ - if (*n == '.') + if (n[0] == '.' && !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT)) return -EINVAL; if (sz >= 1 && d) @@ -1383,4 +1384,20 @@ int dns_name_is_valid_or_address(const char *name) { return dns_name_is_valid(name); } + +int dns_name_dot_suffixed(const char *name) { + const char *p = name; + int r; + + for (;;) { + if (streq(p, ".")) + return true; + + r = dns_label_unescape(&p, NULL, DNS_LABEL_MAX, DNS_LABEL_LEAVE_TRAILING_DOT); + if (r < 0) + return r; + if (r == 0) + return false; + } +} #endif /* NM_IGNORED */ diff --git a/shared/systemd/src/shared/dns-domain.h b/shared/systemd/src/shared/dns-domain.h index 88b3eb11..e4e5b1b9 100644 --- a/shared/systemd/src/shared/dns-domain.h +++ b/shared/systemd/src/shared/dns-domain.h @@ -25,8 +25,9 @@ #define DNS_N_LABELS_MAX 127 typedef enum DNSLabelFlags { - DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */ - DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */ + DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */ + DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */ + DNS_LABEL_LEAVE_TRAILING_DOT = 1 << 2, /* Leave trailing dot in place */ } DNSLabelFlags; int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags); @@ -112,3 +113,5 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret); int dns_name_apply_idna(const char *name, char **ret); int dns_name_is_valid_or_address(const char *name); + +int dns_name_dot_suffixed(const char *name); |