mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-30 05:03:46 +08:00
222 lines
7.7 KiB
C
222 lines
7.7 KiB
C
/* Test the posix_spawn_file_actions_addchdir_np function.
|
|
Copyright (C) 2018-2024 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 <array_length.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <spawn.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <support/check.h>
|
|
#include <support/support.h>
|
|
#include <support/temp_file.h>
|
|
#include <support/test-driver.h>
|
|
#include <support/xstdio.h>
|
|
#include <support/xunistd.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <tst-spawn.h>
|
|
|
|
/* Reads the file at PATH, which must consist of exactly one line.
|
|
Removes the line terminator at the end of the file. */
|
|
static char *
|
|
read_one_line (const char *path)
|
|
{
|
|
FILE *fp = xfopen (path, "r");
|
|
char *buffer = NULL;
|
|
size_t length = 0;
|
|
ssize_t ret = getline (&buffer, &length, fp);
|
|
if (ferror (fp))
|
|
FAIL_EXIT1 ("getline: %m");
|
|
if (ret < 1)
|
|
FAIL_EXIT1 ("getline returned %zd", ret);
|
|
if (fgetc (fp) != EOF)
|
|
FAIL_EXIT1 ("trailing bytes in %s", path);
|
|
if (ferror (fp))
|
|
FAIL_EXIT1 ("fgetc: %m");
|
|
xfclose (fp);
|
|
if (buffer[ret - 1] != '\n')
|
|
FAIL_EXIT1 ("missing line terminator in %s", path);
|
|
buffer[ret - 1] = 0;
|
|
return buffer;
|
|
}
|
|
|
|
/* Return the path to the "pwd" program. */
|
|
const char *
|
|
get_pwd_program (void)
|
|
{
|
|
const char *const paths[] = { "/bin/pwd", "/usr/bin/pwd" };
|
|
for (size_t i = 0; i < array_length (paths); ++i)
|
|
if (access (paths[i], X_OK) == 0)
|
|
return paths[i];
|
|
FAIL_EXIT1 ("cannot find pwd program");
|
|
}
|
|
|
|
/* Adds chdir operations to ACTIONS, using PATH. If DO_FCHDIR, use
|
|
the open function and TMPFD to emulate chdir using fchdir. */
|
|
static void
|
|
add_chdir (posix_spawn_file_actions_t *actions, const char *path,
|
|
bool do_fchdir, int tmpfd)
|
|
{
|
|
if (do_fchdir)
|
|
{
|
|
TEST_COMPARE (posix_spawn_file_actions_addopen
|
|
(actions, tmpfd, path, O_DIRECTORY | O_RDONLY, 0), 0);
|
|
TEST_COMPARE (posix_spawn_file_actions_addfchdir_np
|
|
(actions, tmpfd), 0);
|
|
TEST_COMPARE (posix_spawn_file_actions_addclose (actions, tmpfd), 0);
|
|
}
|
|
else
|
|
TEST_COMPARE (posix_spawn_file_actions_addchdir_np (actions, path), 0);
|
|
}
|
|
|
|
static int
|
|
do_test (void)
|
|
{
|
|
/* Directory for temporary file data. Each subtest uses a numeric
|
|
subdirectory. */
|
|
char *directory = support_create_temp_directory ("tst-spawn-chdir-");
|
|
{
|
|
/* Avoid symbolic links, to get more consistent behavior from the
|
|
pwd command. */
|
|
char *tmp = realpath (directory, NULL);
|
|
if (tmp == NULL)
|
|
FAIL_EXIT1 ("realpath: %m");
|
|
free (directory);
|
|
directory = tmp;
|
|
}
|
|
|
|
char *original_cwd = get_current_dir_name ();
|
|
if (original_cwd == NULL)
|
|
FAIL_EXIT1 ("get_current_dir_name: %m");
|
|
|
|
int iteration = 0;
|
|
for (int do_spawnp = 0; do_spawnp < 2; ++do_spawnp)
|
|
for (int do_overwrite = 0; do_overwrite < 2; ++do_overwrite)
|
|
for (int do_fchdir = 0; do_fchdir < 2; ++do_fchdir)
|
|
{
|
|
/* This subtest does not make sense for fchdir. */
|
|
if (do_overwrite && do_fchdir)
|
|
continue;
|
|
|
|
++iteration;
|
|
if (test_verbose > 0)
|
|
printf ("info: iteration=%d do_spawnp=%d do_overwrite=%d"
|
|
" do_fchdir=%d\n",
|
|
iteration, do_spawnp, do_overwrite, do_fchdir);
|
|
|
|
/* The "pwd" program runs in this directory. */
|
|
char *iteration_directory = xasprintf ("%s/%d", directory, iteration);
|
|
add_temp_file (iteration_directory);
|
|
xmkdir (iteration_directory, 0777);
|
|
|
|
/* This file receives output from "pwd". */
|
|
char *output_file_path
|
|
= xasprintf ("%s/output-file", iteration_directory);
|
|
add_temp_file (output_file_path);
|
|
|
|
/* This subdirectory is used for chdir ordering checks. */
|
|
char *subdir_path = xasprintf ("%s/subdir", iteration_directory);
|
|
add_temp_file (subdir_path);
|
|
xmkdir (subdir_path, 0777);
|
|
|
|
/* Also used for checking the order of actions. */
|
|
char *probe_file_path
|
|
= xasprintf ("%s/subdir/probe-file", iteration_directory);
|
|
add_temp_file (probe_file_path);
|
|
TEST_COMPARE (access (probe_file_path, F_OK), -1);
|
|
TEST_COMPARE (errno, ENOENT);
|
|
|
|
/* This symbolic link is used in a relative path with
|
|
posix_spawn. */
|
|
char *pwd_symlink_path
|
|
= xasprintf ("%s/subdir/pwd-symlink", iteration_directory);
|
|
xsymlink (get_pwd_program (), pwd_symlink_path);
|
|
add_temp_file (pwd_symlink_path);
|
|
|
|
posix_spawn_file_actions_t actions;
|
|
TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0);
|
|
add_chdir (&actions, subdir_path, do_fchdir, 4);
|
|
TEST_COMPARE (posix_spawn_file_actions_addopen
|
|
(&actions, 3, /* Arbitrary unused descriptor. */
|
|
"probe-file",
|
|
O_WRONLY | O_CREAT | O_EXCL, 0777), 0);
|
|
TEST_COMPARE (posix_spawn_file_actions_addclose (&actions, 3), 0);
|
|
/* Run the actual in iteration_directory. */
|
|
add_chdir (&actions, "..", do_fchdir, 5);
|
|
TEST_COMPARE (posix_spawn_file_actions_addopen
|
|
(&actions, STDOUT_FILENO, "output-file",
|
|
O_WRONLY | O_CREAT | O_EXCL, 0777), 0);
|
|
|
|
/* Check that posix_spawn_file_actions_addchdir_np made a copy
|
|
of the path. */
|
|
if (do_overwrite)
|
|
subdir_path[0] = '\0';
|
|
|
|
char *const argv[] = { (char *) "pwd", NULL };
|
|
char *const envp[] = { NULL } ;
|
|
PID_T_TYPE pid;
|
|
if (do_spawnp)
|
|
TEST_COMPARE (POSIX_SPAWNP (&pid, "pwd", &actions,
|
|
NULL, argv, envp), 0);
|
|
else
|
|
TEST_COMPARE (POSIX_SPAWN (&pid, "subdir/pwd-symlink", &actions,
|
|
NULL, argv, envp), 0);
|
|
TEST_VERIFY (pid > 0);
|
|
siginfo_t sinfo;
|
|
TEST_COMPARE (WAITID (P_ALL, 0, &sinfo, WEXITED), 0);
|
|
TEST_COMPARE (sinfo.si_code, CLD_EXITED);
|
|
TEST_COMPARE (sinfo.si_status, 0);
|
|
|
|
/* Check that the current directory did not change. */
|
|
{
|
|
char *cwd = get_current_dir_name ();
|
|
if (cwd == NULL)
|
|
FAIL_EXIT1 ("get_current_dir_name: %m");
|
|
TEST_COMPARE_BLOB (original_cwd, strlen (original_cwd),
|
|
cwd, strlen (cwd));
|
|
free (cwd);
|
|
}
|
|
|
|
|
|
/* Check the output from "pwd". */
|
|
{
|
|
char *pwd = read_one_line (output_file_path);
|
|
TEST_COMPARE_BLOB (iteration_directory, strlen (iteration_directory),
|
|
pwd, strlen (pwd));
|
|
free (pwd);
|
|
}
|
|
|
|
/* This file must now exist. */
|
|
TEST_COMPARE (access (probe_file_path, F_OK), 0);
|
|
|
|
TEST_COMPARE (posix_spawn_file_actions_destroy (&actions), 0);
|
|
free (pwd_symlink_path);
|
|
free (probe_file_path);
|
|
free (subdir_path);
|
|
free (output_file_path);
|
|
}
|
|
|
|
free (directory);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#include <support/test-driver.c>
|