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, 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 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 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 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 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 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(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