summaryrefslogtreecommitdiff
path: root/run.c
blob: ff2565cca530382cd348006279f6f1531d20863d (plain)
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;
}