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