summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--run.c97
2 files changed, 93 insertions, 6 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5a20cd6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+run.so: run.c
+ cc -std=c99 -Wall -fPIC -I/usr/include/lua5.3 run.c -o run.so -shared
diff --git a/run.c b/run.c
index ff2565c..27ea514 100644
--- a/run.c
+++ b/run.c
@@ -5,6 +5,7 @@
#include <fcntl.h>
#include <string.h>
#include <lua.h>
+#include <lauxlib.h>
#define CKE(val, name) do { if (val == -1) { perror(name); exit(1); } } while (0)
@@ -63,14 +64,14 @@ void empipe(int pipefd[2]) {
fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
}
-void run(int count, char **progs[], char *inputstr, size_t inputlen) {
+char *run(int count, char **progs[], size_t inputlen, char *inputstr, size_t *outlen) {
if (inputstr) count++;
- int (*pipefds)[2] = malloc((count-1) * sizeof(int[2]));
+ int (*pipefds)[2] = malloc(count * 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++) 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];
+ int input = (i == 0) ? -1 : pipefds[i-1][0];
+ int output = 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);
@@ -84,6 +85,25 @@ void run(int count, char **progs[], char *inputstr, size_t inputlen) {
CKE(close(pipefds[i][0]), "close");
CKE(close(pipefds[i][1]), "close");
}
+ CKE(close(pipefds[count-1][1]), "close");
+
+ // if the program produces too much data, you will be killed
+ size_t readed = 0;
+ size_t cap = 1024*1024;
+ char *buf = malloc(cap*sizeof(char));
+ size_t remaining = cap;
+ size_t amt = 0;
+ do {
+ amt = read(pipefds[count-1][0], buf+readed, remaining);
+ readed += amt;
+ remaining -= amt;
+ if (remaining == 0) {
+ buf = realloc(buf, cap + cap);
+ remaining += cap;
+ cap += cap;
+ }
+ } while (amt != 0);
+ CKE(close(pipefds[count-1][0]), "close");
for (int i = 0; i < count; i++) {
int status;
@@ -93,9 +113,74 @@ void run(int count, char **progs[], char *inputstr, size_t inputlen) {
free(pipefds);
free(pids);
+
+ *outlen = readed;
+ return buf;
+}
+
+#define FAIL(msg) do { luaL_where(L, 1); lua_pushliteral(L, msg); lua_concat(L, 2); fail = 1; goto finish; } while (0)
+int do_the_thing(lua_State *L) {
+ int fail = 0;
+ char ***argvs = NULL;
+ char *outbuf = NULL;
+ size_t nprogs = 0;
+ if (lua_gettop(L) != 1) FAIL("run wants exactly one argument");
+ if (lua_type(L, 1) != LUA_TTABLE) FAIL("run needs table argumnt");
+ nprogs = lua_rawlen(L, 1);
+ if (nprogs == 0) FAIL("need at least one program to run");
+ argvs = calloc(nprogs, sizeof(char**));
+ for (int i = 0; i < nprogs; i++) {
+ int ty = lua_rawgeti(L, 1, i + 1);
+ if (ty != LUA_TTABLE) FAIL("program arglist must be table");
+ size_t argc = lua_rawlen(L, 2);
+ if (argc == 0) FAIL("need at least one argument to program");
+ argvs[i] = calloc(argc + 1, sizeof(char*));
+ for (int j = 0; j < argc; j++) {
+ int ty = lua_rawgeti(L, 2, j + 1);
+ if (ty != LUA_TSTRING) FAIL("program argument must be string");
+ size_t slen = 0; char *str = lua_tolstring(L, 3, &slen);
+ argvs[i][j] = calloc(slen + 1, sizeof(char));
+ memcpy(argvs[i][j], str, slen);
+ argvs[i][j][slen] = '\0'; // just to make sure
+ lua_pop(L, 1);
+ }
+ argvs[i][argc] = NULL; // just to make sure
+ lua_pop(L, 1);
+ }
+
+ char *inputstr = NULL; size_t inputlen = 0;
+ lua_pushliteral(L, "input");
+ int ty = lua_rawget(L, 1);
+ switch (ty) {
+ case LUA_TNIL: break;
+ case LUA_TSTRING:
+ inputstr = lua_tolstring(L, 2, &inputlen);
+ break;
+ default: FAIL("input field must be string if present");
+ }
+
+ size_t outlen;
+ outbuf = run(nprogs, argvs, inputlen, inputstr, &outlen);
+ lua_pushlstring(L, outbuf, outlen);
+
+finish:
+ if (argvs != NULL) {
+ for (int i = 0; i < nprogs; i++) {
+ if (argvs[i] != NULL) {
+ for (int j = 0; argvs[i][j] != NULL; j++) {
+ free(argvs[i][j]);
+ }
+ free(argvs[i]);
+ }
+ }
+ free(argvs);
+ }
+ free(outbuf);
+ if (fail) return lua_error(L);
+ return 1;
}
int luaopen_run(lua_State *L) {
- lua_pushliteral(L, "fuck");
+ lua_pushcfunction(L, &do_the_thing);
return 1;
}