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, 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
51void 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
60void 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
73void 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
83typedef void (*exec_fun)();
84
85void 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
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(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

source code of clang/tools/scan-build-py/tests/functional/exec/main.c