mirror of git://sourceware.org/git/glibc.git
236 lines
7.8 KiB
C
236 lines
7.8 KiB
C
/* Tests for support_spawn_wrap.
|
|
Copyright (C) 2026 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
#include <getopt.h>
|
|
#include <spawn.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <support/capture_subprocess.h>
|
|
#include <support/check.h>
|
|
#include <support/subprocess.h>
|
|
#include <support/support.h>
|
|
#include <support/xspawn.h>
|
|
#include <support/xunistd.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
/* Return true if running via an explicit ld.so invocation. */
|
|
static bool
|
|
running_via_ldso (void)
|
|
{
|
|
char *self = realpath ("/proc/self/exe", NULL);
|
|
if (self == NULL)
|
|
FAIL_UNSUPPORTED ("/proc/self/exe not available");
|
|
char *ldso = realpath (support_objdir_elf_ldso, NULL);
|
|
TEST_VERIFY_EXIT (ldso != NULL);
|
|
bool result = strcmp (self, ldso) == 0;
|
|
free (ldso);
|
|
free (self);
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
test_subprocess (int argc, char **argv)
|
|
{
|
|
{
|
|
char *argc_env = getenv ("argc");
|
|
if (argc_env != NULL)
|
|
{
|
|
char *argc_arg = xasprintf ("%d", argc);
|
|
TEST_COMPARE_STRING (argc_arg, argc_env);
|
|
free (argc_arg);
|
|
}
|
|
}
|
|
|
|
if (argc >= 2 && strcmp (argv[1], "alpha") == 0)
|
|
{
|
|
TEST_COMPARE (argc, 4);
|
|
TEST_COMPARE_STRING (argv[0], "program");
|
|
TEST_COMPARE_STRING (argv[2], "beta");
|
|
TEST_COMPARE_STRING (argv[3], "gamma");
|
|
TEST_COMPARE_STRING (argv[4], NULL);
|
|
}
|
|
else if (argc >= 2 && strcmp (argv[1], "check-env") == 0)
|
|
printf ("%d %s\n", argc, getenv ("extra"));
|
|
else if (argc >= 2 && strcmp (argv[1], "check-ld.so") == 0)
|
|
TEST_VERIFY (running_via_ldso ());
|
|
}
|
|
|
|
/* The "recurse" environment variable and the --recurse option
|
|
indicate recursive invocation. */
|
|
static int flag_recurse;
|
|
#define CMDLINE_OPTIONS \
|
|
{ "recurse", no_argument, &flag_recurse, 1 }, \
|
|
/* CMDLINE_OPTION */
|
|
|
|
static void
|
|
prepare (int argc, char **argv)
|
|
{
|
|
if (getenv ("recurse") != NULL || flag_recurse)
|
|
{
|
|
test_subprocess (argc, argv);
|
|
support_record_failure_barrier ();
|
|
exit (0);
|
|
}
|
|
}
|
|
|
|
#define PREPARE prepare
|
|
|
|
/* Test wrapping of a non-test program (iconv). This uses posix_spawn
|
|
directly, mainly for illustrative purposes. */
|
|
void
|
|
test_iconv (void)
|
|
{
|
|
char *iconv_prog = xasprintf ("%s/iconv/iconv_prog", support_objdir_root);
|
|
char *argv[] = { (char *) "iconv", (char *) "-f", (char *) "UTF-8",
|
|
(char *) "-t", (char *) "ISO-8859-1", NULL };
|
|
struct support_spawn_wrapped *w
|
|
= support_spawn_wrap (iconv_prog, argv, NULL, support_spawn_wrap_force);
|
|
|
|
/* Set up pipes for stdin, stdout, and stderr. */
|
|
int stdin_pipe[2];
|
|
xpipe (stdin_pipe);
|
|
int stdout_pipe[2];
|
|
xpipe (stdout_pipe);
|
|
int stderr_pipe[2];
|
|
xpipe (stderr_pipe);
|
|
|
|
posix_spawn_file_actions_t fa;
|
|
posix_spawn_file_actions_init (&fa);
|
|
xposix_spawn_file_actions_adddup2 (&fa, stdin_pipe[0], STDIN_FILENO);
|
|
xposix_spawn_file_actions_addclose (&fa, stdin_pipe[0]);
|
|
xposix_spawn_file_actions_addclose (&fa, stdin_pipe[1]);
|
|
xposix_spawn_file_actions_adddup2 (&fa, stdout_pipe[1], STDOUT_FILENO);
|
|
xposix_spawn_file_actions_addclose (&fa, stdout_pipe[0]);
|
|
xposix_spawn_file_actions_addclose (&fa, stdout_pipe[1]);
|
|
xposix_spawn_file_actions_adddup2 (&fa, stderr_pipe[1], STDERR_FILENO);
|
|
xposix_spawn_file_actions_addclose (&fa, stderr_pipe[0]);
|
|
xposix_spawn_file_actions_addclose (&fa, stderr_pipe[1]);
|
|
|
|
pid_t pid = xposix_spawn (w->path, &fa, NULL, w->argv, w->envp);
|
|
posix_spawn_file_actions_destroy (&fa);
|
|
|
|
xclose (stdin_pipe[0]);
|
|
xclose (stdout_pipe[1]);
|
|
xclose (stderr_pipe[1]);
|
|
|
|
/* Write UTF-8 encoding of "äöü\n" to stdin. */
|
|
xwrite (stdin_pipe[1], "\xc3\xa4\xc3\xb6\xc3\xbc\n", 7);
|
|
xclose (stdin_pipe[1]);
|
|
|
|
/* Read the converted output from the pipe. */
|
|
char buf[16];
|
|
ssize_t ret = read (stdout_pipe[0], buf, sizeof (buf));
|
|
xclose (stdout_pipe[0]);
|
|
|
|
/* ISO-8859-1 encoding of "äöü\n". */
|
|
TEST_COMPARE_BLOB (buf, ret, "\xe4\xf6\xfc\n", 4);
|
|
|
|
int status;
|
|
xwaitpid (pid, &status, 0);
|
|
TEST_COMPARE (status, 0);
|
|
|
|
/* Check that nothing has been written to stderr. */
|
|
ret = read (stderr_pipe[0], buf, sizeof (buf));
|
|
TEST_COMPARE (ret, 0);
|
|
xclose (stderr_pipe[0]);
|
|
|
|
support_spawn_wrapped_free (w);
|
|
free (iconv_prog);
|
|
}
|
|
|
|
static int
|
|
do_test (void)
|
|
{
|
|
char *program = xasprintf ("%s/support/tst-support_spawn_wrap",
|
|
support_objdir_root);
|
|
|
|
{
|
|
char *env[] = { (char *) "recurse=", (char *) "argc=1", NULL };
|
|
struct support_spawn_wrapped *w
|
|
= support_spawn_wrap (program, NULL, env, 0);
|
|
struct support_capture_subprocess proc
|
|
= support_capture_subprogram (w->path, w->argv, w->envp);
|
|
support_capture_subprocess_check (&proc, "no arguments", 0, sc_allow_none);
|
|
support_capture_subprocess_free (&proc);
|
|
support_spawn_wrapped_free (w);
|
|
}
|
|
|
|
{
|
|
char *argv[] = { (char *) "program", (char *) "--recurse", NULL };
|
|
struct support_spawn_wrapped *w
|
|
= support_spawn_wrap (program, argv, NULL, 0);
|
|
struct support_capture_subprocess proc
|
|
= support_capture_subprogram (w->path, w->argv, w->envp);
|
|
support_capture_subprocess_check (&proc, "default envvironment", 0,
|
|
sc_allow_none);
|
|
support_capture_subprocess_free (&proc);
|
|
support_spawn_wrapped_free (w);
|
|
}
|
|
|
|
{
|
|
char *argv[] = { (char *) "program", (char *) "alpha", (char *) "beta",
|
|
(char *) "gamma", NULL };
|
|
char *env[] = { (char *) "recurse=", (char *) "argc=4", NULL };
|
|
struct support_spawn_wrapped *w
|
|
= support_spawn_wrap (program, argv, env, 0);
|
|
struct support_capture_subprocess proc
|
|
= support_capture_subprogram (w->path, w->argv, w->envp);
|
|
support_capture_subprocess_check (&proc, "3 arguments", 0, sc_allow_none);
|
|
support_capture_subprocess_free (&proc);
|
|
support_spawn_wrapped_free (w);
|
|
}
|
|
|
|
{
|
|
char *argv[] = { (char *) "program", (char *) "check-env", NULL };
|
|
char *env[] = { (char *) "recurse=", (char *) "argc=2",
|
|
(char *) "extra=17", NULL };
|
|
struct support_spawn_wrapped *w
|
|
= support_spawn_wrap (program, argv, env, 0);
|
|
struct support_capture_subprocess proc
|
|
= support_capture_subprogram (w->path, w->argv, w->envp);
|
|
TEST_COMPARE_STRING (proc.out.buffer, "2 17\n");
|
|
support_capture_subprocess_check (&proc, "check-env", 0, sc_allow_stdout);
|
|
support_capture_subprocess_free (&proc);
|
|
support_spawn_wrapped_free (w);
|
|
}
|
|
|
|
test_iconv ();
|
|
|
|
/* This may trigger EXIT_UNSUPPORTED, so run this before the tests
|
|
that rely on running_via_ldso. */
|
|
TEST_COMPARE (!running_via_ldso (), support_hardcoded_paths_in_test);
|
|
|
|
{
|
|
char *argv[] = { (char *) "program", (char *) "check-ld.so", NULL };
|
|
char *env[] = { (char *) "recurse=", NULL };
|
|
struct support_spawn_wrapped *w
|
|
= support_spawn_wrap (program, argv, env, support_spawn_wrap_force);
|
|
struct support_capture_subprocess proc
|
|
= support_capture_subprogram (w->path, w->argv, w->envp);
|
|
support_capture_subprocess_check (&proc, "check-ld.so", 0, sc_allow_none);
|
|
support_capture_subprocess_free (&proc);
|
|
support_spawn_wrapped_free (w);
|
|
}
|
|
|
|
free (program);
|
|
return 0;
|
|
}
|
|
|
|
#include <support/test-driver.c>
|