mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-30 12:23:06 +02:00
tests: Exercise g_fdwalk_set_cloexec() and g_closefrom()
Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
parent
a7d5a6b69a
commit
f4afed90e6
@ -36,6 +36,187 @@
|
||||
|
||||
#include "testutils.h"
|
||||
|
||||
static void
|
||||
async_signal_safe_message (const char *message)
|
||||
{
|
||||
if (write (2, message, strlen (message)) < 0 ||
|
||||
write (2, "\n", 1) < 0)
|
||||
{
|
||||
/* ignore: not much we can do */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_closefrom (void)
|
||||
{
|
||||
/* Enough file descriptors to be confident that we're operating on
|
||||
* all of them */
|
||||
const int N_FDS = 20;
|
||||
int *fds;
|
||||
int fd;
|
||||
int i;
|
||||
pid_t child;
|
||||
int wait_status;
|
||||
|
||||
/* The loop that populates @fds with pipes assumes this */
|
||||
g_assert (N_FDS % 2 == 0);
|
||||
|
||||
g_test_summary ("Test g_closefrom(), g_fdwalk_set_cloexec()");
|
||||
g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3247");
|
||||
|
||||
for (fd = 0; fd <= 2; fd++)
|
||||
{
|
||||
int flags;
|
||||
|
||||
g_assert_no_errno ((flags = fcntl (fd, F_GETFD)));
|
||||
g_assert_no_errno (fcntl (fd, F_SETFD, flags & ~FD_CLOEXEC));
|
||||
}
|
||||
|
||||
fds = g_new0 (int, N_FDS);
|
||||
|
||||
for (i = 0; i < N_FDS; i += 2)
|
||||
{
|
||||
GError *error = NULL;
|
||||
int pipefd[2];
|
||||
int res;
|
||||
|
||||
/* Intentionally neither O_CLOEXEC nor FD_CLOEXEC */
|
||||
res = g_unix_open_pipe (pipefd, 0, &error);
|
||||
g_assert (res);
|
||||
g_assert_no_error (error);
|
||||
g_clear_error (&error);
|
||||
fds[i] = pipefd[0];
|
||||
fds[i + 1] = pipefd[1];
|
||||
}
|
||||
|
||||
child = fork ();
|
||||
|
||||
/* Child process exits with status = 100 + the first wrong fd,
|
||||
* or 0 if all were correct */
|
||||
if (child == 0)
|
||||
{
|
||||
for (i = 0; i < N_FDS; i++)
|
||||
{
|
||||
int flags = fcntl (fds[i], F_GETFD);
|
||||
|
||||
if (flags == -1)
|
||||
{
|
||||
async_signal_safe_message ("fd should not have been closed");
|
||||
_exit (100 + fds[i]);
|
||||
}
|
||||
|
||||
if (flags & FD_CLOEXEC)
|
||||
{
|
||||
async_signal_safe_message ("fd should not have been close-on-exec yet");
|
||||
_exit (100 + fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
g_fdwalk_set_cloexec (3);
|
||||
|
||||
for (i = 0; i < N_FDS; i++)
|
||||
{
|
||||
int flags = fcntl (fds[i], F_GETFD);
|
||||
|
||||
if (flags == -1)
|
||||
{
|
||||
async_signal_safe_message ("fd should not have been closed");
|
||||
_exit (100 + fds[i]);
|
||||
}
|
||||
|
||||
if (!(flags & FD_CLOEXEC))
|
||||
{
|
||||
async_signal_safe_message ("fd should have been close-on-exec");
|
||||
_exit (100 + fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
g_closefrom (3);
|
||||
|
||||
for (fd = 0; fd <= 2; fd++)
|
||||
{
|
||||
int flags = fcntl (fd, F_GETFD);
|
||||
|
||||
if (flags == -1)
|
||||
{
|
||||
async_signal_safe_message ("fd should not have been closed");
|
||||
_exit (100 + fd);
|
||||
}
|
||||
|
||||
if (flags & FD_CLOEXEC)
|
||||
{
|
||||
async_signal_safe_message ("fd should not have been close-on-exec");
|
||||
_exit (100 + fd);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < N_FDS; i++)
|
||||
{
|
||||
if (fcntl (fds[i], F_GETFD) != -1 || errno != EBADF)
|
||||
{
|
||||
async_signal_safe_message ("fd should have been closed");
|
||||
_exit (100 + fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
g_assert_no_errno (waitpid (child, &wait_status, 0));
|
||||
|
||||
if (WIFEXITED (wait_status))
|
||||
{
|
||||
int exit_status = WEXITSTATUS (wait_status);
|
||||
|
||||
if (exit_status != 0)
|
||||
g_test_fail_printf ("File descriptor %d in incorrect state", exit_status - 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_test_fail_printf ("Unexpected wait status %d", wait_status);
|
||||
}
|
||||
|
||||
for (i = 0; i < N_FDS; i++)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_close (fds[i], &error);
|
||||
g_assert_no_error (error);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_free (fds);
|
||||
|
||||
if (g_test_undefined ())
|
||||
{
|
||||
g_test_trap_subprocess ("/glib-unix/closefrom/subprocess/einval",
|
||||
0, G_TEST_SUBPROCESS_DEFAULT);
|
||||
g_test_trap_assert_passed ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_closefrom_subprocess_einval (void)
|
||||
{
|
||||
int res;
|
||||
int errsv;
|
||||
|
||||
g_log_set_always_fatal (G_LOG_FATAL_MASK);
|
||||
g_log_set_fatal_mask ("GLib", G_LOG_FATAL_MASK);
|
||||
|
||||
errno = 0;
|
||||
res = g_closefrom (-1);
|
||||
errsv = errno;
|
||||
g_assert_cmpint (res, ==, -1);
|
||||
g_assert_cmpint (errsv, ==, EINVAL);
|
||||
|
||||
errno = 0;
|
||||
res = g_fdwalk_set_cloexec (-42);
|
||||
errsv = errno;
|
||||
g_assert_cmpint (res, ==, -1);
|
||||
g_assert_cmpint (errsv, ==, EINVAL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_pipe (void)
|
||||
{
|
||||
@ -613,6 +794,9 @@ main (int argc,
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/glib-unix/closefrom", test_closefrom);
|
||||
g_test_add_func ("/glib-unix/closefrom/subprocess/einval",
|
||||
test_closefrom_subprocess_einval);
|
||||
g_test_add_func ("/glib-unix/pipe", test_pipe);
|
||||
g_test_add_func ("/glib-unix/pipe/fd-cloexec", test_pipe_fd_cloexec);
|
||||
g_test_add_func ("/glib-unix/pipe-stdio-overwrite", test_pipe_stdio_overwrite);
|
||||
|
Loading…
x
Reference in New Issue
Block a user