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