core: support returning binary output from the daemon helper

The full output of the daemon helper is added to a NMStrBuf, without
interpreting it as a string (that is, without stopping at the first
NUL character).

However, when we retrieve the content from the NMStrBuf we assume it's
a string. This is fine for certain commands that expect a string
output, but it's not for other commands as the read-file-as-user one.

Add a new argument to nm_utils_spawn_helper() to specify whether the
output is binary or not. Also have different finish functions
depending on the return type.
This commit is contained in:
Beniamino Galvani 2025-09-16 16:57:19 +02:00 committed by Íñigo Huguet
parent bd2484d1a9
commit 4e26403c4a
3 changed files with 39 additions and 7 deletions

View file

@ -239,7 +239,7 @@ resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data
gs_free_error GError *error = NULL; gs_free_error GError *error = NULL;
gs_free char *output = NULL; gs_free char *output = NULL;
output = nm_utils_spawn_helper_finish(result, &error); output = nm_utils_spawn_helper_finish_string(result, &error);
if (nm_utils_error_is_cancelled(error)) if (nm_utils_error_is_cancelled(error))
return; return;
@ -278,6 +278,7 @@ resolve_addr_spawn_helper(ResolveAddrInfo *info, ResolveAddrService services)
nm_inet_ntop(info->addr_family, &info->address, addr_str); nm_inet_ntop(info->addr_family, &info->address, addr_str);
_LOG2D(info, "start lookup via nm-daemon-helper using services: %s", str); _LOG2D(info, "start lookup via nm-daemon-helper using services: %s", str);
nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str, str), nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str, str),
FALSE,
g_task_get_cancellable(info->task), g_task_get_cancellable(info->task),
resolve_addr_helper_cb, resolve_addr_helper_cb,
info); info);

View file

@ -5012,6 +5012,7 @@ typedef struct {
int child_stdin; int child_stdin;
int child_stdout; int child_stdout;
int child_stderr; int child_stderr;
gboolean binary_output;
GSource *input_source; GSource *input_source;
GSource *output_source; GSource *output_source;
GSource *error_source; GSource *error_source;
@ -5091,9 +5092,17 @@ helper_complete(HelperInfo *info, GError *error)
} }
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id); nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id);
if (info->binary_output) {
g_task_return_pointer(
info->task,
g_bytes_new(nm_str_buf_get_str_unsafe(&info->in_buffer), info->in_buffer.len),
(GDestroyNotify) (g_bytes_unref));
} else {
g_task_return_pointer(info->task, g_task_return_pointer(info->task,
nm_str_buf_finalize(&info->in_buffer, NULL) ?: g_new0(char, 1), nm_str_buf_finalize(&info->in_buffer, NULL) ?: g_new0(char, 1),
g_free); g_free);
}
helper_info_free(info); helper_info_free(info);
} }
@ -5236,6 +5245,7 @@ helper_cancelled(GObject *object, gpointer user_data)
void void
nm_utils_spawn_helper(const char *const *args, nm_utils_spawn_helper(const char *const *args,
gboolean binary_output,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer cb_data) gpointer cb_data)
@ -5252,8 +5262,13 @@ nm_utils_spawn_helper(const char *const *args,
info = g_new(HelperInfo, 1); info = g_new(HelperInfo, 1);
*info = (HelperInfo) { *info = (HelperInfo) {
.task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data), .task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data),
.binary_output = binary_output,
}; };
/* Store if the caller requested binary output so that we can check later
* that the right result function is called. */
g_task_set_task_data(info->task, GINT_TO_POINTER(binary_output), NULL);
if (!g_spawn_async_with_pipes("/", if (!g_spawn_async_with_pipes("/",
(char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"), (char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"),
(char **) NM_MAKE_STRV(), (char **) NM_MAKE_STRV(),
@ -5364,11 +5379,25 @@ nm_utils_spawn_helper(const char *const *args,
} }
char * char *
nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error) nm_utils_spawn_helper_finish_string(GAsyncResult *result, GError **error)
{ {
GTask *task = G_TASK(result); GTask *task = G_TASK(result);
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper)); nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper));
/* Check binary_output */
nm_assert(GPOINTER_TO_INT(g_task_get_task_data(task)) == FALSE);
return g_task_propagate_pointer(task, error);
}
GBytes *
nm_utils_spawn_helper_finish_binary(GAsyncResult *result, GError **error)
{
GTask *task = G_TASK(result);
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper));
/* Check binary_output */
nm_assert(GPOINTER_TO_INT(g_task_get_task_data(task)) == TRUE);
return g_task_propagate_pointer(task, error); return g_task_propagate_pointer(task, error);
} }

View file

@ -478,11 +478,13 @@ guint8 nm_wifi_utils_level_to_quality(int val);
/*****************************************************************************/ /*****************************************************************************/
void nm_utils_spawn_helper(const char *const *args, void nm_utils_spawn_helper(const char *const *args,
gboolean binary_output,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer cb_data); gpointer cb_data);
char *nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error); char *nm_utils_spawn_helper_finish_string(GAsyncResult *result, GError **error);
GBytes *nm_utils_spawn_helper_finish_binary(GAsyncResult *result, GError **error);
/*****************************************************************************/ /*****************************************************************************/