commit
1e4f59c557
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#define API_TYPE_FONT "Font"
|
#define API_TYPE_FONT "Font"
|
||||||
#define API_TYPE_REPLACE "Replace"
|
#define API_TYPE_REPLACE "Replace"
|
||||||
|
#define API_TYPE_PROCESS "Process"
|
||||||
|
|
||||||
void api_load_libs(lua_State *L);
|
void api_load_libs(lua_State *L);
|
||||||
|
|
||||||
|
|
|
@ -5,33 +5,171 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lua.h>
|
|
||||||
#include <lualib.h>
|
|
||||||
#include <lauxlib.h>
|
|
||||||
#include <reproc/reproc.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <reproc/reproc.h>
|
||||||
|
#include "api.h"
|
||||||
|
|
||||||
|
#define READ_BUF_SIZE 2048
|
||||||
|
|
||||||
|
#define L_GETTABLE(L, idx, key, conv, def) ( \
|
||||||
|
lua_getfield(L, idx, key), \
|
||||||
|
conv(L, -1, def) \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define L_GETNUM(L, idx, key, def) L_GETTABLE(L, idx, key, luaL_optnumber, def)
|
||||||
|
#define L_GETSTR(L, idx, key, def) L_GETTABLE(L, idx, key, luaL_optstring, def)
|
||||||
|
|
||||||
|
#define L_SETNUM(L, idx, key, n) (lua_pushnumber(L, n), lua_setfield(L, idx - 1, key))
|
||||||
|
|
||||||
|
#define L_RETURN_REPROC_ERROR(L, code) { \
|
||||||
|
lua_pushnil(L); \
|
||||||
|
lua_pushstring(L, reproc_strerror(code)); \
|
||||||
|
lua_pushnumber(L, code); \
|
||||||
|
return 3; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ASSERT_MALLOC(ptr) \
|
||||||
|
if (ptr == NULL) \
|
||||||
|
L_RETURN_REPROC_ERROR(L, REPROC_ENOMEM)
|
||||||
|
|
||||||
|
#define ASSERT_REPROC_ERRNO(L, code) { \
|
||||||
|
if (code < 0) \
|
||||||
|
L_RETURN_REPROC_ERROR(L, code) \
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
reproc_t * process;
|
reproc_t * process;
|
||||||
lua_State* L;
|
bool running;
|
||||||
|
int returncode;
|
||||||
} process_t;
|
} process_t;
|
||||||
|
|
||||||
static int process_new(lua_State* L)
|
// this function should be called instead of reproc_wait
|
||||||
|
static int poll_process(process_t* proc, int timeout)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_newuserdata(
|
int ret = reproc_wait(proc->process, timeout);
|
||||||
L, sizeof(process_t)
|
if (ret != REPROC_ETIMEDOUT) {
|
||||||
|
proc->running = false;
|
||||||
|
proc->returncode = ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kill_process(process_t* proc)
|
||||||
|
{
|
||||||
|
int ret = reproc_stop(
|
||||||
|
proc->process,
|
||||||
|
(reproc_stop_actions) {
|
||||||
|
{REPROC_STOP_KILL, 0},
|
||||||
|
{REPROC_STOP_TERMINATE, 0},
|
||||||
|
{REPROC_STOP_NOOP, 0}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
memset(self, 0, sizeof(process_t));
|
if (ret != REPROC_ETIMEDOUT) {
|
||||||
|
proc->running = false;
|
||||||
|
proc->returncode = ret;
|
||||||
|
}
|
||||||
|
|
||||||
self->process = NULL;
|
return ret;
|
||||||
self->L = L;
|
}
|
||||||
|
|
||||||
luaL_getmetatable(L, "PROCESS");
|
static int process_start(lua_State* L)
|
||||||
lua_setmetatable(L, -2);
|
{
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
if (lua_isnoneornil(L, 2)) {
|
||||||
|
lua_settop(L, 1); // remove the nil if it's there
|
||||||
|
lua_newtable(L);
|
||||||
|
}
|
||||||
|
luaL_checktype(L, 2, LUA_TTABLE);
|
||||||
|
|
||||||
|
int cmd_len = lua_rawlen(L, 1);
|
||||||
|
const char** cmd = malloc(sizeof(char *) * (cmd_len + 1));
|
||||||
|
ASSERT_MALLOC(cmd);
|
||||||
|
cmd[cmd_len] = NULL;
|
||||||
|
|
||||||
|
for(int i = 0; i < cmd_len; i++) {
|
||||||
|
lua_rawgeti(L, 1, i + 1);
|
||||||
|
|
||||||
|
cmd[i] = luaL_checkstring(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int deadline = L_GETNUM(L, 2, "timeout", 0);
|
||||||
|
const char* cwd =L_GETSTR(L, 2, "cwd", NULL);
|
||||||
|
int redirect_in = L_GETNUM(L, 2, "stdin", REPROC_REDIRECT_DEFAULT);
|
||||||
|
int redirect_out = L_GETNUM(L, 2, "stdout", REPROC_REDIRECT_DEFAULT);
|
||||||
|
int redirect_err = L_GETNUM(L, 2, "stderr", REPROC_REDIRECT_DEFAULT);
|
||||||
|
lua_pop(L, 5); // remove args we just read
|
||||||
|
|
||||||
|
if (
|
||||||
|
redirect_in > REPROC_REDIRECT_STDOUT
|
||||||
|
|| redirect_out > REPROC_REDIRECT_STDOUT
|
||||||
|
|| redirect_err > REPROC_REDIRECT_STDOUT)
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushliteral(L, "redirect to handles, FILE* and paths are not supported");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// env
|
||||||
|
luaL_getsubtable(L, 2, "env");
|
||||||
|
const char **env = NULL;
|
||||||
|
int env_len = 0;
|
||||||
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2) != 0) {
|
||||||
|
env_len++;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env_len > 0) {
|
||||||
|
env = malloc(sizeof(char*) * (env_len + 1));
|
||||||
|
env[env_len] = NULL;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2) != 0) {
|
||||||
|
lua_pushliteral(L, "=");
|
||||||
|
lua_pushvalue(L, -3); // push the key to the top
|
||||||
|
lua_concat(L, 3); // key=value
|
||||||
|
|
||||||
|
env[i++] = luaL_checkstring(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reproc_t* proc = reproc_new();
|
||||||
|
int out = reproc_start(
|
||||||
|
proc,
|
||||||
|
(const char* const*) cmd,
|
||||||
|
(reproc_options) {
|
||||||
|
.working_directory = cwd,
|
||||||
|
.deadline = deadline,
|
||||||
|
.nonblocking = true,
|
||||||
|
.env = {
|
||||||
|
.behavior = REPROC_ENV_EXTEND,
|
||||||
|
.extra = env
|
||||||
|
},
|
||||||
|
.redirect = {
|
||||||
|
.in.type = redirect_in,
|
||||||
|
.out.type = redirect_out,
|
||||||
|
.err.type = redirect_err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (out < 0) {
|
||||||
|
reproc_destroy(proc);
|
||||||
|
L_RETURN_REPROC_ERROR(L, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
process_t* self = lua_newuserdata(L, sizeof(process_t));
|
||||||
|
self->process = proc;
|
||||||
|
self->running = true;
|
||||||
|
|
||||||
|
// this is equivalent to using lua_setmetatable()
|
||||||
|
luaL_setmetatable(L, API_TYPE_PROCESS);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,24 +177,20 @@ static int process_strerror(lua_State* L)
|
||||||
{
|
{
|
||||||
int error_code = luaL_checknumber(L, 1);
|
int error_code = luaL_checknumber(L, 1);
|
||||||
|
|
||||||
if(error_code){
|
if (error_code < 0)
|
||||||
lua_pushstring(
|
lua_pushstring(L, reproc_strerror(error_code));
|
||||||
L,
|
else
|
||||||
reproc_strerror(error_code)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_gc(lua_State* L)
|
static int f_gc(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) luaL_checkudata(L, 1, "PROCESS");
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process) {
|
if(self->process) {
|
||||||
reproc_kill(self->process);
|
kill_process(self);
|
||||||
reproc_destroy(self->process);
|
reproc_destroy(self->process);
|
||||||
self->process = NULL;
|
self->process = NULL;
|
||||||
}
|
}
|
||||||
|
@ -64,385 +198,211 @@ static int process_gc(lua_State* L)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_start(lua_State* L)
|
static int f_tostring(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
luaL_checktype(L, 2, LUA_TTABLE);
|
lua_pushliteral(L, API_TYPE_PROCESS);
|
||||||
|
return 1;
|
||||||
char* path = NULL;
|
|
||||||
size_t path_len = 0;
|
|
||||||
|
|
||||||
if(lua_type(L, 3) == LUA_TSTRING){
|
|
||||||
path = (char*) lua_tolstring(L, 3, &path_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t deadline = 0;
|
static int f_pid(lua_State* L)
|
||||||
|
{
|
||||||
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(lua_type(L, 4) == LUA_TNUMBER){
|
lua_pushnumber(L, reproc_pid(self->process));
|
||||||
deadline = lua_tonumber(L, 4);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t table_len = luaL_len(L, 2);
|
static int f_returncode(lua_State *L)
|
||||||
char* command[table_len+1];
|
{
|
||||||
command[table_len] = NULL;
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
int ret = poll_process(self, 0);
|
||||||
|
|
||||||
int i;
|
if (self->running)
|
||||||
for(i=1; i<=table_len; i++){
|
lua_pushnil(L);
|
||||||
lua_pushnumber(L, i);
|
else
|
||||||
lua_gettable(L, 2);
|
lua_pushnumber(L, ret);
|
||||||
|
|
||||||
command[i-1] = (char*) lua_tostring(L, -1);
|
|
||||||
|
|
||||||
lua_remove(L, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
reproc_kill(self->process);
|
|
||||||
reproc_destroy(self->process);
|
|
||||||
}
|
|
||||||
|
|
||||||
self->process = reproc_new();
|
|
||||||
|
|
||||||
int out = reproc_start(
|
|
||||||
self->process,
|
|
||||||
(const char* const*) command,
|
|
||||||
(reproc_options){
|
|
||||||
.working_directory = path,
|
|
||||||
.deadline = deadline,
|
|
||||||
.nonblocking=true,
|
|
||||||
.redirect.err.type=REPROC_REDIRECT_PIPE
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if(out > 0) {
|
|
||||||
lua_pushboolean(L, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reproc_destroy(self->process);
|
|
||||||
self->process = NULL;
|
|
||||||
lua_pushnumber(L, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_pid(lua_State* L)
|
static int g_read(lua_State* L, int stream)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
unsigned long read_size = luaL_optunsigned(L, 2, READ_BUF_SIZE);
|
||||||
|
|
||||||
if(self->process){
|
luaL_Buffer b;
|
||||||
int id = reproc_pid(self->process);
|
uint8_t* buffer = (uint8_t*) luaL_buffinitsize(L, &b, read_size);
|
||||||
|
|
||||||
if(id > 0){
|
int out = reproc_read(
|
||||||
lua_pushnumber(L, id);
|
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int process_read(lua_State* L)
|
|
||||||
{
|
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
int read_size = 4096;
|
|
||||||
if (lua_type(L, 2) == LUA_TNUMBER){
|
|
||||||
read_size = (int) lua_tonumber(L, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int tries = 1;
|
|
||||||
if (lua_type(L, 3) == LUA_TNUMBER){
|
|
||||||
tries = (int) lua_tonumber(L, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
int out = 0;
|
|
||||||
uint8_t buffer[read_size];
|
|
||||||
|
|
||||||
int runs;
|
|
||||||
for (runs=0; runs<tries; runs++){
|
|
||||||
out = reproc_read(
|
|
||||||
self->process,
|
self->process,
|
||||||
REPROC_STREAM_OUT,
|
stream,
|
||||||
buffer,
|
buffer,
|
||||||
read_size
|
read_size
|
||||||
);
|
);
|
||||||
|
|
||||||
if (out >= 0)
|
if (out >= 0)
|
||||||
break;
|
luaL_addsize(&b, out);
|
||||||
}
|
luaL_pushresult(&b);
|
||||||
|
|
||||||
// if request for tries was set and nothing
|
|
||||||
// read kill the process
|
|
||||||
if(tries > 1 && out < 0)
|
|
||||||
out = REPROC_EPIPE;
|
|
||||||
|
|
||||||
if (out == REPROC_EPIPE) {
|
if (out == REPROC_EPIPE) {
|
||||||
reproc_kill(self->process);
|
kill_process(self);
|
||||||
reproc_destroy(self->process);
|
ASSERT_REPROC_ERRNO(L, out);
|
||||||
self->process = NULL;
|
|
||||||
|
|
||||||
lua_pushnil(L);
|
|
||||||
} else if(out > 0) {
|
|
||||||
lua_pushlstring(L, (const char*) buffer, out);
|
|
||||||
} else {
|
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_read_errors(lua_State* L)
|
static int f_read_stdout(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
return g_read(L, REPROC_STREAM_OUT);
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
int read_size = 4096;
|
|
||||||
if (lua_type(L, 2) == LUA_TNUMBER){
|
|
||||||
read_size = (int) lua_tonumber(L, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int tries = 1;
|
static int f_read_stderr(lua_State* L)
|
||||||
if (lua_type(L, 3) == LUA_TNUMBER){
|
|
||||||
tries = (int) lua_tonumber(L, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
int out = 0;
|
|
||||||
uint8_t buffer[read_size];
|
|
||||||
|
|
||||||
int runs;
|
|
||||||
for (runs=0; runs<tries; runs++){
|
|
||||||
out = reproc_read(
|
|
||||||
self->process,
|
|
||||||
REPROC_STREAM_ERR,
|
|
||||||
buffer,
|
|
||||||
read_size
|
|
||||||
);
|
|
||||||
|
|
||||||
if (out >= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if request for tries was set and nothing
|
|
||||||
// read kill the process
|
|
||||||
if(tries > 1 && out < 0)
|
|
||||||
out = REPROC_EPIPE;
|
|
||||||
|
|
||||||
if(out == REPROC_EPIPE){
|
|
||||||
reproc_kill(self->process);
|
|
||||||
reproc_destroy(self->process);
|
|
||||||
self->process = NULL;
|
|
||||||
|
|
||||||
lua_pushnil(L);
|
|
||||||
} else if(out > 0) {
|
|
||||||
lua_pushlstring(L, (const char*) buffer, out);
|
|
||||||
} else {
|
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int process_write(lua_State* L)
|
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
return g_read(L, REPROC_STREAM_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int f_read(lua_State* L)
|
||||||
|
{
|
||||||
|
int stream = luaL_checknumber(L, 2);
|
||||||
|
lua_remove(L, 2);
|
||||||
|
if (stream > REPROC_STREAM_ERR)
|
||||||
|
L_RETURN_REPROC_ERROR(L, REPROC_EINVAL);
|
||||||
|
|
||||||
|
return g_read(L, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int f_write(lua_State* L)
|
||||||
|
{
|
||||||
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
size_t data_size = 0;
|
size_t data_size = 0;
|
||||||
const char* data = luaL_checklstring(L, 2, &data_size);
|
const char* data = luaL_checklstring(L, 2, &data_size);
|
||||||
|
|
||||||
int out = 0;
|
int out = reproc_write(
|
||||||
|
|
||||||
out = reproc_write(
|
|
||||||
self->process,
|
self->process,
|
||||||
(uint8_t*) data,
|
(uint8_t*) data,
|
||||||
data_size
|
data_size
|
||||||
);
|
);
|
||||||
|
|
||||||
if (out == REPROC_EPIPE) {
|
if (out == REPROC_EPIPE) {
|
||||||
reproc_kill(self->process);
|
kill_process(self);
|
||||||
reproc_destroy(self->process);
|
L_RETURN_REPROC_ERROR(L, out);
|
||||||
self->process = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pushnumber(L, out);
|
lua_pushnumber(L, out);
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, REPROC_EPIPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_close_stream(lua_State* L)
|
static int f_close_stream(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
size_t stream = luaL_checknumber(L, 2);
|
|
||||||
|
|
||||||
|
int stream = luaL_checknumber(L, 2);
|
||||||
int out = reproc_close(self->process, stream);
|
int out = reproc_close(self->process, stream);
|
||||||
|
ASSERT_REPROC_ERRNO(L, out);
|
||||||
|
|
||||||
lua_pushnumber(L, out);
|
lua_pushboolean(L, 1);
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, REPROC_EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_wait(lua_State* L)
|
static int f_wait(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process){
|
int timeout = luaL_optnumber(L, 2, 0);
|
||||||
size_t timeout = luaL_checknumber(L, 2);
|
|
||||||
|
|
||||||
int out = reproc_wait(self->process, timeout);
|
int ret = poll_process(self, timeout);
|
||||||
|
// negative returncode is also used for signals on POSIX
|
||||||
if(out >= 0){
|
if (ret == REPROC_ETIMEDOUT)
|
||||||
reproc_destroy(self->process);
|
L_RETURN_REPROC_ERROR(L, ret);
|
||||||
self->process = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_pushnumber(L, out);
|
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, REPROC_EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
lua_pushnumber(L, ret);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_terminate(lua_State* L)
|
static int f_terminate(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
int out = reproc_terminate(self->process);
|
int out = reproc_terminate(self->process);
|
||||||
|
ASSERT_REPROC_ERRNO(L, out);
|
||||||
|
|
||||||
if(out < 0){
|
poll_process(self, 0);
|
||||||
lua_pushnumber(L, out);
|
|
||||||
} else {
|
|
||||||
reproc_destroy(self->process);
|
|
||||||
self->process = NULL;
|
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, REPROC_EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_kill(lua_State* L)
|
static int f_kill(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process){
|
|
||||||
int out = reproc_kill(self->process);
|
int out = reproc_kill(self->process);
|
||||||
|
ASSERT_REPROC_ERRNO(L, out);
|
||||||
|
|
||||||
if(out < 0){
|
poll_process(self, 0);
|
||||||
lua_pushnumber(L, out);
|
|
||||||
} else {
|
|
||||||
reproc_destroy(self->process);
|
|
||||||
self->process = NULL;
|
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pushnumber(L, REPROC_EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_running(lua_State* L)
|
static int f_running(lua_State* L)
|
||||||
{
|
{
|
||||||
process_t* self = (process_t*) lua_touserdata(L, 1);
|
process_t* self = (process_t*) luaL_checkudata(L, 1, API_TYPE_PROCESS);
|
||||||
|
|
||||||
if(self->process){
|
poll_process(self, 0);
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, self->running);
|
||||||
} else {
|
|
||||||
lua_pushboolean(L, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct luaL_Reg process_methods[] = {
|
static const struct luaL_Reg lib[] = {
|
||||||
{ "__gc", process_gc},
|
|
||||||
{"start", process_start},
|
{"start", process_start},
|
||||||
{"pid", process_pid},
|
|
||||||
{"read", process_read},
|
|
||||||
{"read_errors", process_read_errors},
|
|
||||||
{"write", process_write},
|
|
||||||
{"close_stream", process_close_stream},
|
|
||||||
{"wait", process_wait},
|
|
||||||
{"terminate", process_terminate},
|
|
||||||
{"kill", process_kill},
|
|
||||||
{"running", process_running},
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct luaL_Reg process[] = {
|
|
||||||
{"new", process_new},
|
|
||||||
{"strerror", process_strerror},
|
{"strerror", process_strerror},
|
||||||
{"ERROR_PIPE", NULL},
|
{"__gc", f_gc},
|
||||||
{"ERROR_WOULDBLOCK", NULL},
|
{"__tostring", f_tostring},
|
||||||
{"ERROR_TIMEDOUT", NULL},
|
{"pid", f_pid},
|
||||||
{"ERROR_INVALID", NULL},
|
{"returncode", f_returncode},
|
||||||
{"STREAM_STDIN", NULL},
|
{"read", f_read},
|
||||||
{"STREAM_STDOUT", NULL},
|
{"read_stdout", f_read_stdout},
|
||||||
{"STREAM_STDERR", NULL},
|
{"read_stderr", f_read_stderr},
|
||||||
{"WAIT_INFINITE", NULL},
|
{"write", f_write},
|
||||||
{"WAIT_DEADLINE", NULL},
|
{"close_stream", f_close_stream},
|
||||||
|
{"wait", f_wait},
|
||||||
|
{"terminate", f_terminate},
|
||||||
|
{"kill", f_kill},
|
||||||
|
{"running", f_running},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
int luaopen_process(lua_State *L)
|
int luaopen_process(lua_State *L)
|
||||||
{
|
{
|
||||||
luaL_newmetatable(L, "PROCESS");
|
luaL_newmetatable(L, API_TYPE_PROCESS);
|
||||||
luaL_setfuncs(L, process_methods, 0);
|
luaL_setfuncs(L, lib, 0);
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
lua_setfield(L, -2, "__index");
|
lua_setfield(L, -2, "__index");
|
||||||
|
|
||||||
luaL_newlib(L, process);
|
// constants
|
||||||
|
L_SETNUM(L, -1, "ERROR_INVAL", REPROC_EINVAL);
|
||||||
|
L_SETNUM(L, -1, "ERROR_TIMEDOUT", REPROC_ETIMEDOUT);
|
||||||
|
L_SETNUM(L, -1, "ERROR_PIPE", REPROC_EPIPE);
|
||||||
|
L_SETNUM(L, -1, "ERROR_NOMEM", REPROC_ENOMEM);
|
||||||
|
L_SETNUM(L, -1, "ERROR_WOULDBLOCK", REPROC_EWOULDBLOCK);
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_EPIPE);
|
L_SETNUM(L, -1, "WAIT_INFINITE", REPROC_INFINITE);
|
||||||
lua_setfield(L, -2, "ERROR_PIPE");
|
L_SETNUM(L, -1, "WAIT_DEADLINE", REPROC_DEADLINE);
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_EWOULDBLOCK);
|
L_SETNUM(L, -1, "STREAM_STDIN", REPROC_STREAM_IN);
|
||||||
lua_setfield(L, -2, "ERROR_WOULDBLOCK");
|
L_SETNUM(L, -1, "STREAM_STDOUT", REPROC_STREAM_OUT);
|
||||||
|
L_SETNUM(L, -1, "STREAM_STDERR", REPROC_STREAM_ERR);
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_ETIMEDOUT);
|
L_SETNUM(L, -1, "REDIRECT_DEFAULT", REPROC_REDIRECT_DEFAULT);
|
||||||
lua_setfield(L, -2, "ERROR_TIMEDOUT");
|
L_SETNUM(L, -1, "REDIRECT_PIPE", REPROC_REDIRECT_PIPE);
|
||||||
|
L_SETNUM(L, -1, "REDIRECT_PARENT", REPROC_REDIRECT_PARENT);
|
||||||
lua_pushnumber(L, REPROC_EINVAL);
|
L_SETNUM(L, -1, "REDIRECT_DISCARD", REPROC_REDIRECT_DISCARD);
|
||||||
lua_setfield(L, -2, "ERROR_INVALID");
|
L_SETNUM(L, -1, "REDIRECT_STDOUT", REPROC_REDIRECT_STDOUT);
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_STREAM_IN);
|
|
||||||
lua_setfield(L, -2, "STREAM_STDIN");
|
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_STREAM_OUT);
|
|
||||||
lua_setfield(L, -2, "STREAM_STDOUT");
|
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_STREAM_ERR);
|
|
||||||
lua_setfield(L, -2, "STREAM_STDERR");
|
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_INFINITE);
|
|
||||||
lua_setfield(L, -2, "WAIT_INFINITE");
|
|
||||||
|
|
||||||
lua_pushnumber(L, REPROC_DEADLINE);
|
|
||||||
lua_setfield(L, -2, "WAIT_DEADLINE");
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue