main.c revision 1.1.1.1
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
23extern char **environ;
24#endif
25
26char **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 ::..
36static char const *cwd = NULL;
37static FILE *fd = NULL;
38static int need_comma = 0;
39
40void 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
51void expected_out_close() {
52    fprintf(fd, "]\n");
53    fclose(fd);
54    fd = NULL;
55
56    free((void *)cwd);
57    cwd = NULL;
58}
59
60void 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
73void 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
83typedef void (*exec_fun)();
84
85void 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
113void 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
126void 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
140void 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
153void 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
166void 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
180void 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
194void 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
206void 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
218void 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
231void 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
249void 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
266int 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