diff options
| author | Michael Biebl <biebl@debian.org> | 2017-11-07 00:14:39 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-11-07 00:14:39 +0100 |
| commit | 90e8691111889a7b5f3c812f5a41f15a8a058913 (patch) | |
| tree | f101a879eca27c34a9bfa5f3da52266b22539a36 /src/nm-core-utils.c | |
| parent | bdb6eeb0670658255c2a4c3c501c0a27fa8cfe55 (diff) | |
New upstream version 1.9.90 upstream/1.9.90
Diffstat (limited to 'src/nm-core-utils.c')
| -rw-r--r-- | src/nm-core-utils.c | 604 |
1 files changed, 246 insertions, 358 deletions
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index aaaf7b6c..a8ff3513 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -26,7 +26,6 @@ #include <errno.h> #include <fcntl.h> #include <string.h> -#include <poll.h> #include <unistd.h> #include <stdlib.h> #include <resolv.h> @@ -37,6 +36,7 @@ #include <linux/if_infiniband.h> #include <net/ethernet.h> +#include "nm-utils/nm-random-utils.h" #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-connection.h" @@ -110,10 +110,6 @@ _nm_utils_set_testing (NMUtilsTestFlags flags) /*****************************************************************************/ -const NMIPAddr nm_ip_addr_zero = NMIPAddrInit; - -/*****************************************************************************/ - static GSList *_singletons = NULL; static gboolean _singletons_shutdown = FALSE; @@ -265,7 +261,7 @@ nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) { - return addr & nm_utils_ip4_prefix_to_netmask (plen); + return addr & _nm_utils_ip4_prefix_to_netmask (plen); } /* nm_utils_ip6_address_clear_host_address: @@ -274,15 +270,17 @@ nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) * @plen: prefix length of network * * Note: this function is self assignment safe, to update @src inplace, set both - * @dst and @src to the same destination. + * @dst and @src to the same destination or set @src NULL. */ const struct in6_addr * nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen) { g_return_val_if_fail (plen <= 128, NULL); - g_return_val_if_fail (src, NULL); g_return_val_if_fail (dst, NULL); + if (!src) + src = dst; + if (plen < 128) { guint nbytes = plen / 8; guint nbits = plen % 8; @@ -301,28 +299,28 @@ nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_ return dst; } -gboolean -nm_utils_ip6_address_same_prefix (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen) +int +nm_utils_ip6_address_same_prefix_cmp (const struct in6_addr *addr_a, const struct in6_addr *addr_b, guint8 plen) { int nbytes; - guint8 t, m; + guint8 va, vb, m; if (plen >= 128) - return memcmp (addr_a, addr_b, sizeof (struct in6_addr)) == 0; - - nbytes = plen / 8; - if (nbytes) { - if (memcmp (addr_a, addr_b, nbytes) != 0) - return FALSE; + NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, sizeof (struct in6_addr)); + else { + nbytes = plen / 8; + if (nbytes) + NM_CMP_DIRECT_MEMCMP (addr_a, addr_b, nbytes); + + plen = plen % 8; + if (plen != 0) { + m = ~((1 << (8 - plen)) - 1); + va = ((((const guint8 *) addr_a))[nbytes]) & m; + vb = ((((const guint8 *) addr_b))[nbytes]) & m; + NM_CMP_DIRECT (va, vb); + } } - - plen = plen % 8; - if (plen == 0) - return TRUE; - - m = ~((1 << (8 - plen)) - 1); - t = ((((const guint8 *) addr_a))[nbytes]) ^ ((((const guint8 *) addr_b))[nbytes]); - return (t & m) == 0; + return 0; } /*****************************************************************************/ @@ -1820,81 +1818,6 @@ nm_match_spec_join (GSList *specs) /*****************************************************************************/ -char _nm_utils_to_string_buffer[]; - -void -nm_utils_to_string_buffer_init (char **buf, gsize *len) -{ - if (!*buf) { - *buf = _nm_utils_to_string_buffer; - *len = sizeof (_nm_utils_to_string_buffer); - } -} - -gboolean -nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len) -{ - nm_utils_to_string_buffer_init (buf, len); - if (!obj) { - g_strlcpy (*buf, "(null)", *len); - return FALSE; - } - return TRUE; -} - -const char * -nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, - gsize n_descs, - unsigned flags, - char *buf, - gsize len) -{ - gsize i; - char *p; - -#if NM_MORE_ASSERTS > 10 - nm_assert (descs); - nm_assert (n_descs > 0); - for (i = 0; i < n_descs; i++) { - gsize j; - - nm_assert (descs[i].flag && nm_utils_is_power_of_two (descs[i].flag)); - nm_assert (descs[i].name && descs[i].name[0]); - for (j = 0; j < i; j++) - nm_assert (descs[j].flag != descs[i].flag); - } -#endif - - nm_utils_to_string_buffer_init (&buf, &len); - - if (!len) - return buf; - - buf[0] = '\0'; - if (!flags) { - return buf; - } - - p = buf; - for (i = 0; flags && i < n_descs; i++) { - if (NM_FLAGS_HAS (flags, descs[i].flag)) { - flags &= ~descs[i].flag; - - if (buf[0] != '\0') - nm_utils_strbuf_append_c (&p, &len, ','); - nm_utils_strbuf_append_str (&p, &len, descs[i].name); - } - } - if (flags) { - if (buf[0] != '\0') - nm_utils_strbuf_append_c (&p, &len, ','); - nm_utils_strbuf_append (&p, &len, "0x%x", flags); - } - return buf; -}; - -/*****************************************************************************/ - char * nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id) { @@ -1952,101 +1875,109 @@ nm_utils_new_infiniband_name (char *name, const char *parent_name, int p_key) return name; } -/** - * nm_utils_read_resolv_conf_nameservers(): - * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf - * - * Reads all nameservers out of @rc_contents or /etc/resolv.conf and returns - * them. - * - * Returns: a #GPtrArray of 'char *' elements of each nameserver line from - * @contents or resolv.conf - */ -GPtrArray * -nm_utils_read_resolv_conf_nameservers (const char *rc_contents) -{ - GPtrArray *nameservers = NULL; - char *contents = NULL; - char **lines, **iter; - char *p; - - if (rc_contents) - contents = g_strdup (rc_contents); - else { - if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL)) - return NULL; - } - - nameservers = g_ptr_array_new_full (3, g_free); - - lines = g_strsplit_set (contents, "\r\n", -1); - for (iter = lines; *iter; iter++) { - if (!g_str_has_prefix (*iter, "nameserver")) - continue; - p = *iter + strlen ("nameserver"); - if (!g_ascii_isspace (*p++)) - continue; - /* Skip intermediate whitespace */ - while (g_ascii_isspace (*p)) - p++; - g_strchomp (p); +/*****************************************************************************/ - g_ptr_array_add (nameservers, g_strdup (p)); - } - g_strfreev (lines); - g_free (contents); +gboolean +nm_utils_resolve_conf_parse (int addr_family, + const char *rc_contents, + GArray *nameservers, + GPtrArray *dns_options) +{ + guint i; + gboolean changed = FALSE; + gs_free const char **lines = NULL; + gsize l; + + g_return_val_if_fail (rc_contents, FALSE); + g_return_val_if_fail (nameservers, FALSE); + g_return_val_if_fail ( ( addr_family == AF_INET + && g_array_get_element_size (nameservers) == sizeof (in_addr_t)) + || ( addr_family == AF_INET6 + && g_array_get_element_size (nameservers) == sizeof (struct in6_addr)), FALSE); + + lines = nm_utils_strsplit_set (rc_contents, "\r\n"); + if (!lines) + return FALSE; - return nameservers; -} +/* like glibc's MATCH() macro in resolv/res_init.c. */ +#define RC_MATCH(line, option, out_arg) \ + ({ \ + const char *const _line = (line); \ + gboolean _match = FALSE; \ + \ + if ( (strncmp (_line, option, NM_STRLEN (option)) == 0) \ + && (NM_IN_SET (_line[NM_STRLEN (option)], ' ', '\t'))) { \ + _match = TRUE;\ + (out_arg) = &_line[NM_STRLEN (option) + 1]; \ + } \ + _match; \ + }) + + for (l = 0; lines[l]; l++) { + const char *const line = lines[l]; + const char *s = NULL; + + if (RC_MATCH (line, "nameserver", s)) { + gs_free char *s_cpy = NULL; + NMIPAddr ns; + + s = nm_strstrip_avoid_copy (s, &s_cpy); + if (inet_pton (addr_family, s, &ns) != 1) + continue; -/** - * nm_utils_read_resolv_conf_dns_options(): - * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf - * - * Reads all dns options out of @rc_contents or /etc/resolv.conf and returns - * them. - * - * Returns: a #GPtrArray of 'char *' elements of each option - */ -GPtrArray * -nm_utils_read_resolv_conf_dns_options (const char *rc_contents) -{ - GPtrArray *options = NULL; - char *contents = NULL; - char **lines, **line_iter; - char **tokens, **token_iter; - char *p; - - if (rc_contents) - contents = g_strdup (rc_contents); - else { - if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL)) - return NULL; - } + if (addr_family == AF_INET) { + if (!ns.addr4) + continue; + for (i = 0; i < nameservers->len; i++) { + if (g_array_index (nameservers, guint32, i) == ns.addr4) + break; + } + } else { + if (IN6_IS_ADDR_UNSPECIFIED (&ns.addr6)) + continue; + for (i = 0; i < nameservers->len; i++) { + struct in6_addr *t = &g_array_index (nameservers, struct in6_addr, i); - options = g_ptr_array_new_full (3, g_free); + if (IN6_ARE_ADDR_EQUAL (t, &ns.addr6)) + break; + } + } - lines = g_strsplit_set (contents, "\r\n", -1); - for (line_iter = lines; *line_iter; line_iter++) { - if (!g_str_has_prefix (*line_iter, "options")) - continue; - p = *line_iter + strlen ("options"); - if (!g_ascii_isspace (*p++)) + if (i == nameservers->len) { + g_array_append_val (nameservers, ns); + changed = TRUE; + } continue; + } - tokens = g_strsplit (p, " ", 0); - for (token_iter = tokens; token_iter && *token_iter; token_iter++) { - g_strstrip (*token_iter); - if (!*token_iter[0]) + if (RC_MATCH (line, "options", s)) { + if (!dns_options) continue; - g_ptr_array_add (options, g_strdup (*token_iter)); + + s = nm_str_skip_leading_spaces (s); + if (s[0]) { + gs_free const char **tokens = NULL; + gsize i_tokens; + + tokens = nm_utils_strsplit_set (s, " \t"); + nm_assert (tokens); + for (i_tokens = 0; tokens[i_tokens]; i_tokens++) { + gs_free char *t = g_strstrip (g_strdup (tokens[i_tokens])); + + if ( _nm_utils_dns_option_validate (t, NULL, NULL, + addr_family == AF_INET6, + _nm_utils_dns_option_descs) + && _nm_utils_dns_option_find_idx (dns_options, t) < 0) { + g_ptr_array_add (dns_options, g_steal_pointer (&t)); + changed = TRUE; + } + } + } + continue; } - g_strfreev (tokens); } - g_strfreev (lines); - g_free (contents); - return options; + return changed; } /*****************************************************************************/ @@ -2131,7 +2062,7 @@ monotonic_timestamp_get (struct timespec *tp) break; case 2: /* fallback, return CLOCK_MONOTONIC. Kernels prior to 2.6.39 - * don't support CLOCK_BOOTTIME. */ + * (released on 18 May, 2011) don't support CLOCK_BOOTTIME. */ err = clock_gettime (CLOCK_MONOTONIC, tp); break; } @@ -2292,7 +2223,7 @@ _log_connection_sort_hashes_fcn (gconstpointer a, gconstpointer b) { const LogConnectionSettingData *v1 = a; const LogConnectionSettingData *v2 = b; - guint32 p1, p2; + NMSettingPriority p1, p2; NMSetting *s1, *s2; s1 = v1->setting ? v1->setting : v1->diff_base_setting; @@ -2432,12 +2363,26 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, if (!name) name = ""; - connection_diff_are_same = nm_connection_diff (connection, diff_base, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &connection_diff); + connection_diff_are_same = nm_connection_diff (connection, diff_base, + NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, + &connection_diff); if (connection_diff_are_same) { - if (diff_base) - nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s and %p/%s): no difference", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base)); - else - nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s): no properties set", prefix, name, connection, G_OBJECT_TYPE_NAME (connection)); + const char *t1, *t2; + + t1 = nm_connection_get_connection_type (connection); + if (diff_base) { + t2 = nm_connection_get_connection_type (diff_base); + nm_log (level, domain, NULL, NULL, + "%sconnection '%s' (%p/%s/%s%s%s and %p/%s/%s%s%s): no difference", + prefix, name, + connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), + diff_base, G_OBJECT_TYPE_NAME (diff_base), NM_PRINT_FMT_QUOTE_STRING (t2)); + } else { + nm_log (level, domain, NULL, NULL, + "%sconnection '%s' (%p/%s/%s%s%s): no properties set", + prefix, name, + connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1)); + } g_assert (!connection_diff); return; } @@ -2471,12 +2416,20 @@ nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, if (print_header) { GError *err_verify = NULL; const char *path = nm_connection_get_path (connection); + const char *t1, *t2; + t1 = nm_connection_get_connection_type (connection); if (diff_base) { - nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s < %p/%s)%s%s%s:", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), diff_base, G_OBJECT_TYPE_NAME (diff_base), + t2 = nm_connection_get_connection_type (diff_base); + nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s/%s%s%s < %p/%s/%s%s%s)%s%s%s:", + prefix, name, + connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), + diff_base, G_OBJECT_TYPE_NAME (diff_base), NM_PRINT_FMT_QUOTE_STRING (t2), NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); } else { - nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s):%s%s%s", prefix, name, connection, G_OBJECT_TYPE_NAME (connection), + nm_log (level, domain, NULL, NULL, "%sconnection '%s' (%p/%s/%s%s%s):%s%s%s", + prefix, name, + connection, G_OBJECT_TYPE_NAME (connection), NM_PRINT_FMT_QUOTE_STRING (t1), NM_PRINT_FMT_QUOTED (path, " [", path, "]", "")); } print_header = FALSE; @@ -2572,55 +2525,88 @@ nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_ #define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/" #define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/" G_STATIC_ASSERT (sizeof (IPV4_PROPERTY_DIR) == sizeof (IPV6_PROPERTY_DIR)); +G_STATIC_ASSERT (NM_STRLEN (IPV6_PROPERTY_DIR) + IFNAMSIZ + 60 == NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE); -static const char * -_get_property_path (const char *ifname, - const char *property, - gboolean ipv6) +/** + * nm_utils_sysctl_ip_conf_path: + * @addr_family: either AF_INET or AF_INET6. + * @buf: the output buffer where to write the path. It + * must be at least NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE bytes + * long. + * @ifname: an interface name + * @property: a property name + * + * Returns: the path to IPv6 property @property on @ifname. Note that + * this returns the input argument @buf. + */ +const char * +nm_utils_sysctl_ip_conf_path (int addr_family, char *buf, const char *ifname, const char *property) { - static char path[sizeof (IPV6_PROPERTY_DIR) + IFNAMSIZ + 32]; int len; - ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname); + nm_assert (buf); + nm_assert_addr_family (addr_family); + + g_assert (nm_utils_is_valid_iface_name (ifname, NULL)); property = NM_ASSERT_VALID_PATH_COMPONENT (property); - len = g_snprintf (path, - sizeof (path), + len = g_snprintf (buf, + NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE, "%s%s/%s", - ipv6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR, + addr_family == AF_INET6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR, ifname, property); - g_assert (len < sizeof (path) - 1); - - return path; + g_assert (len < NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE - 1); + return buf; } -/** - * nm_utils_ip6_property_path: - * @ifname: an interface name - * @property: a property name - * - * Returns the path to IPv6 property @property on @ifname. Note that - * this uses a static buffer. - */ -const char * -nm_utils_ip6_property_path (const char *ifname, const char *property) +gboolean +nm_utils_sysctl_ip_conf_is_path (int addr_family, const char *path, const char *ifname, const char *property) { - return _get_property_path (ifname, property, TRUE); -} + g_return_val_if_fail (path, FALSE); + NM_ASSERT_VALID_PATH_COMPONENT (property); + g_assert (!ifname || nm_utils_is_valid_iface_name (ifname, NULL)); -/** - * nm_utils_ip4_property_path: - * @ifname: an interface name - * @property: a property name - * - * Returns the path to IPv4 property @property on @ifname. Note that - * this uses a static buffer. - */ -const char * -nm_utils_ip4_property_path (const char *ifname, const char *property) -{ - return _get_property_path (ifname, property, FALSE); + if (addr_family == AF_INET) { + if (!g_str_has_prefix (path, IPV4_PROPERTY_DIR)) + return FALSE; + path += NM_STRLEN (IPV4_PROPERTY_DIR); + } else if (addr_family == AF_INET6) { + if (!g_str_has_prefix (path, IPV6_PROPERTY_DIR)) + return FALSE; + path += NM_STRLEN (IPV6_PROPERTY_DIR); + } else + g_return_val_if_reached (FALSE); + + if (ifname) { + if (!g_str_has_prefix (path, ifname)) + return FALSE; + path += strlen (ifname); + if (path[0] != '/') + return FALSE; + path++; + } else { + const char *slash; + char buf[IFNAMSIZ]; + gsize l; + + slash = strchr (path, '/'); + if (!slash) + return FALSE; + l = slash - path; + if (l >= IFNAMSIZ) + return FALSE; + memcpy (buf, path, l); + buf[l] = '\0'; + if (!nm_utils_is_valid_iface_name (buf, NULL)) + return FALSE; + path = slash + 1; + } + + if (!nm_streq (path, property)) + return FALSE; + + return TRUE; } gboolean @@ -2733,99 +2719,6 @@ nm_utils_machine_id_read (void) /*****************************************************************************/ -/* taken from systemd's fd_wait_for_event(). Note that the timeout - * is here in nano-seconds, not micro-seconds. */ -int -nm_utils_fd_wait_for_event (int fd, int event, gint64 timeout_ns) -{ - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; - struct timespec ts, *pts; - int r; - - if (timeout_ns < 0) - pts = NULL; - else { - ts.tv_sec = (time_t) (timeout_ns / NM_UTILS_NS_PER_SECOND); - ts.tv_nsec = (long int) (timeout_ns % NM_UTILS_NS_PER_SECOND); - pts = &ts; - } - - r = ppoll (&pollfd, 1, pts, NULL); - if (r < 0) - return -errno; - if (r == 0) - return 0; - return pollfd.revents; -} - -/* taken from systemd's loop_read() */ -ssize_t -nm_utils_fd_read_loop (int fd, void *buf, size_t nbytes, bool do_poll) -{ - uint8_t *p = buf; - ssize_t n = 0; - - g_return_val_if_fail (fd >= 0, -EINVAL); - g_return_val_if_fail (buf, -EINVAL); - - /* If called with nbytes == 0, let's call read() at least - * once, to validate the operation */ - - if (nbytes > (size_t) SSIZE_MAX) - return -EINVAL; - - do { - ssize_t k; - - k = read (fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; - - if (errno == EAGAIN && do_poll) { - - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ - - (void) nm_utils_fd_wait_for_event (fd, POLLIN, -1); - continue; - } - - return n > 0 ? n : -errno; - } - - if (k == 0) - return n; - - g_assert ((size_t) k <= nbytes); - - p += k; - nbytes -= k; - n += k; - } while (nbytes > 0); - - return n; -} - -/* taken from systemd's loop_read_exact() */ -int -nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll) -{ - ssize_t n; - - n = nm_utils_fd_read_loop (fd, buf, nbytes, do_poll); - if (n < 0) - return (int) n; - if ((size_t) n != nbytes) - return -EIO; - - return 0; -} - _nm_printf (3, 4) static int _get_contents_error (GError **error, int errsv, const char *format, ...) @@ -2856,6 +2749,8 @@ _get_contents_error (GError **error, int errsv, const char *format, ...) * nm_utils_fd_get_contents: * @fd: open file descriptor to read. The fd will not be closed, * but don't rely on it's state afterwards. + * @close_fd: if %TRUE, @fd will be closed by the function. + * Passing %TRUE here might safe a syscall for dup(). * @max_length: allocate at most @max_length bytes. If the * file is larger, reading will fail. Set to zero to use * a very large default. @@ -2883,11 +2778,13 @@ _get_contents_error (GError **error, int errsv, const char *format, ...) */ int nm_utils_fd_get_contents (int fd, + gboolean close_fd, gsize max_length, char **contents, gsize *length, GError **error) { + nm_auto_close int fd_keeper = close_fd ? fd : -1; struct stat stat_buf; gs_free char *str = NULL; @@ -2933,9 +2830,20 @@ nm_utils_fd_get_contents (int fd, nm_auto_fclose FILE *f = NULL; char buf[4096]; gsize n_have, n_alloc; + int fd2; + + if (fd_keeper >= 0) + fd2 = nm_steal_fd (&fd_keeper); + else { + fd2 = dup (fd); + if (fd2 < 0) + return _get_contents_error (error, 0, "error during dup"); + } - if (!(f = fdopen (fd, "r"))) + if (!(f = fdopen (fd2, "r"))) { + close (fd2); return _get_contents_error (error, 0, "failure during fdopen"); + } n_have = 0; n_alloc = 0; @@ -3025,7 +2933,7 @@ nm_utils_file_get_contents (int dirfd, gsize *length, GError **error) { - nm_auto_close int fd = -1; + int fd; int errsv; g_return_val_if_fail (filename && filename[0], -EINVAL); @@ -3058,6 +2966,7 @@ nm_utils_file_get_contents (int dirfd, } } return nm_utils_fd_get_contents (fd, + TRUE, max_length, contents, length, @@ -3066,30 +2975,6 @@ nm_utils_file_get_contents (int dirfd, /*****************************************************************************/ -/* taken from systemd's dev_urandom(). */ -int -nm_utils_read_urandom (void *p, size_t nbytes) -{ - int fd = -1; - int r; - -again: - fd = open ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); - if (fd < 0) { - r = errno; - if (r == EINTR) - goto again; - return r == ENOENT ? -ENOSYS : -r; - } - - r = nm_utils_fd_read_loop_exact (fd, p, nbytes, TRUE); - close (fd); - - return r; -} - -/*****************************************************************************/ - guint8 * nm_utils_secret_key_read (gsize *out_key_len, GError **error) { @@ -3108,7 +2993,6 @@ nm_utils_secret_key_read (gsize *out_key_len, GError **error) key_len = 0; } } else { - int r; mode_t key_mask; /* RFC7217 mandates the key SHOULD be at least 128 bits. @@ -3116,10 +3000,9 @@ nm_utils_secret_key_read (gsize *out_key_len, GError **error) key_len = 32; secret_key = g_malloc (key_len); - r = nm_utils_read_urandom (secret_key, key_len); - if (r < 0) { + if (!nm_utils_random_bytes (secret_key, key_len)) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "Can't read /dev/urandom: %s", strerror (-r)); + "Can't get random data to generate secret key"); key_len = 0; goto out; } @@ -3373,8 +3256,7 @@ nm_utils_stable_id_random (void) { char buf[15]; - if (nm_utils_read_urandom (buf, sizeof (buf)) < 0) - g_return_val_if_reached (nm_utils_uuid_generate ()); + nm_utils_random_bytes (buf, sizeof (buf)); return g_base64_encode ((guchar *) buf, sizeof (buf)); } @@ -3437,7 +3319,7 @@ nm_utils_stable_id_parse (const char *stable_id, g_return_val_if_fail (out_generated, NM_UTILS_STABLE_TYPE_RANDOM); if (!stable_id) { - out_generated = NULL; + *out_generated = NULL; return NM_UTILS_STABLE_TYPE_UUID; } @@ -3505,7 +3387,7 @@ nm_utils_stable_id_parse (const char *stable_id, _stable_id_append (str, bootid ?: nm_utils_get_boot_id ()); else if (g_str_has_prefix (&stable_id[i], "${RANDOM}")) { /* RANDOM makes not so much sense for cloned-mac-address - * as the result is simmilar to specifing "cloned-mac-address=random". + * as the result is simmilar to specyifing "cloned-mac-address=random". * It makes however sense for RFC 7217 Stable Privacy IPv6 addresses * where this is effectively the only way to generate a different * (random) host identifier for each connect. @@ -3758,8 +3640,7 @@ nm_utils_hw_addr_gen_random_eth (const char *current_mac_address, { struct ether_addr bin_addr; - if (nm_utils_read_urandom (&bin_addr, ETH_ALEN) < 0) - return NULL; + nm_utils_random_bytes (&bin_addr, ETH_ALEN); _hw_addr_eth_complete (&bin_addr, current_mac_address, generate_mac_address_mask); return nm_utils_hwaddr_ntoa (&bin_addr, ETH_ALEN); } @@ -4451,6 +4332,13 @@ nm_utils_format_con_diff_for_audit (GHashTable *diff) /*****************************************************************************/ +NM_UTILS_ENUM2STR_DEFINE (nm_icmpv6_router_pref_to_string, NMIcmpv6RouterPref, + NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_LOW, "low"), + NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), + NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_HIGH, "high"), + NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_INVALID, "invalid"), +); + NM_UTILS_LOOKUP_STR_DEFINE (nm_activation_type_to_string, NMActivationType, NM_UTILS_LOOKUP_DEFAULT_WARN ("(unknown)"), NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVATION_TYPE_MANAGED, "managed"), |