aboutsummaryrefslogtreecommitdiffstats
path: root/cscript.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2018-06-29 20:19:59 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2018-07-05 01:24:35 +0200
commit7b969e846ad2e5d50b1095255c705c69ad2f84f6 (patch)
tree2eade7379678ee7da3d2a5d82802724745c952c4 /cscript.c
downloadcscript-7b969e846ad2e5d50b1095255c705c69ad2f84f6.tar.xz
cscript-7b969e846ad2e5d50b1095255c705c69ad2f84f6.zip
Initial commit
Diffstat (limited to 'cscript.c')
-rw-r--r--cscript.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/cscript.c b/cscript.c
new file mode 100644
index 0000000..c7dbcf5
--- /dev/null
+++ b/cscript.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+
+int main(int argc, char *argv[], char *envp[])
+{
+ int fd, fd2, input = -1, pipes[2] = { 0 }, status;
+ pid_t compiler_pid;
+ char *output_path;
+
+ if (argc > 1 && argv[argc - 1][0] != '-') {
+ input = open(argv[1], O_RDONLY);
+ ++argv;
+ --argc;
+ if (input < 0) {
+ perror("Error: unable to open input file");
+ return 1;
+ }
+ if (pipe(pipes) < 0) {
+ perror("Error: unable to open filter pipe");
+ return 1;
+ }
+ }
+
+ fd = open(getenv("HOME") ?: getenv("TMPDIR") ?: "/tmp", O_TMPFILE | O_EXCL | O_RDWR, S_IWUSR | S_IRUSR);
+ if (fd < 0) {
+ perror("Error: unable to create temporary inode");
+ return 1;
+ }
+ if (asprintf(&output_path, "/proc/self/fd/%d", fd) < 0) {
+ perror("Error: unable to allocate memory for fd string");
+ return 1;
+ }
+
+ compiler_pid = fork();
+ if (compiler_pid < 0) {
+ perror("Error: unable to fork for compiler");
+ return 1;
+ }
+
+ if (compiler_pid == 0) {
+ const char *cc = getenv("CC") ?: "gcc";
+ close(input);
+ if (pipes[0] != 0) {
+ close(pipes[1]);
+ if (dup2(pipes[0], 0) < 0) {
+ perror("Error: unable to duplicate pipe fd");
+ _exit(1);
+ }
+ close(pipes[0]);
+ }
+ execlp(cc, cc, "-xc", "-o", output_path, "-", NULL);
+ _exit(1);
+ }
+
+ if (input != -1) {
+ char beginning[2];
+ ssize_t len;
+
+ close(pipes[0]);
+ len = read(input, beginning, 2);
+ if (len < 0) {
+ perror("Error: unable to read from input file");
+ return 1;
+ } else if (len == 2 && beginning[0] == '#' && beginning[1] == '!')
+ len = write(pipes[1], "//", 2);
+ else if (len > 0)
+ len = write(pipes[1], beginning, len);
+ if (len < 0) {
+ perror("Error: unable to write input preamble");
+ return 1;
+ }
+ if (splice(input, NULL, pipes[1], NULL, 0x7fffffff, 0) < 0) {
+ perror("Error: unable to splice input to compiler child");
+ return 1;
+ }
+ close(pipes[1]);
+ }
+
+ if (waitpid(compiler_pid, &status, 0) != compiler_pid || (!WIFEXITED(status) || WEXITSTATUS(status))) {
+ fprintf(stderr, "Error: compiler process did not complete successfully\n");
+ return 1;
+ }
+
+ fd2 = open(output_path, O_RDONLY);
+ if (fd2 < 0) {
+ perror("Error: unable to reopen temporary inode");
+ return 1;
+ }
+ close(fd);
+
+ if (fexecve(fd2, argv, envp) < 0) {
+ perror("Error: could not execute compiled program");
+ return 1;
+ }
+ return 0;
+}