gspawn: Use GUnixPipe on Unix

Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie 2023-05-31 12:00:58 +01:00 committed by Philip Withnall
parent 9e20a7d0e7
commit e80b0c4e4b

View File

@ -2268,6 +2268,16 @@ out_free_spawnattr:
}
#endif /* POSIX_SPAWN_AVAILABLE */
static gboolean
source_fds_collide_with_pipe (const GUnixPipe *pipefd,
const int *source_fds,
gsize n_fds,
GError **error)
{
return (_g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_READ], source_fds, n_fds, error) ||
_g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_WRITE], source_fds, n_fds, error));
}
static gboolean
fork_exec (gboolean intermediate_child,
const gchar *working_directory,
@ -2296,8 +2306,8 @@ fork_exec (gboolean intermediate_child,
GError **error)
{
GPid pid = -1;
gint child_err_report_pipe[2] = { -1, -1 };
gint child_pid_report_pipe[2] = { -1, -1 };
GUnixPipe child_err_report_pipe = G_UNIX_PIPE_INIT;
GUnixPipe child_pid_report_pipe = G_UNIX_PIPE_INIT;
guint pipe_flags = cloexec_pipes ? FD_CLOEXEC : 0;
gint status;
const gchar *chosen_search_path;
@ -2307,9 +2317,9 @@ fork_exec (gboolean intermediate_child,
gchar **argv_buffer = NULL;
gchar **argv_buffer_heap = NULL;
gsize argv_buffer_len = 0;
gint stdin_pipe[2] = { -1, -1 };
gint stdout_pipe[2] = { -1, -1 };
gint stderr_pipe[2] = { -1, -1 };
GUnixPipe stdin_pipe = G_UNIX_PIPE_INIT;
GUnixPipe stdout_pipe = G_UNIX_PIPE_INIT;
GUnixPipe stderr_pipe = G_UNIX_PIPE_INIT;
gint child_close_fds[4] = { -1, -1, -1, -1 };
gint n_child_close_fds = 0;
gint *source_fds_copy = NULL;
@ -2322,35 +2332,32 @@ fork_exec (gboolean intermediate_child,
/* If pipes have been requested, open them */
if (stdin_pipe_out != NULL)
{
if (!g_unix_open_pipe (stdin_pipe, pipe_flags, error))
if (!g_unix_pipe_open (&stdin_pipe, pipe_flags, error))
goto cleanup_and_fail;
if (_g_spawn_invalid_source_fd (stdin_pipe[0], source_fds, n_fds, error) ||
_g_spawn_invalid_source_fd (stdin_pipe[1], source_fds, n_fds, error))
if (source_fds_collide_with_pipe (&stdin_pipe, source_fds, n_fds, error))
goto cleanup_and_fail;
child_close_fds[n_child_close_fds++] = stdin_pipe[1];
stdin_fd = stdin_pipe[0];
child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_WRITE);
stdin_fd = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_READ);
}
if (stdout_pipe_out != NULL)
{
if (!g_unix_open_pipe (stdout_pipe, pipe_flags, error))
if (!g_unix_pipe_open (&stdout_pipe, pipe_flags, error))
goto cleanup_and_fail;
if (_g_spawn_invalid_source_fd (stdout_pipe[0], source_fds, n_fds, error) ||
_g_spawn_invalid_source_fd (stdout_pipe[1], source_fds, n_fds, error))
if (source_fds_collide_with_pipe (&stdout_pipe, source_fds, n_fds, error))
goto cleanup_and_fail;
child_close_fds[n_child_close_fds++] = stdout_pipe[0];
stdout_fd = stdout_pipe[1];
child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_READ);
stdout_fd = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_WRITE);
}
if (stderr_pipe_out != NULL)
{
if (!g_unix_open_pipe (stderr_pipe, pipe_flags, error))
if (!g_unix_pipe_open (&stderr_pipe, pipe_flags, error))
goto cleanup_and_fail;
if (_g_spawn_invalid_source_fd (stderr_pipe[0], source_fds, n_fds, error) ||
_g_spawn_invalid_source_fd (stderr_pipe[1], source_fds, n_fds, error))
if (source_fds_collide_with_pipe (&stderr_pipe, source_fds, n_fds, error))
goto cleanup_and_fail;
child_close_fds[n_child_close_fds++] = stderr_pipe[0];
stderr_fd = stderr_pipe[1];
child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_READ);
stderr_fd = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_WRITE);
}
child_close_fds[n_child_close_fds++] = -1;
@ -2488,18 +2495,16 @@ fork_exec (gboolean intermediate_child,
if (n_fds > 0)
memcpy (source_fds_copy, source_fds, sizeof (*source_fds) * n_fds);
if (!g_unix_open_pipe (child_err_report_pipe, pipe_flags, error))
if (!g_unix_pipe_open (&child_err_report_pipe, pipe_flags, error))
goto cleanup_and_fail;
if (_g_spawn_invalid_source_fd (child_err_report_pipe[0], source_fds, n_fds, error) ||
_g_spawn_invalid_source_fd (child_err_report_pipe[1], source_fds, n_fds, error))
if (source_fds_collide_with_pipe (&child_err_report_pipe, source_fds, n_fds, error))
goto cleanup_and_fail;
if (intermediate_child)
{
if (!g_unix_open_pipe (child_pid_report_pipe, pipe_flags, error))
if (!g_unix_pipe_open (&child_pid_report_pipe, pipe_flags, error))
goto cleanup_and_fail;
if (_g_spawn_invalid_source_fd (child_pid_report_pipe[0], source_fds, n_fds, error) ||
_g_spawn_invalid_source_fd (child_pid_report_pipe[1], source_fds, n_fds, error))
if (source_fds_collide_with_pipe (&child_pid_report_pipe, source_fds, n_fds, error))
goto cleanup_and_fail;
}
@ -2538,8 +2543,8 @@ fork_exec (gboolean intermediate_child,
* not needed in the close_descriptors case,
* though
*/
g_clear_fd (&child_err_report_pipe[0], NULL);
g_clear_fd (&child_pid_report_pipe[0], NULL);
g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL);
g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL);
if (child_close_fds[0] != -1)
{
int i = -1;
@ -2561,16 +2566,16 @@ fork_exec (gboolean intermediate_child,
if (grandchild_pid < 0)
{
/* report -1 as child PID */
write_all (child_pid_report_pipe[1], &grandchild_pid,
sizeof(grandchild_pid));
write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE),
&grandchild_pid, sizeof(grandchild_pid));
write_err_and_exit (child_err_report_pipe[1],
write_err_and_exit (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
CHILD_FORK_FAILED);
}
else if (grandchild_pid == 0)
{
g_clear_fd (&child_pid_report_pipe[1], NULL);
do_exec (child_err_report_pipe[1],
g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
stdin_fd,
stdout_fd,
stderr_fd,
@ -2595,8 +2600,9 @@ fork_exec (gboolean intermediate_child,
}
else
{
write_all (child_pid_report_pipe[1], &grandchild_pid, sizeof(grandchild_pid));
g_clear_fd (&child_pid_report_pipe[1], NULL);
write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE),
&grandchild_pid, sizeof(grandchild_pid));
g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
_exit (0);
}
@ -2606,7 +2612,7 @@ fork_exec (gboolean intermediate_child,
/* Just run the child.
*/
do_exec (child_err_report_pipe[1],
do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE),
stdin_fd,
stdout_fd,
stderr_fd,
@ -2638,8 +2644,8 @@ fork_exec (gboolean intermediate_child,
gint n_ints = 0;
/* Close the uncared-about ends of the pipes */
g_clear_fd (&child_err_report_pipe[1], NULL);
g_clear_fd (&child_pid_report_pipe[1], NULL);
g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL);
/* If we had an intermediate child, reap it */
if (intermediate_child)
@ -2657,7 +2663,7 @@ fork_exec (gboolean intermediate_child,
}
if (!read_ints (child_err_report_pipe[0],
if (!read_ints (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_READ),
buf, 2, &n_ints,
error))
goto cleanup_and_fail;
@ -2738,7 +2744,7 @@ fork_exec (gboolean intermediate_child,
{
n_ints = 0;
if (!read_ints (child_pid_report_pipe[0],
if (!read_ints (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_READ),
buf, 1, &n_ints, error))
goto cleanup_and_fail;
@ -2761,8 +2767,8 @@ fork_exec (gboolean intermediate_child,
}
/* Success against all odds! return the information */
g_clear_fd (&child_err_report_pipe[0], NULL);
g_clear_fd (&child_pid_report_pipe[0], NULL);
g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL);
g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL);
g_free (search_path_buffer_heap);
g_free (argv_buffer_heap);
@ -2776,18 +2782,18 @@ fork_exec (gboolean intermediate_child,
success:
/* Close the uncared-about ends of the pipes */
g_clear_fd (&stdin_pipe[0], NULL);
g_clear_fd (&stdout_pipe[1], NULL);
g_clear_fd (&stderr_pipe[1], NULL);
g_unix_pipe_close (&stdin_pipe, G_UNIX_PIPE_END_READ, NULL);
g_unix_pipe_close (&stdout_pipe, G_UNIX_PIPE_END_WRITE, NULL);
g_unix_pipe_close (&stderr_pipe, G_UNIX_PIPE_END_WRITE, NULL);
if (stdin_pipe_out != NULL)
*stdin_pipe_out = g_steal_fd (&stdin_pipe[1]);
*stdin_pipe_out = g_unix_pipe_steal (&stdin_pipe, G_UNIX_PIPE_END_WRITE);
if (stdout_pipe_out != NULL)
*stdout_pipe_out = g_steal_fd (&stdout_pipe[0]);
*stdout_pipe_out = g_unix_pipe_steal (&stdout_pipe, G_UNIX_PIPE_END_READ);
if (stderr_pipe_out != NULL)
*stderr_pipe_out = g_steal_fd (&stderr_pipe[0]);
*stderr_pipe_out = g_unix_pipe_steal (&stderr_pipe, G_UNIX_PIPE_END_READ);
return TRUE;
@ -2811,17 +2817,11 @@ success:
}
}
g_clear_fd (&stdin_pipe[0], NULL);
g_clear_fd (&stdin_pipe[1], NULL);
g_clear_fd (&stdout_pipe[0], NULL);
g_clear_fd (&stdout_pipe[1], NULL);
g_clear_fd (&stderr_pipe[0], NULL);
g_clear_fd (&stderr_pipe[1], NULL);
g_clear_fd (&child_err_report_pipe[0], NULL);
g_clear_fd (&child_err_report_pipe[1], NULL);
g_clear_fd (&child_pid_report_pipe[0], NULL);
g_clear_fd (&child_pid_report_pipe[1], NULL);
g_unix_pipe_clear (&stdin_pipe);
g_unix_pipe_clear (&stdout_pipe);
g_unix_pipe_clear (&stderr_pipe);
g_unix_pipe_clear (&child_err_report_pipe);
g_unix_pipe_clear (&child_pid_report_pipe);
g_clear_pointer (&search_path_buffer_heap, g_free);
g_clear_pointer (&argv_buffer_heap, g_free);