@@ -60,6 +60,13 @@ Major new features:
set the cgroupv2 in the new process in a race free manner. These functions
are GNU extensions and require a kernel with clone3 support.
+* On Linux, the pidfd_spawn and pidfd_spawp functions have been added.
+ They have similar prototype and semantic as posix_spawn, but instead of
+ returning a process ID, they return a file descriptor that can be used
+ along other pidfd function (like pidfd_send_signal, poll, or waitid).
+ The pidfd functionality avoid the issue of PID reuse with traditional
+ posix_spawn interface.
+
Deprecated and removed features, and other changes affecting compatibility:
* In the Linux kernel for the hppa/parisc architecture some of the
@@ -35,6 +35,10 @@ extern int __clone_internal_fallback (struct clone_args *__cl_args,
void *__arg)
attribute_hidden;
+/* Return whether the kernel supports pid file descriptor, including clone
+ with CLONE_PIDFD and waitid with P_PIDFD. */
+extern bool __clone_pidfd_supported (void) attribute_hidden;
+
#ifndef _ISOMAC
libc_hidden_proto (__clone3)
libc_hidden_proto (__clone_internal)
@@ -136,13 +136,13 @@ creating a process and making it run another program.
@cindex parent process
@cindex subprocess
A new processes is created when one of the functions
-@code{posix_spawn}, @code{fork}, @code{_Fork} or @code{vfork} is called.
-(The @code{system} and @code{popen} also create new processes internally.)
-Due to the name of the @code{fork} function, the act of creating a new
-process is sometimes called @dfn{forking} a process. Each new process
-(the @dfn{child process} or @dfn{subprocess}) is allocated a process
-ID, distinct from the process ID of the parent process. @xref{Process
-Identification}.
+@code{posix_spawn}, @code{fork}, @code{_Fork}, @code{vfork}, or
+@code{pidfd_spawn} is called. (The @code{system} and @code{popen} also
+create new processes internally.) Due to the name of the @code{fork}
+function, the act of creating a new process is sometimes called
+@dfn{forking} a process. Each new process (the @dfn{child process} or
+@dfn{subprocess}) is allocated a process ID, distinct from the process
+ID of the parent process. @xref{Process Identification}.
After forking a child process, both the parent and child processes
continue to execute normally. If you want your program to wait for a
@@ -602,6 +602,7 @@ tst-spawn-static-ARGS = $(tst-spawn-ARGS)
tst-spawn5-ARGS = -- $(host-test-program-cmd)
tst-spawn6-ARGS = -- $(host-test-program-cmd)
tst-spawn7-ARGS = -- $(host-test-program-cmd)
+tst-posix_spawn-setsid-ARGS = -- $(host-test-program-cmd)
tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir
tst-chmod-ARGS = $(objdir)
tst-vfork3-ARGS = --test-dir=$(objpfx)
@@ -76,12 +76,13 @@ struct __spawn_action
#define SPAWN_XFLAGS_USE_PATH 0x1
#define SPAWN_XFLAGS_TRY_SHELL 0x2
+#define SPAWN_XFLAGS_RET_PIDFD 0x4
extern int __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *
file_actions)
attribute_hidden;
-extern int __spawni (pid_t *pid, const char *path,
+extern int __spawni (int *pid, const char *path,
const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *attrp, char *const argv[],
char *const envp[], int xflags) attribute_hidden;
@@ -18,78 +18,158 @@
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
+#include <intprops.h>
+#include <paths.h>
#include <spawn.h>
#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/resource.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/temp_file.h>
+#include <tst-spawn.h>
+
+/* Nonzero if the program gets called via `exec'. */
+static int restart;
+
+/* Hold the four initial argument used to respawn the process, plus
+ the extra '--direct' and '--restart', and a final NULL. */
+static char *initial_argv[7];
+static int initial_argv_count;
+
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+
+static char *pidfile;
+
+static pid_t
+read_child_sid (void)
+{
+ int pidfd = xopen (pidfile, O_RDONLY, 0);
+
+ char buf[INT_STRLEN_BOUND (pid_t)];
+ ssize_t n = read (pidfd, buf, sizeof (buf));
+ TEST_VERIFY (n < sizeof buf && n >= 0);
+ buf[n] = '\0';
+
+ /* We only expect to read the PID. */
+ char *endp;
+ long int rpid = strtol (buf, &endp, 10);
+ TEST_VERIFY (endp != buf);
+
+ xclose (pidfd);
+
+ return rpid;
+}
+
+/* Called on process re-execution, write down the session id on PIDFILE. */
+_Noreturn static void
+handle_restart (const char *pidfile)
+{
+ int pidfd = xopen (pidfile, O_WRONLY, 0);
+
+ char buf[INT_STRLEN_BOUND (pid_t)];
+ int s = snprintf (buf, sizeof buf, "%d", getsid (0));
+ size_t n = write (pidfd, buf, s);
+ TEST_VERIFY (n == s);
+
+ xclose (pidfd);
+
+ exit (EXIT_SUCCESS);
+}
static void
do_test_setsid (bool test_setsid)
{
- pid_t sid, child_sid;
- int res;
-
/* Current session ID. */
- sid = getsid(0);
- if (sid == (pid_t) -1)
- FAIL_EXIT1 ("getsid (0): %m");
+ pid_t sid = getsid (0);
+ TEST_VERIFY (sid != (pid_t) -1);
posix_spawnattr_t attrp;
- /* posix_spawnattr_init should not fail (it basically memset the
- attribute). */
- posix_spawnattr_init (&attrp);
+ TEST_COMPARE (posix_spawnattr_init (&attrp), 0);
if (test_setsid)
- {
- res = posix_spawnattr_setflags (&attrp, POSIX_SPAWN_SETSID);
- if (res != 0)
- {
- errno = res;
- FAIL_EXIT1 ("posix_spawnattr_setflags: %m");
- }
- }
-
- /* Program to run. */
- char *args[2] = { (char *) "true", NULL };
- pid_t child;
-
- res = posix_spawnp (&child, "true", NULL, &attrp, args, environ);
- /* posix_spawnattr_destroy is noop. */
- posix_spawnattr_destroy (&attrp);
-
- if (res != 0)
- {
- errno = res;
- FAIL_EXIT1 ("posix_spawnp: %m");
- }
+ TEST_COMPARE (posix_spawnattr_setflags (&attrp, POSIX_SPAWN_SETSID), 0);
+
+ /* 1 or 4 elements from initial_argv:
+ + path to ld.so optional
+ + --library-path optional
+ + the library path optional
+ + application name
+ + --direct
+ + --restart
+ + pidfile */
+ int argv_size = initial_argv_count + 2;
+ char *args[argv_size];
+ int argc = 0;
+
+ for (char **arg = initial_argv; *arg != NULL; arg++)
+ args[argc++] = *arg;
+ args[argc++] = pidfile;
+ args[argc] = NULL;
+ TEST_VERIFY (argc < argv_size);
+
+ PID_T_TYPE pid;
+ TEST_COMPARE (POSIX_SPAWN (&pid, args[0], NULL, &attrp, args, environ), 0);
+ TEST_COMPARE (posix_spawnattr_destroy (&attrp), 0);
+
+ siginfo_t sinfo;
+ TEST_COMPARE (WAITID (P_PID, pid, &sinfo, WEXITED), 0);
+ TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+ TEST_COMPARE (sinfo.si_status, 0);
+
+ pid_t child_sid = read_child_sid ();
/* Child should have a different session ID than parent. */
- child_sid = getsid (child);
-
- if (child_sid == (pid_t) -1)
- FAIL_EXIT1 ("getsid (%i): %m", child);
+ TEST_VERIFY (child_sid != (pid_t) -1);
if (test_setsid)
- {
- if (child_sid == sid)
- FAIL_EXIT1 ("child session ID matched parent one");
- }
+ TEST_VERIFY (child_sid != sid);
else
- {
- if (child_sid != sid)
- FAIL_EXIT1 ("child session ID did not match parent one");
- }
+ TEST_VERIFY (child_sid == sid);
}
static int
-do_test (void)
+do_test (int argc, char *argv[])
{
+ /* We must have either:
+
+ - one or four parameters if called initially:
+ + argv[1]: path for ld.so optional
+ + argv[2]: "--library-path" optional
+ + argv[3]: the library path optional
+ + argv[4]: the application name
+
+ - six parameters left if called through re-execution:
+ + argv[5/1]: the application name
+ + argv[6/2]: the pidfile
+
+ * When built with --enable-hardcoded-path-in-tests or issued without
+ using the loader directly. */
+
+ if (restart)
+ handle_restart (argv[1]);
+
+ TEST_VERIFY_EXIT (argc == 2 || argc == 5);
+
+ int i;
+ for (i = 0; i < argc - 1; i++)
+ initial_argv[i] = argv[i + 1];
+ initial_argv[i++] = (char *) "--direct";
+ initial_argv[i++] = (char *) "--restart";
+ initial_argv_count = i;
+
+ create_temp_file ("tst-posix_spawn-setsid-", &pidfile);
+
do_test_setsid (false);
do_test_setsid (true);
return 0;
}
+#define TEST_FUNCTION_ARGV do_test
#include <support/test-driver.c>
@@ -29,7 +29,9 @@
#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. */
@@ -169,17 +171,18 @@ do_test (void)
char *const argv[] = { (char *) "pwd", NULL };
char *const envp[] = { NULL } ;
- pid_t pid;
+ PID_T_TYPE pid;
if (do_spawnp)
- TEST_COMPARE (posix_spawnp (&pid, "pwd", &actions,
+ TEST_COMPARE (POSIX_SPAWNP (&pid, "pwd", &actions,
NULL, argv, envp), 0);
else
- TEST_COMPARE (posix_spawn (&pid, "subdir/pwd-symlink", &actions,
+ TEST_COMPARE (POSIX_SPAWN (&pid, "subdir/pwd-symlink", &actions,
NULL, argv, envp), 0);
TEST_VERIFY (pid > 0);
- int status;
- xwaitpid (pid, &status, 0);
- TEST_COMPARE (status, 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. */
{
@@ -25,11 +25,13 @@
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
+#include <sys/wait.h>
#include <support/check.h>
#include <support/xunistd.h>
#include <support/temp_file.h>
#include <support/support.h>
+#include <tst-spawn.h>
/* Nonzero if the program gets called via `exec'. */
@@ -143,9 +145,9 @@ handle_restart (const char *fd1s, const char *fd2s, const char *fd3s,
static int
do_test (int argc, char *argv[])
{
- pid_t pid;
+ PID_T_TYPE pid;
int fd4;
- int status;
+ siginfo_t sinfo;
posix_spawn_file_actions_t actions;
char fd1name[18];
char fd2name[18];
@@ -233,17 +235,16 @@ do_test (int argc, char *argv[])
spargv[i++] = fd5name;
spargv[i] = NULL;
- TEST_COMPARE (posix_spawn (&pid, argv[1], &actions, NULL, spargv, environ),
+ TEST_COMPARE (POSIX_SPAWN (&pid, argv[1], &actions, NULL, spargv, environ),
0);
/* Wait for the children. */
- TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
- TEST_VERIFY (WIFEXITED (status));
- TEST_VERIFY (!WIFSIGNALED (status));
- TEST_COMPARE (WEXITSTATUS (status), 0);
+ TEST_COMPARE (WAITID (P_PID, pid, &sinfo, WEXITED), 0);
+ TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+ TEST_COMPARE (sinfo.si_status, 0);
/* Same test but with a NULL pid argument. */
- TEST_COMPARE (posix_spawn (NULL, argv[1], &actions, NULL, spargv, environ),
+ TEST_COMPARE (POSIX_SPAWN (NULL, argv[1], &actions, NULL, spargv, environ),
0);
/* Cleanup. */
@@ -251,10 +252,9 @@ do_test (int argc, char *argv[])
free (name3_copy);
/* Wait for the children. */
- xwaitpid (-1, &status, 0);
- TEST_VERIFY (WIFEXITED (status));
- TEST_VERIFY (!WIFSIGNALED (status));
- TEST_COMPARE (WEXITSTATUS (status), 0);
+ TEST_COMPARE (WAITID (P_ALL, 0, &sinfo, WEXITED), 0);
+ TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+ TEST_COMPARE (sinfo.si_status, 0);
return 0;
}
new file mode 100644
@@ -0,0 +1,36 @@
+/* Generic definitions for posix_spawn tests.
+ Copyright (C) 2023 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/>. */
+
+#ifndef PID_T_TYPE
+# define PID_T_TYPE pid_t
+#endif
+
+#ifndef POSIX_SPAWN
+# define POSIX_SPAWN(__child, __path, __actions, __attr, __argv, __envp) \
+ posix_spawn (__child, __path, __actions, __attr, __argv, __envp)
+#endif
+
+#ifndef POSIX_SPAWNP
+# define POSIX_SPAWNP(__child, __path, __actions, __attr, __argv, __envp) \
+ posix_spawnp (__child, __path, __actions, __attr, __argv, __envp)
+#endif
+
+#ifndef WAITID
+# define WAITID(__idtype, __id, __info, __opts) \
+ waitid (__idtype, __id, __info, __opts)
+#endif
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <support/check.h>
+#include <tst-spawn.h>
int
do_test (void)
@@ -35,9 +36,9 @@ do_test (void)
const char *program = "/path/to/invalid/binary";
char * const args[] = { 0 };
- pid_t pid = -1;
+ PID_T_TYPE pid = -1;
- int ret = posix_spawn (&pid, program, 0, 0, args, environ);
+ int ret = POSIX_SPAWN (&pid, program, 0, 0, args, environ);
if (ret != ENOENT)
{
errno = ret;
@@ -51,14 +52,13 @@ do_test (void)
FAIL_EXIT1 ("posix_spawn returned pid != -1 (%i)", (int) pid);
/* Check if no child is actually created. */
- ret = waitpid (-1, NULL, 0);
- if (ret != -1 || errno != ECHILD)
- FAIL_EXIT1 ("waitpid: %m)");
+ TEST_COMPARE (WAITID (P_ALL, 0, NULL, WEXITED), -1);
+ TEST_COMPARE (errno, ECHILD);
/* Same as before, but with posix_spawnp. */
char *args2[] = { (char*) program, 0 };
- ret = posix_spawnp (&pid, args2[0], 0, 0, args2, environ);
+ ret = POSIX_SPAWNP (&pid, args2[0], 0, 0, args2, environ);
if (ret != ENOENT)
{
errno = ret;
@@ -68,9 +68,8 @@ do_test (void)
if (pid != -1)
FAIL_EXIT1 ("posix_spawnp returned pid != -1 (%i)", (int) pid);
- ret = waitpid (-1, NULL, 0);
- if (ret != -1 || errno != ECHILD)
- FAIL_EXIT1 ("waitpid: %m)");
+ TEST_COMPARE (WAITID (P_ALL, 0, NULL, WEXITED), -1);
+ TEST_COMPARE (errno, ECHILD);
return 0;
}
@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <stdio.h>
#include <spawn.h>
#include <error.h>
@@ -27,9 +28,12 @@
#include <sys/resource.h>
#include <fcntl.h>
#include <paths.h>
+#include <intprops.h>
#include <support/check.h>
#include <support/temp_file.h>
+#include <support/xunistd.h>
+#include <tst-spawn.h>
static int
do_test (void)
@@ -48,7 +52,6 @@ do_test (void)
struct rlimit rl;
int max_fd = 24;
- int ret;
/* Set maximum number of file descriptor to a low value to avoid open
too many files in environments where RLIMIT_NOFILE is large and to
@@ -66,7 +69,7 @@ do_test (void)
/* Exhauste the file descriptor limit with temporary files. */
int files[max_fd];
int nfiles = 0;
- for (;;)
+ for (; nfiles < max_fd; nfiles++)
{
int fd = create_temp_file ("tst-spawn3.", NULL);
if (fd == -1)
@@ -75,75 +78,82 @@ do_test (void)
FAIL_EXIT1 ("create_temp_file: %m");
break;
}
- files[nfiles++] = fd;
+ files[nfiles] = fd;
}
+ assert (nfiles != 0);
posix_spawn_file_actions_t a;
- if (posix_spawn_file_actions_init (&a) != 0)
- FAIL_EXIT1 ("posix_spawn_file_actions_init");
+ TEST_COMPARE (posix_spawn_file_actions_init (&a), 0);
/* Executes a /bin/sh echo $$ 2>&1 > ${objpfx}tst-spawn3.pid . */
const char pidfile[] = OBJPFX "tst-spawn3.pid";
- if (posix_spawn_file_actions_addopen (&a, STDOUT_FILENO, pidfile, O_WRONLY
- | O_CREAT | O_TRUNC, 0644) != 0)
- FAIL_EXIT1 ("posix_spawn_file_actions_addopen");
+ TEST_COMPARE (posix_spawn_file_actions_addopen (&a, STDOUT_FILENO, pidfile,
+ O_WRONLY| O_CREAT | O_TRUNC,
+ 0644),
+ 0);
- if (posix_spawn_file_actions_adddup2 (&a, STDOUT_FILENO, STDERR_FILENO) != 0)
- FAIL_EXIT1 ("posix_spawn_file_actions_adddup2");
+ TEST_COMPARE (posix_spawn_file_actions_adddup2 (&a, STDOUT_FILENO,
+ STDERR_FILENO),
+ 0);
/* Since execve (called by posix_spawn) might require to open files to
actually execute the shell script, setup to close the temporary file
descriptors. */
- for (int i=0; i<nfiles; i++)
- {
- if (posix_spawn_file_actions_addclose (&a, files[i]))
- FAIL_EXIT1 ("posix_spawn_file_actions_addclose");
- }
+ int maxnfiles =
+#ifdef TST_SPAWN_PIDFD
+ /* The sparing file descriptor will be returned as the pid descriptor,
+ otherwise clone fail with EMFILE. */
+ nfiles - 1;
+#else
+ nfiles;
+#endif
+
+ for (int i=0; i<maxnfiles; i++)
+ TEST_COMPARE (posix_spawn_file_actions_addclose (&a, files[i]), 0);
char *spawn_argv[] = { (char *) _PATH_BSHELL, (char *) "-c",
(char *) "echo $$", NULL };
- pid_t pid;
- if ((ret = posix_spawn (&pid, _PATH_BSHELL, &a, NULL, spawn_argv, NULL))
- != 0)
- {
- errno = ret;
- FAIL_EXIT1 ("posix_spawn: %m");
- }
-
- int status;
- int err = waitpid (pid, &status, 0);
- if (err != pid)
- FAIL_EXIT1 ("waitpid: %m");
+ PID_T_TYPE pid;
+
+ {
+ int r = POSIX_SPAWN (&pid, _PATH_BSHELL, &a, NULL, spawn_argv, NULL);
+ if (r == ENOSYS)
+ FAIL_UNSUPPORTED ("kernel does not support CLONE_PIDFD clone flag");
+#ifdef TST_SPAWN_PIDFD
+ TEST_COMPARE (r, EMFILE);
+
+ /* Free up one file descriptor, so posix_spawn_pidfd_ex can return it. */
+ xclose (files[nfiles-1]);
+ nfiles--;
+ r = POSIX_SPAWN (&pid, _PATH_BSHELL, &a, NULL, spawn_argv, NULL);
+#endif
+ TEST_COMPARE (r, 0);
+ }
+
+ siginfo_t sinfo;
+ TEST_COMPARE (WAITID (P_PID, pid, &sinfo, WEXITED), 0);
+ TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+ TEST_COMPARE (sinfo.si_status, 0);
/* Close the temporary files descriptor so it can check posix_spawn
output. */
for (int i=0; i<nfiles; i++)
- {
- if (close (files[i]))
- FAIL_EXIT1 ("close: %m");
- }
+ xclose (files[i]);
- int pidfd = open (pidfile, O_RDONLY);
- if (pidfd == -1)
- FAIL_EXIT1 ("open: %m");
+ int pidfd = xopen (pidfile, O_RDONLY, 0);
- char buf[64];
- ssize_t n;
- if ((n = read (pidfd, buf, sizeof (buf))) < 0)
- FAIL_EXIT1 ("read: %m");
+ char buf[INT_STRLEN_BOUND (pid_t)];
+ ssize_t n = read (pidfd, buf, sizeof (buf));
+ TEST_VERIFY (n < sizeof buf && n >= 0);
- unlink (pidfile);
+ xunlink (pidfile);
/* We only expect to read the PID. */
char *endp;
long int rpid = strtol (buf, &endp, 10);
- if (*endp != '\n')
- FAIL_EXIT1 ("*endp != \'n\'");
- if (endp == buf)
- FAIL_EXIT1 ("read empty line");
+ TEST_VERIFY (*endp == '\n' && endp != buf);
- if (rpid != pid)
- FAIL_EXIT1 ("found \"%s\", expected pid %ld\n", buf, (long int) pid);
+ TEST_COMPARE (rpid, sinfo.si_pid);
return 0;
}
@@ -24,6 +24,7 @@
#include <support/xunistd.h>
#include <support/check.h>
#include <support/temp_file.h>
+#include <tst-spawn.h>
static int
do_test (void)
@@ -38,15 +39,15 @@ do_test (void)
TEST_VERIFY_EXIT (chmod (scriptname, 0x775) == 0);
- pid_t pid;
+ PID_T_TYPE pid;
int status;
/* Check if scripts without shebang are correctly not executed. */
- status = posix_spawn (&pid, scriptname, NULL, NULL, (char *[]) { 0 },
+ status = POSIX_SPAWN (&pid, scriptname, NULL, NULL, (char *[]) { 0 },
(char *[]) { 0 });
TEST_VERIFY_EXIT (status == ENOEXEC);
- status = posix_spawnp (&pid, scriptname, NULL, NULL, (char *[]) { 0 },
+ status = POSIX_SPAWNP (&pid, scriptname, NULL, NULL, (char *[]) { 0 },
(char *[]) { 0 });
TEST_VERIFY_EXIT (status == ENOEXEC);
@@ -33,6 +33,7 @@
#include <arch-fd_to_filename.h>
#include <array_length.h>
+#include <tst-spawn.h>
/* Nonzero if the program gets called via `exec'. */
static int restart;
@@ -161,14 +162,13 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd,
args[argc] = NULL;
TEST_VERIFY (argc < argv_size);
- pid_t pid;
- int status;
+ PID_T_TYPE pid;
+ siginfo_t sinfo;
- TEST_COMPARE (posix_spawn (&pid, args[0], fa, NULL, args, environ), 0);
- TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
- TEST_VERIFY (WIFEXITED (status));
- TEST_VERIFY (!WIFSIGNALED (status));
- TEST_COMPARE (WEXITSTATUS (status), 0);
+ TEST_COMPARE (POSIX_SPAWN (&pid, args[0], fa, NULL, args, environ), 0);
+ TEST_COMPARE (WAITID (P_PID, pid, &sinfo, WEXITED), 0);
+ TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+ TEST_COMPARE (sinfo.si_status, 0);
}
static void
@@ -32,6 +32,7 @@
#include <sys/ioctl.h>
#include <stdlib.h>
#include <termios.h>
+#include <tst-spawn.h>
#ifndef PATH_MAX
# define PATH_MAX 1024
@@ -108,17 +109,15 @@ run_subprogram (int argc, char *argv[], const posix_spawnattr_t *attr,
spargv[i] = NULL;
pid_t pid;
- TEST_COMPARE (posix_spawn (&pid, argv[1], actions, attr, spargv, environ),
+ TEST_COMPARE (POSIX_SPAWN (&pid, argv[1], actions, attr, spargv, environ),
exp_err);
if (exp_err != 0)
return;
- int status;
- TEST_COMPARE (xwaitpid (pid, &status, WUNTRACED), pid);
- TEST_VERIFY (WIFEXITED (status));
- TEST_VERIFY (!WIFSTOPPED (status));
- TEST_VERIFY (!WIFSIGNALED (status));
- TEST_COMPARE (WEXITSTATUS (status), 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);
}
static int
@@ -202,7 +201,7 @@ do_test (int argc, char *argv[])
if (restart)
return handle_restart (argv[1], argv[2]);
- pid_t pid = xfork ();
+ PID_T_TYPE pid = xfork ();
if (pid == 0)
{
/* Create a pseudo-terminal to avoid interfering with the one using by
@@ -24,7 +24,9 @@
#include <support/check.h>
#include <support/xsignal.h>
#include <support/xunistd.h>
+#include <sys/wait.h>
#include <unistd.h>
+#include <tst-spawn.h>
/* Nonzero if the program gets called via `exec'. */
#define CMDLINE_OPTIONS \
@@ -81,14 +83,13 @@ spawn_signal_test (const char *type, const posix_spawnattr_t *attr)
{
spargs[check_type_argc] = (char*) type;
- pid_t pid;
- int status;
+ PID_T_TYPE pid;
+ siginfo_t sinfo;
TEST_COMPARE (posix_spawn (&pid, spargs[0], NULL, attr, spargs, environ), 0);
- TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
- TEST_VERIFY (WIFEXITED (status));
- TEST_VERIFY (!WIFSIGNALED (status));
- TEST_COMPARE (WEXITSTATUS (status), 0);
+ TEST_COMPARE (WAITID (P_ALL, 0, &sinfo, WEXITED), 0);
+ TEST_COMPARE (sinfo.si_code, CLD_EXITED);
+ TEST_COMPARE (sinfo.si_status, 0);
}
static void
@@ -62,6 +62,7 @@ sysdep_routines += \
clock_adjtime \
clone \
clone-internal \
+ clone-pidfd-support \
clone3 \
closefrom_fallback \
convert_scm_timestamps \
@@ -492,6 +493,8 @@ sysdep_headers += \
sysdep_routines += \
getcpu \
oldglob \
+ pidfd_spawn \
+ pidfd_spawnp \
sched_getcpu \
spawnattr_getcgroup_np \
spawnattr_setcgroup_np \
@@ -500,7 +503,16 @@ sysdep_routines += \
tests += \
tst-affinity \
tst-affinity-pid \
+ tst-posix_spawn-setsid-pidfd \
tst-spawn-cgroup \
+ tst-spawn-chdir-pidfd \
+ tst-spawn-pidfd \
+ tst-spawn2-pidfd \
+ tst-spawn3-pidfd \
+ tst-spawn4-pidfd \
+ tst-spawn5-pidfd \
+ tst-spawn6-pidfd \
+ tst-spawn7-pidfd \
# tests
tests-static += \
@@ -514,8 +526,14 @@ tests += \
CFLAGS-fork.c = $(libio-mtsafe)
CFLAGS-getpid.o = -fomit-frame-pointer
CFLAGS-getpid.os = -fomit-frame-pointer
+CFLAGS-tst-spawn3-pidfd.c += -DOBJPFX=\"$(objpfx)\"
tst-spawn-cgroup-ARGS = -- $(host-test-program-cmd)
+tst-spawn-pidfd-ARGS = -- $(host-test-program-cmd)
+tst-spawn5-pidfd-ARGS = -- $(host-test-program-cmd)
+tst-spawn6-pidfd-ARGS = -- $(host-test-program-cmd)
+tst-spawn7-pidfd-ARGS = -- $(host-test-program-cmd)
+tst-posix_spawn-setsid-pidfd-ARGS = -- $(host-test-program-cmd)
endif
ifeq ($(subdir),inet)
@@ -324,6 +324,8 @@ libc {
GLIBC_2.38 {
posix_spawnattr_getcgroup_np;
posix_spawnattr_setcgroup_np;
+ pidfd_spawn;
+ pidfd_spawnp;
}
GLIBC_PRIVATE {
# functions used in other libraries
@@ -2669,6 +2669,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2778,6 +2778,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2430,6 +2430,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -550,6 +550,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -547,6 +547,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -37,4 +37,24 @@ extern int posix_spawnattr_setcgroup_np (posix_spawnattr_t *__restrict __attr,
#endif /* __USE_MISC */
+#ifdef __USE_GNU
+
+extern int pidfd_spawn (int *__restrict __pidfd,
+ const char *__restrict __file,
+ const posix_spawn_file_actions_t *__restrict __facts,
+ const posix_spawnattr_t *__restrict __attrp,
+ char *const __argv[__restrict_arr],
+ char *const __envp[__restrict_arr])
+ __nonnull ((2, 5));
+
+extern int pidfd_spawnp (int *__restrict __pidfd,
+ const char *__restrict __path,
+ const posix_spawn_file_actions_t *__restrict __facts,
+ const posix_spawnattr_t *__restrict __attrp,
+ char *const __argv[__restrict_arr],
+ char *const __envp[__restrict_arr])
+ __nonnull ((2, 5));
+
+#endif /* __USE_GNU */
+
__END_DECLS
new file mode 100644
@@ -0,0 +1,58 @@
+/* Check if kernel supports PID file descriptors.
+ Copyright (C) 2023 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 <atomic.h>
+#include <sys/wait.h>
+#include <sysdep.h>
+
+/* The PID file descriptors was added during multiple releases:
+ - Linux 5.2 added CLONE_PIDFD support for clone and __clone_pidfd_supported
+ syscall.
+ - Linux 5.3 added support for poll and CLONE_PIDFD for clone3.
+ - Linux 5.4 added P_PIDFD support on waitid.
+
+ For internal usage on spawn and fork, it only make sense to return a file
+ descriptor if caller can actually waitid on it. */
+bool
+__clone_pidfd_supported (void)
+{
+ static int supported = 0;
+ int state = atomic_load_relaxed (&supported);
+ if (state == 0)
+ {
+ /* Linux define the maximum allocated file descriptor value as
+ 0x7fffffc0 (from fs/file.c):
+
+ #define __const_min(x, y) ((x) < (y) ? (x) : (y))
+ unsigned int sysctl_nr_open_max =
+ __const_min(INT_MAX, ~(size_t)0/sizeof(void *)) & -BITS_PER_LONG;
+
+ So we can detect whether kernel supports all pidfd interfaces by
+ using a valid but never allocated file descriptor: if is not
+ supported waitid will return EINVAL, otherwise EBADF.
+
+ Also the waitid is a cancellation entrypoint, so issue the syscall
+ directly. */
+ int r = INTERNAL_SYSCALL_CALL (waitid, P_PIDFD, INT_MAX, NULL,
+ WEXITED | WNOHANG, NULL);
+ state = r == -EBADF ? 1 : -1;
+ atomic_store_relaxed (&supported, state);
+ }
+
+ return state == 1;
+}
@@ -2706,6 +2706,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2655,6 +2655,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2839,6 +2839,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2604,6 +2604,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2190,6 +2190,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -551,6 +551,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2782,6 +2782,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2755,6 +2755,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2752,6 +2752,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2747,6 +2747,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2745,6 +2745,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2753,6 +2753,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2655,6 +2655,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2794,6 +2794,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2176,6 +2176,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
new file mode 100644
@@ -0,0 +1,30 @@
+/* pidfd_spawn - Spawn a process and return a pid file descriptor.
+ Copyright (C) 2023 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 <spawn.h>
+#include "spawn_int.h"
+
+int
+pidfd_spawn (int *pidfd, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp, char *const argv[],
+ char *const envp[])
+{
+ return __spawni (pidfd, path, file_actions, attrp, argv, envp,
+ SPAWN_XFLAGS_RET_PIDFD);
+}
new file mode 100644
@@ -0,0 +1,30 @@
+/* pidfd_spawnp - Spawn a process and return a pid file descriptor.
+ Copyright (C) 2023 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 <spawn.h>
+#include "spawn_int.h"
+
+int
+pidfd_spawnp (int *pidfd, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp, char *const argv[],
+ char *const envp[])
+{
+ return __spawni (pidfd, path, file_actions, attrp, argv, envp,
+ SPAWN_XFLAGS_USE_PATH | SPAWN_XFLAGS_RET_PIDFD);
+}
@@ -2821,6 +2821,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2854,6 +2854,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2575,6 +2575,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2889,6 +2889,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2432,6 +2432,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2632,6 +2632,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2819,6 +2819,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2612,6 +2612,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2662,6 +2662,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2659,6 +2659,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2814,6 +2814,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2627,6 +2627,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -68,6 +68,7 @@ struct posix_spawn_args
int xflags;
bool use_clone3;
int err;
+ int pidfd;
};
/* Older version requires that shell script without shebang definition
@@ -309,7 +310,7 @@ fail:
/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
Before running the process perform the actions described in FILE-ACTIONS. */
static int
-__spawnix (pid_t * pid, const char *file,
+__spawnix (int *pid, const char *file,
const posix_spawn_file_actions_t * file_actions,
const posix_spawnattr_t * attrp, char *const argv[],
char *const envp[], int xflags,
@@ -319,6 +320,15 @@ __spawnix (pid_t * pid, const char *file,
struct posix_spawn_args args;
int ec;
+ bool use_pidfd = xflags & SPAWN_XFLAGS_RET_PIDFD;
+
+ /* For CLONE_PIDFD, older kernels might not fail with unsupported flags or
+ some versions might not support waitid (P_PIDFD). So to avoid the need
+ to handle the error on the helper process, check for full pidfd
+ support. */
+ if (use_pidfd && !__clone_pidfd_supported ())
+ return ENOSYS;
+
/* To avoid imposing hard limits on posix_spawn{p} the total number of
arguments is first calculated to allocate a mmap to hold all possible
values. */
@@ -368,6 +378,7 @@ __spawnix (pid_t * pid, const char *file,
args.argv = argv;
args.argc = argc;
args.envp = envp;
+ args.pidfd = 0;
args.xflags = xflags;
internal_signal_block_all (&args.oldmask);
@@ -386,13 +397,16 @@ __spawnix (pid_t * pid, const char *file,
/* Unsupported flags like CLONE_CLEAR_SIGHAND will be cleared up by
__clone_internal_fallback. */
.flags = (set_cgroup ? CLONE_INTO_CGROUP : 0)
+ | (use_pidfd ? CLONE_PIDFD : 0)
| CLONE_CLEAR_SIGHAND
| CLONE_VM
| CLONE_VFORK,
.exit_signal = SIGCHLD,
.stack = (uintptr_t) stack,
.stack_size = stack_size,
- .cgroup = (set_cgroup ? attrp->__cgroup : 0)
+ .cgroup = (set_cgroup ? attrp->__cgroup : 0),
+ .pidfd = use_pidfd ? (uintptr_t) &args.pidfd : 0,
+ .parent_tid = use_pidfd ? (uintptr_t) &args.pidfd : 0,
};
#ifdef HAVE_CLONE3_WRAPPER
args.use_clone3 = true;
@@ -443,7 +457,7 @@ __spawnix (pid_t * pid, const char *file,
__munmap (stack, stack_size);
if ((ec == 0) && (pid != NULL))
- *pid = new_pid;
+ *pid = use_pidfd ? args.pidfd : new_pid;
internal_signal_restore_set (&args.oldmask);
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-posix_spawn-setsid.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn-chdir.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn.c>
new file mode 100644
@@ -0,0 +1,63 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <errno.h>
+#include <spawn.h>
+#include <support/check.h>
+
+#define PID_T_TYPE int
+
+/* Call posix_spawn with POSIX_SPAWN_PIDFD set. */
+static inline int
+pidfd_spawn_check (int *pidfd, const char *path,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *attr, char *const argv[],
+ char *const envp[])
+{
+ int r = pidfd_spawn (pidfd, path, fa, attr, argv, envp);
+ if (r == ENOSYS)
+ FAIL_UNSUPPORTED ("kernel does not support CLONE_PIDFD clone flag");
+ return r;
+}
+
+#define POSIX_SPAWN(__pidfd, __path, __actions, __attr, __argv, __envp) \
+ pidfd_spawn_check (__pidfd, __path, __actions, __attr, __argv, __envp)
+
+static inline int
+pidfd_spawnp_check (int *pidfd, const char *file,
+ const posix_spawn_file_actions_t *fa,
+ const posix_spawnattr_t *attr,
+ char *const argv[], char *const envp[])
+{
+ int r = pidfd_spawnp (pidfd, file, fa, attr, argv, envp);
+ if (r == ENOSYS)
+ FAIL_UNSUPPORTED ("kernel does not support CLONE_PIDFD clone flag");
+ return r;
+}
+
+#define POSIX_SPAWNP(__child, __path, __actions, __attr, __argv, __envp) \
+ pidfd_spawnp_check (__child, __path, __actions, __attr, __argv, __envp)
+
+#define WAITID(__idtype, __id, __info, __opts) \
+ ({ \
+ __typeof (__idtype) __new_idtype = __idtype == P_PID \
+ ? P_PIDFD : __idtype; \
+ waitid (__new_idtype, __id, __info, __opts); \
+ })
+
+#define TST_SPAWN_PIDFD 1
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn2.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Check posix_spawn add file actions.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn3.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn4.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn5.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn6.c>
new file mode 100644
@@ -0,0 +1,20 @@
+/* Tests for spawn pidfd extension.
+ Copyright (C) 2023 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 <tst-spawn-pidfd.h>
+#include <posix/tst-spawn7.c>
@@ -2578,6 +2578,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F
@@ -2684,6 +2684,8 @@ GLIBC_2.38 __strlcat_chk F
GLIBC_2.38 __strlcpy_chk F
GLIBC_2.38 __wcslcat_chk F
GLIBC_2.38 __wcslcpy_chk F
+GLIBC_2.38 pidfd_spawn F
+GLIBC_2.38 pidfd_spawnp F
GLIBC_2.38 posix_spawnattr_getcgroup_np F
GLIBC_2.38 posix_spawnattr_setcgroup_np F
GLIBC_2.38 strlcat F