summaryrefslogtreecommitdiff
path: root/run.c
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2024-11-26 14:02:24 +0000
committerubq323 <ubq323@ubq323.website>2024-11-26 14:02:24 +0000
commit195d1526cc67f7b7d20dd3fe32b97840a4193223 (patch)
tree76fa7bcd4da855248a8150a16a75131623490bca /run.c
ok
Diffstat (limited to 'run.c')
-rw-r--r--run.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/run.c b/run.c
new file mode 100644
index 0000000..ff2565c
--- /dev/null
+++ b/run.c
@@ -0,0 +1,101 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <string.h>
+#include <lua.h>
+
+#define CKE(val, name) do { if (val == -1) { perror(name); exit(1); } } while (0)
+
+#ifdef DEBUG
+#define DP(...) fprintf(stderr, __VA_ARGS__);
+#else
+#define DP(...)
+#endif
+
+int filefork(char *argv[], int input, int output) {
+ int pid = fork();
+ switch (pid) {
+ case -1: perror("fork"); exit(1); break;
+ case 0:
+ if (input != -1) {
+ CKE(close(STDIN_FILENO),"close stdin");
+ CKE(dup2(input, STDIN_FILENO),"dup2 stdin");
+ }
+ if (output != -1) {
+ CKE(close(STDOUT_FILENO),"close stdout");
+ CKE(dup2(output, STDOUT_FILENO),"dup2 stdout");
+ }
+ CKE(execvp(argv[0], argv), "exec");
+ exit(1);
+ break;
+ default: return pid;
+ }
+}
+
+int echofork(char *str, size_t len, int fd) {
+ int pid = fork();
+ switch (pid) {
+ case -1: perror("fork"), exit(1); break;
+ case 0:
+ size_t remaining = len;
+ char *cur = str;
+ do {
+ ssize_t res = write(fd, cur, remaining);
+ if (res == -1) { perror("write"); exit(1); }
+ cur += res;
+ remaining -= res;
+ } while (remaining > 0);
+ exit(0);
+ default: return pid;
+ }
+}
+
+char *p1[] = {"sed","-e","s/a/b/g",NULL};
+char *p2[] = {"tac",NULL};
+char *p3[] = {"sed","-e","s/fish/PIG/",NULL};
+char *p4[] = {"rev",NULL};
+
+void empipe(int pipefd[2]) {
+ CKE(pipe(pipefd), "pipe");
+ fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
+ fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
+}
+
+void run(int count, char **progs[], char *inputstr, size_t inputlen) {
+ if (inputstr) count++;
+ int (*pipefds)[2] = malloc((count-1) * sizeof(int[2]));
+ pid_t *pids = malloc(count * sizeof(pid_t));
+ for (int i = 0; i < count-1; i++) empipe(pipefds[i]);
+ for (int i = 0; i < count; i++) {
+ int input = (i == 0) ? -1 : pipefds[i-1][0];
+ int output = (i == count-1) ? -1 : pipefds[i ][1];
+ if (!inputstr) pids[i] = filefork(progs[i ], input, output);
+ else if (i==0) pids[i] = echofork(inputstr, inputlen, output);
+ else pids[i] = filefork(progs[i-1], input, output);
+
+ DP("[%d] %d\n",i,pids[i]);
+ }
+ // pipes need to be closed everywhere they aren't being used.
+ // close them in the parent process here; CLOEXEC will take care of them everwhere else
+ // (duped fds won't have CLOEXEC set so those ones, ie the ones being used, won't be closed)
+ for (int i = 0; i < count-1; i++) {
+ CKE(close(pipefds[i][0]), "close");
+ CKE(close(pipefds[i][1]), "close");
+ }
+
+ for (int i = 0; i < count; i++) {
+ int status;
+ pid_t rpid = waitpid(pids[i], &status, 0);
+ DP("-> %d %d\n",rpid,WEXITSTATUS(status));
+ }
+
+ free(pipefds);
+ free(pids);
+}
+
+int luaopen_run(lua_State *L) {
+ lua_pushliteral(L, "fuck");
+ return 1;
+}