Initial commit
[c2run.git] / cscript.c
blobc7dbcf58d93f0e2fad72a0288671ee40ab6feca8
1 /* SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4 */
6 #define _GNU_SOURCE
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <fcntl.h>
17 int main(int argc, char *argv[], char *envp[])
19 int fd, fd2, input = -1, pipes[2] = { 0 }, status;
20 pid_t compiler_pid;
21 char *output_path;
23 if (argc > 1 && argv[argc - 1][0] != '-') {
24 input = open(argv[1], O_RDONLY);
25 ++argv;
26 --argc;
27 if (input < 0) {
28 perror("Error: unable to open input file");
29 return 1;
31 if (pipe(pipes) < 0) {
32 perror("Error: unable to open filter pipe");
33 return 1;
37 fd = open(getenv("HOME") ?: getenv("TMPDIR") ?: "/tmp", O_TMPFILE | O_EXCL | O_RDWR, S_IWUSR | S_IRUSR);
38 if (fd < 0) {
39 perror("Error: unable to create temporary inode");
40 return 1;
42 if (asprintf(&output_path, "/proc/self/fd/%d", fd) < 0) {
43 perror("Error: unable to allocate memory for fd string");
44 return 1;
47 compiler_pid = fork();
48 if (compiler_pid < 0) {
49 perror("Error: unable to fork for compiler");
50 return 1;
53 if (compiler_pid == 0) {
54 const char *cc = getenv("CC") ?: "gcc";
55 close(input);
56 if (pipes[0] != 0) {
57 close(pipes[1]);
58 if (dup2(pipes[0], 0) < 0) {
59 perror("Error: unable to duplicate pipe fd");
60 _exit(1);
62 close(pipes[0]);
64 execlp(cc, cc, "-xc", "-o", output_path, "-", NULL);
65 _exit(1);
68 if (input != -1) {
69 char beginning[2];
70 ssize_t len;
72 close(pipes[0]);
73 len = read(input, beginning, 2);
74 if (len < 0) {
75 perror("Error: unable to read from input file");
76 return 1;
77 } else if (len == 2 && beginning[0] == '#' && beginning[1] == '!')
78 len = write(pipes[1], "//", 2);
79 else if (len > 0)
80 len = write(pipes[1], beginning, len);
81 if (len < 0) {
82 perror("Error: unable to write input preamble");
83 return 1;
85 if (splice(input, NULL, pipes[1], NULL, 0x7fffffff, 0) < 0) {
86 perror("Error: unable to splice input to compiler child");
87 return 1;
89 close(pipes[1]);
92 if (waitpid(compiler_pid, &status, 0) != compiler_pid || (!WIFEXITED(status) || WEXITSTATUS(status))) {
93 fprintf(stderr, "Error: compiler process did not complete successfully\n");
94 return 1;
97 fd2 = open(output_path, O_RDONLY);
98 if (fd2 < 0) {
99 perror("Error: unable to reopen temporary inode");
100 return 1;
102 close(fd);
104 if (fexecve(fd2, argv, envp) < 0) {
105 perror("Error: could not execute compiled program");
106 return 1;
108 return 0;