about summary refs log tree commit diff
path: root/shared
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-06-29 22:15:58 +0200
committerMichael Biebl <biebl@debian.org>2020-06-29 22:15:58 +0200
commit10ae7d8cd706062742d0cdb1803d49909aef9e06 (patch)
treecb89e8b475cec18f22b1abfe45f1d63da7e3f440 /shared
parenta54ac63bbf9b2c71026ac9028a8ffaf186cf3c82 (diff)
New upstream version 1.25.91 upstream/1.25.91
Diffstat (limited to 'shared')
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c146
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h21
-rw-r--r--shared/nm-glib-aux/nm-str-buf.h61
-rw-r--r--shared/nm-version-macros.h2
-rw-r--r--shared/systemd/nm-sd-utils-shared.c40
-rw-r--r--shared/systemd/nm-sd-utils-shared.h4
6 files changed, 255 insertions, 19 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
index 39e98a31..e29520b2 100644
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
@@ -1069,6 +1069,47 @@ nm_utils_parse_inaddr_prefix (int addr_family,
 	return TRUE;
 }
 
+gboolean
+nm_utils_parse_next_line (const char **inout_ptr,
+                          gsize *inout_len,
+                          const char **out_line,
+                          gsize *out_line_len)
+{
+	const char *line_start;
+	const char *line_end;
+
+	g_return_val_if_fail (inout_ptr, FALSE);
+	g_return_val_if_fail (inout_len, FALSE);
+	g_return_val_if_fail (out_line, FALSE);
+
+	if (*inout_len <= 0)
+		goto error;
+
+	line_start = *inout_ptr;
+	line_end = memchr (line_start, '\n', *inout_len);
+	if (!line_end)
+		line_end = memchr (line_start, '\0', *inout_len);
+	if (!line_end) {
+		line_end = line_start + *inout_len;
+		NM_SET_OUT (inout_len, 0);
+	} else
+		NM_SET_OUT (inout_len, *inout_len - (line_end - line_start) - 1);
+
+	NM_SET_OUT (out_line, line_start);
+	NM_SET_OUT (out_line_len, (gsize) (line_end - line_start));
+
+	if (*inout_len > 0)
+		NM_SET_OUT (inout_ptr, line_end + 1);
+	else
+		NM_SET_OUT (inout_ptr, NULL);
+	return TRUE;
+
+error:
+	NM_SET_OUT (out_line, NULL);
+	NM_SET_OUT (out_line_len, 0);
+	return FALSE;
+}
+
 /*****************************************************************************/
 
 gboolean
