1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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;
}
|