diff options
author | ubq323 <ubq323@ubq323.website> | 2024-11-26 14:02:24 +0000 |
---|---|---|
committer | ubq323 <ubq323@ubq323.website> | 2024-11-26 14:02:24 +0000 |
commit | 195d1526cc67f7b7d20dd3fe32b97840a4193223 (patch) | |
tree | 76fa7bcd4da855248a8150a16a75131623490bca |
ok
-rw-r--r-- | run.c | 101 |
1 files changed, 101 insertions, 0 deletions
@@ -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; +} |