@@ -2021,6 +2062,100 @@ nm_utils_escaped_tokens_options_split (char *str,
 /*****************************************************************************/
 
 /**
+ * nm_utils_strsplit_quoted:
+ * @str: the string to split (e.g. from /proc/cmdline).
+ *
+ * This basically does that systemd's extract_first_word() does
+ * with the flags "EXTRACT_UNQUOTE | EXTRACT_RELAX". This is what
+ * systemd uses to parse /proc/cmdline, and we do too.
+ *
+ * Splits the string. We have nm_utils_strsplit_set() which
+ * supports a variety of flags. However, extending that already
+ * complex code to also support quotation and escaping is hard.
+ * Instead, add a naive implementation.
+ *
+ * Returns: (transfer full): the split string.
+ */
+char **
+nm_utils_strsplit_quoted (const char *str)
+{
+	gs_unref_ptrarray GPtrArray *arr = NULL;
+	gs_free char *str_out = NULL;
+	guint8 ch_lookup[256];
+
+	nm_assert (str);
+
+	_char_lookup_table_init (ch_lookup, NM_ASCII_WHITESPACES);
+
+	for (;;) {
+		char quote;
+		gsize j;
+
+		while (_char_lookup_has (ch_lookup, str[0]))
+			str++;
+
+		if (str[0] == '\0')
+			break;
+
+		if (!str_out)
+			str_out = g_new (char, strlen (str) + 1);
+
+		quote = '\0';
+		j = 0;
+		for (;;) {
+			if (str[0] == '\\') {
+				str++;
+				if (str[0] == '\0')
+					break;
+				str_out[j++] = str[0];
+				str++;
+				continue;
+			}
+			if (quote) {
+				if (str[0] == '\0')
+					break;
+				if (str[0] == quote) {
+					quote = '\0';
+					str++;
+					continue;
+				}
+				str_out[j++] = str[0];
+				str++;
+				continue;
+			}
+			if (str[0] == '\0')
+				break;
+			if (NM_IN_SET (str[0], '\'', '"')) {
+				quote = str[0];
+				str++;
+				continue;
+			}
+			if (_char_lookup_has (ch_lookup, str[0])) {
+				str++;
+				break;
+			}
+			str_out[j++] = str[0];
+			str++;
+		}
+
+		if (!arr)
+			arr = g_ptr_array_new ();
+		g_ptr_array_add (arr, g_strndup (str_out, j));
+	}
+
+	if (!arr)
+		return g_new0 (char *, 1);
+
+	g_ptr_array_add (arr, NULL);
+
+	/* We want to return an optimally sized strv array, with no excess
+	 * memory allocated. Hence, clone once more. */
+	return nm_memdup (arr->pdata, sizeof (char *) * arr->len);
+}
+
+/*****************************************************************************/
+
+/**
  * nm_utils_strv_find_first:
  * @list: the strv list to search
  * @len: the length of the list, or a negative value if @list is %NULL terminated.
@@ -4841,6 +4976,8 @@ nm_str_buf_append_printf (NMStrBuf *strbuf,
 
 	available = strbuf->_priv_allocated - strbuf->_priv_len;
 
+	nm_assert (available < G_MAXULONG);
+
 	va_start (args, format);
 	l = g_vsnprintf (&strbuf->_priv_str[strbuf->_priv_len],
 	                 available,
@@ -4851,8 +4988,13 @@ nm_str_buf_append_printf (NMStrBuf *strbuf,
 	nm_assert (l >= 0);
 	nm_assert (l < G_MAXINT);
 
-	if ((gsize) l > available) {
-		gsize l2 = ((gsize) l) + 1u;
+	if ((gsize) l >= available) {
+		gsize l2;
+
+		if (l == 0)
+			return;
+
+		l2 = ((gsize) l) + 1u;
 
 		nm_str_buf_maybe_expand (strbuf, l2, FALSE);
 
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
index eeb8be5b..b17c8d1a 100644
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ b/shared/nm-glib-aux/nm-shared-utils.h
@@ -680,6 +680,10 @@ nm_utils_escaped_tokens_escape_gstr (const char *str,
 
 /*****************************************************************************/
 
+char **nm_utils_strsplit_quoted (const char *str);
+
+/*****************************************************************************/
+
 static inline const char **
 nm_utils_escaped_tokens_options_split_list (const char *str)
 {
@@ -803,6 +807,11 @@ gboolean nm_utils_parse_inaddr_prefix (int addr_family,
                                        char **out_addr,
                                        int *out_prefix);
 
+gboolean nm_utils_parse_next_line (const char **inout_ptr,
+                                   gsize *inout_len,
+                                   const char **out_line,
+                                   gsize *out_line_len);
+
 gint64 nm_g_ascii_strtoll (const char *nptr,
                            char **endptr,
                            guint base);
@@ -2024,6 +2033,18 @@ nm_strvarray_add (GArray *array, const char *str)
 }
 
 static inline const char *const*
+nm_strvarray_get_strv_non_empty (GArray *arr, guint *length)
+{
+	if (!arr || arr->len == 0) {
+		NM_SET_OUT (length, 0);
+		return NULL;
+	}
+
+	NM_SET_OUT (length, arr->len);
+	return &g_array_index (arr, const char *, 0);
+}
+
+static inline const char *const*
 nm_strvarray_get_strv (GArray **arr, guint *length)
 {
 	if (!*arr) {
diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h
index 8c73bfaf..da082abe 100644
--- a/shared/nm-glib-aux/nm-str-buf.h
+++ b/shared/nm-glib-aux/nm-str-buf.h
@@ -35,24 +35,30 @@ static inline void
 _nm_str_buf_assert (NMStrBuf *strbuf)
 {
 	nm_assert (strbuf);
-	nm_assert (strbuf->_priv_str);
-	nm_assert (strbuf->_priv_allocated > 0);
+	nm_assert ((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0));
 	nm_assert (strbuf->_priv_len <= strbuf->_priv_allocated);
 }
 
+static inline NMStrBuf
+NM_STR_BUF_INIT (gsize allocated, gboolean do_bzero_mem)
+{
+	NMStrBuf strbuf = {
+		._priv_str          = allocated ? g_malloc (allocated) : NULL,
+		._priv_allocated    = allocated,
+		._priv_len          = 0,
+		._priv_do_bzero_mem = do_bzero_mem,
+	};
+
+	return strbuf;
+}
+
 static inline void
 nm_str_buf_init (NMStrBuf *strbuf,
                  gsize len,
                  bool do_bzero_mem)
 {
 	nm_assert (strbuf);
-	nm_assert (len > 0);
-
-	strbuf->_priv_str          = g_malloc (len);
-	strbuf->_priv_allocated    = len;
-	strbuf->_priv_len          = 0;
-	strbuf->_priv_do_bzero_mem = do_bzero_mem;
-
+	*strbuf = NM_STR_BUF_INIT (len, do_bzero_mem);
 	_nm_str_buf_assert (strbuf);
 }
 
@@ -66,9 +72,6 @@ nm_str_buf_maybe_expand (NMStrBuf *strbuf,
                          gboolean reserve_exact)
 {
 	_nm_str_buf_assert (strbuf);
-
-	/* currently we always require to reserve a non-zero number of bytes. */
-	nm_assert (reserve > 0);
 	nm_assert (strbuf->_priv_len < G_MAXSIZE - reserve);
 
 	/* @reserve is the extra space that we require. */
@@ -164,6 +167,19 @@ nm_str_buf_erase (NMStrBuf *strbuf,
 /*****************************************************************************/
 
 static inline void
+nm_str_buf_append_c_repeated (NMStrBuf *strbuf,
+                              char ch,
+                              guint len)
+{
+	if (len > 0) {
+		nm_str_buf_maybe_expand (strbuf, len + 1, FALSE);
+		do {
+			strbuf->_priv_str[strbuf->_priv_len++] = ch;
+		} while (--len > 0);
+	}
+}
+
+static inline void
 nm_str_buf_append_c (NMStrBuf *strbuf,
                      char ch)
 {
@@ -263,10 +279,16 @@ nm_str_buf_is_initalized (NMStrBuf *strbuf)
  *   is of length "strbuf->len", which may be larger if the
  *   returned string contains NUL characters (binary). The terminating
  *   NUL character is always present after "strbuf->len" characters.
+ *   If currently no buffer is allocated, this will return %NULL.
  */
-static inline const char *
+static inline char *
 nm_str_buf_get_str (NMStrBuf *strbuf)
 {
+	_nm_str_buf_assert (strbuf);
+
+	if (!strbuf->_priv_str)
+		return NULL;
+
 	nm_str_buf_maybe_expand (strbuf, 1, FALSE);
 	strbuf->_priv_str[strbuf->_priv_len] = '\0';
 	return strbuf->_priv_str;
@@ -288,16 +310,23 @@ nm_str_buf_get_str_unsafe (NMStrBuf *strbuf)
  * Returns: (transfer full): the string of the buffer
  *   which must be freed by the caller. The @strbuf
  *   is afterwards in undefined state, though it can be
- *   reused after nm_str_buf_init(). */
+ *   reused after nm_str_buf_init().
+ *   Note that if no string is allocated yet (after nm_str_buf_init() with
+ *   length zero), this will return %NULL. */
 static inline char *
 nm_str_buf_finalize (NMStrBuf *strbuf,
                      gsize *out_len)
 {
-	nm_str_buf_maybe_expand (strbuf, 1, TRUE);
-	strbuf->_priv_str[strbuf->_priv_len] = '\0';
+	_nm_str_buf_assert (strbuf);
 
 	NM_SET_OUT (out_len, strbuf->_priv_len);
 
+	if (!strbuf->_priv_str)
+		return NULL;
+
+	nm_str_buf_maybe_expand (strbuf, 1, TRUE);
+	strbuf->_priv_str[strbuf->_priv_len] = '\0';
+
 	/* the buffer is in invalid state afterwards, however, we clear it
 	 * so far, that nm_auto_str_buf and nm_str_buf_destroy() is happy.  */
 	return g_steal_pointer (&strbuf->_priv_str);
diff --git a/shared/nm-version-macros.h b/shared/nm-version-macros.h
index 40bfaaa9..0906a62b 100644
--- a/shared/nm-version-macros.h
+++ b/shared/nm-version-macros.h
@@ -30,7 +30,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (90)
+#define NM_MICRO_VERSION (91)
 
 /**
  * NM_CHECK_VERSION:
diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c
index 4444e6c7..4fe82ca0 100644
--- a/shared/systemd/nm-sd-utils-shared.c
+++ b/shared/systemd/nm-sd-utils-shared.c
@@ -137,3 +137,43 @@ nm_sd_http_url_is_valid_https (const char *url)
 	nm_assert (_http_url_is_valid (url, FALSE) == http_url_is_valid (url));
 	return _http_url_is_valid (url, TRUE);
 }
+
+/*****************************************************************************/
+
+int
+nmtst_systemd_extract_first_word_all (const char *str, char ***out_strv)
+{
+	gs_unref_ptrarray GPtrArray *arr = NULL;
+
+	/* we implement a str split function to parse `/proc/cmdline`. This
+	 * code should behave like systemd, which uses extract_first_word()
+	 * for that.
+	 *
+	 * As we want to unit-test our implementation to match systemd,
+	 * expose this function for testing. */
+
+	g_assert (out_strv);
+	g_assert (!*out_strv);
+
+	if (!str)
+		return 0;
+
+	arr = g_ptr_array_new_with_free_func (g_free);
+
+	for (;;) {
+		gs_free char *word = NULL;
+		int r;
+
+		r = extract_first_word (&str, &word, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX);
+		if (r < 0)
+			return r;
+		if (r == 0)
+			break;
+		g_ptr_array_add (arr, g_steal_pointer (&word));
+	}
+
+	g_ptr_array_add (arr, NULL);
+
+	*out_strv = (char **) g_ptr_array_free (g_steal_pointer (&arr), FALSE);
+	return 1;
+}
diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h
index a3ca1edc..75e38b84 100644
--- a/shared/systemd/nm-sd-utils-shared.h
+++ b/shared/systemd/nm-sd-utils-shared.h
@@ -38,4 +38,8 @@ gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot);
 
 gboolean nm_sd_http_url_is_valid_https (const char *url);
 
+/*****************************************************************************/
+
+int nmtst_systemd_extract_first_word_all (const char *str, char ***out_strv);
+
 #endif /* __NM_SD_UTILS_SHARED_H__ */