doc: Document version-etc, version-etc, and argp-version-etc.
[gnulib.git] / tests / test-execute-child.c
blob6e5a209eaeaeaeb9fefc2a21a07a2d32352c5c66
1 /* Child program invoked by test-execute-main.
2 Copyright (C) 2009-2025 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
17 /* If the user's config.h happens to include <sys/stat.h>, let it include only
18 the system's <sys/stat.h> here. */
19 #define __need_system_sys_stat_h
20 #include <config.h>
22 /* Get the original definition of fstat. It might be defined as a macro.
23 Also, 'stat' might be defined as a macro. */
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #undef __need_system_sys_stat_h
28 /* Return non-zero if FD is opened to a device. */
29 static int
30 is_device (int fd)
32 #if defined _WIN32 && ! defined __CYGWIN__
33 struct _stat st;
34 return _fstat (fd, &st) >= 0 && !((st.st_mode & S_IFMT) == S_IFREG);
35 #else
36 struct stat st;
37 return fstat (fd, &st) >= 0 && !S_ISREG (st.st_mode);
38 #endif
41 /* Now include the other header files. */
42 #include <fcntl.h>
43 #include <signal.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
50 #if defined _WIN32 && ! defined __CYGWIN__
51 /* Get declarations of the native Windows API functions. */
52 # define WIN32_LEAN_AND_MEAN
53 # include <windows.h>
54 /* Get _get_osfhandle, _isatty, _chdir, _getcwd. */
55 # include <io.h>
56 #endif
58 /* In this file, we use only system functions, no overrides from gnulib. */
59 #undef abort
60 #undef atoi
61 #undef close
62 #undef fcntl
63 #undef fflush
64 #undef fgetc
65 #undef fprintf
66 #undef fputs
67 #undef getcwd
68 #undef isatty
69 #undef open
70 #undef raise
71 #undef read
72 #undef sprintf
73 #undef strcasestr
74 #undef strcmp
75 #undef strlen
76 #undef strstr
77 #undef write
79 /* macOS 12's "warning: 'sprintf' is deprecated" is pointless,
80 as sprintf is used safely here. */
81 #if defined __APPLE__ && defined __MACH__ && _GL_GNUC_PREREQ (4, 2)
82 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
83 #endif
85 #include "qemu.h"
87 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
88 static void __cdecl
89 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
90 const wchar_t *function,
91 const wchar_t *file,
92 unsigned int line,
93 uintptr_t dummy)
96 #endif
98 /* Return non-zero if FD is open. */
99 static int
100 is_open (int fd)
102 #if defined _WIN32 && ! defined __CYGWIN__
103 /* On native Windows, the initial state of unassigned standard file
104 descriptors is that they are open but point to an
105 INVALID_HANDLE_VALUE, and there is no fcntl. */
106 return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
107 #else
108 # ifndef F_GETFL
109 # error Please port fcntl to your platform
110 # endif
111 return 0 <= fcntl (fd, F_GETFL);
112 #endif
116 main (int argc, char *argv[])
118 if (argc == 1)
119 /* Check an invocation without arguments. Check the exit code. */
120 return 40;
122 int test = atoi (argv[1]);
123 switch (test)
125 case 2:
126 /* Check argument passing. */
127 return !(argc == 12
128 && strcmp (argv[2], "abc def") == 0
129 && strcmp (argv[3], "abc\"def\"ghi") == 0
130 && strcmp (argv[4], "xyz\"") == 0
131 && strcmp (argv[5], "abc\\def\\ghi") == 0
132 && strcmp (argv[6], "xyz\\") == 0
133 && strcmp (argv[7], "???") == 0
134 && strcmp (argv[8], "***") == 0
135 && strcmp (argv[9], "") == 0
136 && strcmp (argv[10], "foo") == 0
137 && strcmp (argv[11], "") == 0);
138 #if !(defined _WIN32 && !defined __CYGWIN__)
139 case 3:
140 /* Check SIGPIPE handling with ignore_sigpipe = false. */
141 case 4:
142 /* Check SIGPIPE handling with ignore_sigpipe = true. */
143 raise (SIGPIPE);
144 return 71;
145 #endif
146 case 5:
147 /* Check other signal. */
148 raise (SIGINT);
149 return 71;
150 case 6:
151 /* Check stdin is inherited. */
152 return !(fgetc (stdin) == 'F' && fgetc (stdin) == 'o');
153 case 7:
154 /* Check null_stdin = true. */
155 return !(fgetc (stdin) == EOF);
156 case 8:
157 /* Check stdout is inherited, part 1 (regular file). */
158 return !(fputs ("bar", stdout) != EOF && fflush (stdout) == 0);
159 case 9:
160 /* Check stdout is inherited, part 2 (device). */
161 case 10:
162 /* Check null_stdout = true. */
163 return !is_device (STDOUT_FILENO);
164 case 11:
165 /* Check stderr is inherited, part 1 (regular file). */
166 return !(fputs ("bar", stderr) != EOF && fflush (stderr) == 0);
167 case 12:
168 /* Check stderr is inherited, part 2 (device). */
169 case 13:
170 /* Check null_stderr = true. */
171 return !is_device (STDERR_FILENO);
172 case 14:
173 case 15:
174 /* Check file descriptors >= 3 can be inherited. */
175 case 16:
176 /* Check file descriptors >= 3 with O_CLOEXEC bit are not inherited. */
177 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
178 /* Avoid exceptions from within _get_osfhandle. */
179 _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
180 #endif
182 /* QEMU 6.1 in user-mode passes an open fd = 3, that references
183 /dev/urandom. We need to ignore this fd. */
184 bool is_qemu = is_running_under_qemu_user ();
185 char buf[300];
186 buf[0] = '\0';
187 char *p = buf;
188 int fd;
189 for (fd = 0; fd < 20; fd++)
190 if (is_open (fd) && !(is_qemu && fd == 3))
192 sprintf (p, "%d ", fd);
193 p += strlen (p);
195 const char *expected = (test < 16 ? "0 1 2 10 " : "0 1 2 ");
196 if (strcmp (buf, expected) == 0)
197 return 0;
198 else
200 fprintf (stderr, "Test case %d: %s\n", test, buf); fflush (stderr);
201 return 1;
204 case 17:
205 /* Check that file descriptors >= 3, open for reading, can be inherited,
206 including the file position. */
208 char buf[6];
209 int n = read (15, buf, sizeof (buf));
210 return !(n == 4 && memcmp (buf, "obar", 4) == 0);
212 case 18:
213 /* Check that file descriptors >= 3, open for writing, can be inherited,
214 including the file position. */
216 int n = write (15, "bar", 3);
217 return !(n == 3);
219 case 19:
220 /* Check that file descriptors >= 3, when inherited, preserve their
221 isatty() property, part 1 (regular file). */
222 case 20:
223 /* Check that file descriptors >= 3, when inherited, preserve their
224 isatty() property, part 2 (character devices). */
226 #if defined _WIN32 && ! defined __CYGWIN__
227 return 4 + 2 * (_isatty (15) != 0) + (_isatty (16) != 0);
228 #else
229 return 4 + 2 * (isatty (15) != 0) + (isatty (16) != 0);
230 #endif
232 case 21:
233 /* Check execution in a different directory. */
235 char cwd[1024];
236 #if defined _WIN32 && ! defined __CYGWIN__
237 if (_chdir ("..") != 0)
238 return 1;
239 if (_getcwd (cwd, sizeof (cwd)) == NULL)
240 return 2;
241 #else
242 if (chdir ("..") != 0)
243 return 1;
244 if (getcwd (cwd, sizeof (cwd)) == NULL)
245 return 2;
246 #endif
247 return (argc == 3 && strcmp (argv[2], cwd) == 0 ? 0 : 3);
249 default:
250 abort ();