1 | /* -*- coding: utf-8 -*- |
2 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
3 | // See https://llvm.org/LICENSE.txt for license information. |
4 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
5 | */ |
6 | |
7 | #include "config.h" |
8 | |
9 | #include <sys/wait.h> |
10 | #include <unistd.h> |
11 | #include <stdio.h> |
12 | #include <stdlib.h> |
13 | #include <paths.h> |
14 | |
15 | #if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP |
16 | #include <spawn.h> |
17 | #endif |
18 | |
19 | // ..:: environment access fixer - begin ::.. |
20 | #ifdef HAVE_NSGETENVIRON |
21 | #include <crt_externs.h> |
22 | #else |
23 | extern char **environ; |
24 | #endif |
25 | |
26 | char **get_environ() { |
27 | #ifdef HAVE_NSGETENVIRON |
28 | return *_NSGetEnviron(); |
29 | #else |
30 | return environ; |
31 | #endif |
32 | } |
33 | // ..:: environment access fixer - end ::.. |
34 | |
35 | // ..:: test fixtures - begin ::.. |
36 | static char const *cwd = NULL; |
37 | static FILE *fd = NULL; |
38 | static int need_comma = 0; |
39 | |
40 | void expected_out_open(const char *expected) { |
41 | cwd = getcwd(NULL, size: 0); |
42 | fd = fopen(filename: expected, modes: "w" ); |
43 | if (!fd) { |
44 | perror(s: "fopen" ); |
45 | exit(EXIT_FAILURE); |
46 | } |
47 | fprintf(stream: fd, format: "[\n" ); |
48 | need_comma = 0; |
49 | } |
50 | |
51 | void expected_out_close() { |
52 | fprintf(stream: fd, format: "]\n" ); |
53 | fclose(stream: fd); |
54 | fd = NULL; |
55 | |
56 | free(ptr: (void *)cwd); |
57 | cwd = NULL; |
58 | } |
59 | |
60 | void expected_out(const char *file) { |
61 | if (need_comma) |
62 | fprintf(stream: fd, format: ",\n" ); |
63 | else |
64 | need_comma = 1; |
65 | |
66 | fprintf(stream: fd, format: "{\n" ); |
67 | fprintf(stream: fd, format: " \"directory\": \"%s\",\n" , cwd); |
68 | fprintf(stream: fd, format: " \"command\": \"cc -c %s\",\n" , file); |
69 | fprintf(stream: fd, format: " \"file\": \"%s/%s\"\n" , cwd, file); |
70 | fprintf(stream: fd, format: "}\n" ); |
71 | } |
72 | |
73 | void create_source(char *file) { |
74 | FILE *fd = fopen(filename: file, modes: "w" ); |
75 | if (!fd) { |
76 | perror(s: "fopen" ); |
77 | exit(EXIT_FAILURE); |
78 | } |
79 | fprintf(stream: fd, format: "typedef int score;\n" ); |
80 | fclose(stream: fd); |
81 | } |
82 | |
83 | typedef void (*exec_fun)(); |
84 | |
85 | void wait_for(pid_t child) { |
86 | int status; |
87 | if (-1 == waitpid(pid: child, stat_loc: &status, options: 0)) { |
88 | perror(s: "wait" ); |
89 | exit(EXIT_FAILURE); |
90 | } |
91 | if (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE) { |
92 | fprintf(stderr, format: "children process has non zero exit code\n" ); |
93 | exit(EXIT_FAILURE); |
94 | } |
95 | } |
96 | |
97 | #define FORK(FUNC) \ |
98 | { \ |
99 | pid_t child = fork(); \ |
100 | if (-1 == child) { \ |
101 | perror("fork"); \ |
102 | exit(EXIT_FAILURE); \ |
103 | } else if (0 == child) { \ |
104 | FUNC fprintf(stderr, "children process failed to exec\n"); \ |
105 | exit(EXIT_FAILURE); \ |
106 | } else { \ |
107 | wait_for(child); \ |
108 | } \ |
109 | } |
110 | // ..:: test fixtures - end ::.. |
111 | |
112 | #ifdef HAVE_EXECV |
113 | void call_execv() { |
114 | char *const file = "execv.c" ; |
115 | char *const compiler = "/usr/bin/cc" ; |
116 | char *const argv[] = {"cc" , "-c" , file, 0}; |
117 | |
118 | expected_out(file); |
119 | create_source(file); |
120 | |
121 | FORK(execv(compiler, argv);) |
122 | } |
123 | #endif |
124 | |
125 | #ifdef HAVE_EXECVE |
126 | void call_execve() { |
127 | char *const file = "execve.c" ; |
128 | char *const compiler = "/usr/bin/cc" ; |
129 | char *const argv[] = {compiler, "-c" , file, 0}; |
130 | char *const envp[] = {"THIS=THAT" , 0}; |
131 | |
132 | expected_out(file); |
133 | create_source(file); |
134 | |
135 | FORK(execve(compiler, argv, envp);) |
136 | } |
137 | #endif |
138 | |
139 | #ifdef HAVE_EXECVP |
140 | void call_execvp() { |
141 | char *const file = "execvp.c" ; |
142 | char *const compiler = "cc" ; |
143 | char *const argv[] = {compiler, "-c" , file, 0}; |
144 | |
145 | expected_out(file); |
146 | create_source(file); |
147 | |
148 | FORK(execvp(compiler, argv);) |
149 | } |
150 | #endif |
151 | |
152 | #ifdef HAVE_EXECVP2 |
153 | void call_execvP() { |
154 | char *const file = "execv_p.c" ; |
155 | char *const compiler = "cc" ; |
156 | char *const argv[] = {compiler, "-c" , file, 0}; |
157 | |
158 | expected_out(file); |
159 | create_source(file); |
160 | |
161 | FORK(execvP(compiler, _PATH_DEFPATH, argv);) |
162 | } |
163 | #endif |
164 | |
165 | #ifdef HAVE_EXECVPE |
166 | void call_execvpe() { |
167 | char *const file = "execvpe.c" ; |
168 | char *const compiler = "cc" ; |
169 | char *const argv[] = {"/usr/bin/cc" , "-c" , file, 0}; |
170 | char *const envp[] = {"THIS=THAT" , 0}; |
171 | |
172 | expected_out(file); |
173 | create_source(file); |
174 | |
175 | FORK(execvpe(compiler, argv, envp);) |
176 | } |
177 | #endif |
178 | |
179 | #ifdef HAVE_EXECT |
180 | void call_exect() { |
181 | char *const file = "exect.c" ; |
182 | char *const compiler = "/usr/bin/cc" ; |
183 | char *const argv[] = {compiler, "-c" , file, 0}; |
184 | char *const envp[] = {"THIS=THAT" , 0}; |
185 | |
186 | expected_out(file); |
187 | create_source(file); |
188 | |
189 | FORK(exect(compiler, argv, envp);) |
190 | } |
191 | #endif |
192 | |
193 | #ifdef HAVE_EXECL |
194 | void call_execl() { |
195 | char *const file = "execl.c" ; |
196 | char *const compiler = "/usr/bin/cc" ; |
197 | |
198 | expected_out(file); |
199 | create_source(file); |
200 | |
201 | FORK(execl(compiler, "cc" , "-c" , file, (char *)0);) |
202 | } |
203 | #endif |
204 | |
205 | #ifdef HAVE_EXECLP |
206 | void call_execlp() { |
207 | char *const file = "execlp.c" ; |
208 | char *const compiler = "cc" ; |
209 | |
210 | expected_out(file); |
211 | create_source(file); |
212 | |
213 | FORK(execlp(compiler, compiler, "-c" , file, (char *)0);) |
214 | } |
215 | #endif |
216 | |
217 | #ifdef HAVE_EXECLE |
218 | void call_execle() { |
219 | char *const file = "execle.c" ; |
220 | char *const compiler = "/usr/bin/cc" ; |
221 | char *const envp[] = {"THIS=THAT" , 0}; |
222 | |
223 | expected_out(file); |
224 | create_source(file); |
225 | |
226 | FORK(execle(compiler, compiler, "-c" , file, (char *)0, envp);) |
227 | } |
228 | #endif |
229 | |
230 | #ifdef HAVE_POSIX_SPAWN |
231 | void call_posix_spawn() { |
232 | char *const file = "posix_spawn.c" ; |
233 | char *const compiler = "cc" ; |
234 | char *const argv[] = {compiler, "-c" , file, 0}; |
235 | |
236 | expected_out(file); |
237 | create_source(file); |
238 | |
239 | pid_t child; |
240 | if (0 != posix_spawn(&child, "/usr/bin/cc" , 0, 0, argv, get_environ())) { |
241 | perror("posix_spawn" ); |
242 | exit(EXIT_FAILURE); |
243 | } |
244 | wait_for(child); |
245 | } |
246 | #endif |
247 | |
248 | #ifdef HAVE_POSIX_SPAWNP |
249 | void call_posix_spawnp() { |
250 | char *const file = "posix_spawnp.c" ; |
251 | char *const compiler = "cc" ; |
252 | char *const argv[] = {compiler, "-c" , file, 0}; |
253 | |
254 | expected_out(file); |
255 | create_source(file); |
256 | |
257 | pid_t child; |
258 | if (0 != posix_spawnp(&child, "cc" , 0, 0, argv, get_environ())) { |
259 | perror("posix_spawnp" ); |
260 | exit(EXIT_FAILURE); |
261 | } |
262 | wait_for(child); |
263 | } |
264 | #endif |
265 | |
266 | int main(int argc, char *const argv[]) { |
267 | if (argc != 2) |
268 | exit(EXIT_FAILURE); |
269 | |
270 | expected_out_open(expected: argv[1]); |
271 | #ifdef HAVE_EXECV |
272 | call_execv(); |
273 | #endif |
274 | #ifdef HAVE_EXECVE |
275 | call_execve(); |
276 | #endif |
277 | #ifdef HAVE_EXECVP |
278 | call_execvp(); |
279 | #endif |
280 | #ifdef HAVE_EXECVP2 |
281 | call_execvP(); |
282 | #endif |
283 | #ifdef HAVE_EXECVPE |
284 | call_execvpe(); |
285 | #endif |
286 | #ifdef HAVE_EXECT |
287 | call_exect(); |
288 | #endif |
289 | #ifdef HAVE_EXECL |
290 | call_execl(); |
291 | #endif |
292 | #ifdef HAVE_EXECLP |
293 | call_execlp(); |
294 | #endif |
295 | #ifdef HAVE_EXECLE |
296 | call_execle(); |
297 | #endif |
298 | #ifdef HAVE_POSIX_SPAWN |
299 | call_posix_spawn(); |
300 | #endif |
301 | #ifdef HAVE_POSIX_SPAWNP |
302 | call_posix_spawnp(); |
303 | #endif |
304 | expected_out_close(); |
305 | return 0; |
306 | } |
307 | |