1 /* Check posix_spawn add file actions.
2 Copyright (C) 2016-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
27 #include <sys/resource.h>
32 #include <support/check.h>
33 #include <support/temp_file.h>
34 #include <support/xunistd.h>
35 #include <tst-spawn.h>
40 /* The test checks if posix_spawn open file action close the file descriptor
41 before opening a new one in case the input file descriptor is already
42 opened. It does by exhausting all file descriptors on the process before
43 issue posix_spawn. It then issues a posix_spawn for '/bin/sh echo $$'
46 1. Redirect stdout to a temporary filepath
47 2. Redirect stderr to stdout
49 If the implementation does not close the file 1. will fail with
55 /* Set maximum number of file descriptor to a low value to avoid open
56 too many files in environments where RLIMIT_NOFILE is large and to
57 limit the array size to track the opened file descriptors. */
59 if (getrlimit (RLIMIT_NOFILE
, &rl
) == -1)
60 FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
62 max_fd
= (rl
.rlim_cur
< max_fd
? rl
.rlim_cur
: max_fd
);
65 if (setrlimit (RLIMIT_NOFILE
, &rl
) == 1)
66 FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
68 /* Exhauste the file descriptor limit with temporary files. */
71 for (; nfiles
< max_fd
; nfiles
++)
73 int fd
= create_temp_file ("tst-spawn3.", NULL
);
77 FAIL_EXIT1 ("create_temp_file: %m");
82 TEST_VERIFY_EXIT (nfiles
!= 0);
84 posix_spawn_file_actions_t a
;
85 TEST_COMPARE (posix_spawn_file_actions_init (&a
), 0);
87 /* Executes a /bin/sh echo $$ 2>&1 > ${objpfx}tst-spawn3.pid . */
88 const char pidfile
[] = OBJPFX
"tst-spawn3.pid";
89 TEST_COMPARE (posix_spawn_file_actions_addopen (&a
, STDOUT_FILENO
, pidfile
,
90 O_WRONLY
| O_CREAT
| O_TRUNC
,
94 TEST_COMPARE (posix_spawn_file_actions_adddup2 (&a
, STDOUT_FILENO
,
98 /* Since execve (called by posix_spawn) might require to open files to
99 actually execute the shell script, setup to close the temporary file
102 #ifdef TST_SPAWN_PIDFD
103 /* The sparing file descriptor will be returned as the pid descriptor,
104 otherwise clone fail with EMFILE. */
110 for (int i
=0; i
<maxnfiles
; i
++)
111 TEST_COMPARE (posix_spawn_file_actions_addclose (&a
, files
[i
]), 0);
113 char *spawn_argv
[] = { (char *) _PATH_BSHELL
, (char *) "-c",
114 (char *) "echo $$", NULL
};
118 int r
= POSIX_SPAWN (&pid
, _PATH_BSHELL
, &a
, NULL
, spawn_argv
, NULL
);
120 FAIL_UNSUPPORTED ("kernel does not support CLONE_PIDFD clone flag");
121 #ifdef TST_SPAWN_PIDFD
122 TEST_COMPARE (r
, EMFILE
);
124 /* Free up one file descriptor, so posix_spawn_pidfd_ex can return it. */
125 xclose (files
[nfiles
-1]);
127 r
= POSIX_SPAWN (&pid
, _PATH_BSHELL
, &a
, NULL
, spawn_argv
, NULL
);
133 TEST_COMPARE (WAITID (P_PID
, pid
, &sinfo
, WEXITED
), 0);
134 TEST_COMPARE (sinfo
.si_code
, CLD_EXITED
);
135 TEST_COMPARE (sinfo
.si_status
, 0);
137 /* Close the temporary files descriptor so it can check posix_spawn
139 for (int i
=0; i
<nfiles
; i
++)
142 int pidfd
= xopen (pidfile
, O_RDONLY
, 0);
144 char buf
[INT_BUFSIZE_BOUND (pid_t
)];
145 ssize_t n
= read (pidfd
, buf
, sizeof (buf
));
146 TEST_VERIFY (n
< sizeof buf
&& n
>= 0);
150 /* We only expect to read the PID. */
152 long int rpid
= strtol (buf
, &endp
, 10);
153 TEST_VERIFY (*endp
== '\n' && endp
!= buf
);
155 TEST_COMPARE (rpid
, sinfo
.si_pid
);
160 #include <support/test-driver.c>