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
get_environ()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
expected_out_open(const char * expected)40 void expected_out_open(const char *expected) {
41 cwd = getcwd(NULL, 0);
42 fd = fopen(expected, "w");
43 if (!fd) {
44 perror("fopen");
45 exit(EXIT_FAILURE);
46 }
47 fprintf(fd, "[\n");
48 need_comma = 0;
49 }
50
expected_out_close()51 void expected_out_close() {
52 fprintf(fd, "]\n");
53 fclose(fd);
54 fd = NULL;
55
56 free((void *)cwd);
57 cwd = NULL;
58 }
59
expected_out(const char * file)60 void expected_out(const char *file) {
61 if (need_comma)
62 fprintf(fd, ",\n");
63 else
64 need_comma = 1;
65
66 fprintf(fd, "{\n");
67 fprintf(fd, " \"directory\": \"%s\",\n", cwd);
68 fprintf(fd, " \"command\": \"cc -c %s\",\n", file);
69 fprintf(fd, " \"file\": \"%s/%s\"\n", cwd, file);
70 fprintf(fd, "}\n");
71 }
72
create_source(char * file)73 void create_source(char *file) {
74 FILE *fd = fopen(file, "w");
75 if (!fd) {
76 perror("fopen");
77 exit(EXIT_FAILURE);
78 }
79 fprintf(fd, "typedef int score;\n");
80 fclose(fd);
81 }
82
83 typedef void (*exec_fun)();
84
wait_for(pid_t child)85 void wait_for(pid_t child) {
86 int status;
87 if (-1 == waitpid(child, &status, 0)) {
88 perror("wait");
89 exit(EXIT_FAILURE);
90 }
91 if (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE) {
92 fprintf(stderr, "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
call_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
call_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
call_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
call_execvP()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
call_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
call_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
call_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
call_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
call_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
call_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
call_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
main(int argc,char * const argv[])266 int main(int argc, char *const argv[]) {
267 if (argc != 2)
268 exit(EXIT_FAILURE);
269
270 expected_out_open(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