1 /* SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2021 Julien Rische <jrische@laposte.net>.
4 * Copyright (C) 2018-2021 Jason A. Donenfeld <Jason@zx2c4.com>.
13 #include <sys/types.h>
19 typedef const char *err_t
;
21 const char *header
= "#include <stddef.h>\n"
22 "#include <stdint.h>\n"
23 "#include <inttypes.h>\n"
24 "#include <stdbool.h>\n"
25 "#include <string.h>\n"
26 "#include <assert.h>\n"
27 "#include <errno.h>\n"
28 "#include <unistd.h>\n"
29 "#include <pthread.h>\n"
30 "#include <limits.h>\n"
32 "#include <fcntl.h>\n"
33 "#include <stdio.h>\n"
34 "#include <stdlib.h>\n"
35 "int main(int argc, char *argv[], char *envp[]) {\n"
40 void exec_cc(int pipe
, char *output_path
, size_t argc
, char *argv
[])
44 char *cc
= getenv("CC") ?: "gcc";
46 if (dup2(pipe
, 0) < 0) {
47 perror("Error: unable to duplicate pipe fd");
52 cc_argv
= malloc(cc_argc
* sizeof(*cc_argv
));
54 perror("Error: cannot allocation compiler argument list");
58 memcpy(cc_argv
, (char *[]){cc
, "-xc", "-o", output_path
}, 4 * sizeof(char *));
59 memcpy(cc_argv
+ 4, argv
, argc
* sizeof(*argv
));
60 memcpy(cc_argv
+ (cc_argc
- 2), (char *[]){"-", NULL
}, 2 * sizeof(char *));
67 err_t
pipe_source(int pipe
, const char *src_path
, int input
)
74 len
= read(input
, beginning
, 2);
76 return "Error: unable to read from input file";
77 else if (len
== 2 && beginning
[0] == '#' && beginning
[1] == '!')
78 len
= write(pipe
, "//", 2);
80 len
= write(pipe
, beginning
, (size_t)len
);
82 return "Error: unable to write input preamble";
84 len
= write(pipe
, header
, strlen(header
));
86 return "Error: unable to write input header";
88 if (splice(input
, NULL
, pipe
, NULL
, 0x7fffffff, 0) < 0)
89 return "Error: unable to splice input to compiler child";
91 len
= write(pipe
, "}", 1);
93 return "Error: unable to write input footer";
100 int main(int argc
, char *argv
[], char *envp
[])
104 size_t cc_argc
= (size_t)argc
- 1;
105 char **cc_argv
, **esc_argv
= (char *[]){argv
[0], NULL
};
107 int fd
, input
= STDIN_FILENO
, pipes
[2] = {0};
109 char *arg
, *output_path
, *src_path
= NULL
;
112 for (size_t i
= 1; arg
= argv
[i
], i
< (size_t)argc
; ++i
) {
113 bool cc_param
= arg
[0] == '-';
116 if (!cc_param
|| strncmp("-", arg
, 2) == 0) {
124 input
= open(src_path
, O_RDONLY
);
126 perror("Error: unable to open input file");
132 if (pipe(pipes
) < 0) {
133 perror("Error: unable to open filter pipe");
138 fd
= memfd_create("c2run", 0);
140 perror("Error: unable to create memfd");
144 if (asprintf(&output_path
, "/proc/self/fd/%d", fd
) < 0) {
145 perror("Error: unable to allocate memory for fd string");
152 perror("Error: unable to fork for compiler");
160 exec_cc(pipes
[0], output_path
, cc_argc
, cc_argv
);
164 err
= pipe_source(pipes
[1], src_path
, input
);
173 if (waitpid(cc_pid
, &status
, 0) != cc_pid
|| (!WIFEXITED(status
) || WEXITSTATUS(status
))) {
174 fprintf(stderr
, "Error: compiler process did not complete successfully\n");
180 if (fexecve(fd
, esc_argv
, envp
) < 0) {
181 perror("Error: could not execute compiled program");