Moved spawn_* functions out of ex.c
parent
ecb5e17609
commit
36cb453953
@ -1,13 +1,19 @@
|
|||||||
CFLAGS = -std=c99 $(WARNINGS) $(DEFINES) $(INCLUDES)
|
CFLAGS = -std=c99 $(WARNINGS) $(DEFINES) $(INCLUDES)
|
||||||
DEFINES = -D_POSIX_SOURCE -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L -U__STRICT_ANSI__
|
DEFINES = -D_POSIX_SOURCE -D_XOPEN_SOURCE=600 -D_POSIX_C_SOURCE=200112L -U__STRICT_ANSI__ -DMISSING_POSIX_SPAWN
|
||||||
INCLUDES = -I$(LUA)/include -I.
|
INCLUDES = -I$(LUA)/include
|
||||||
WARNINGS = -W -Wall
|
WARNINGS = -W -Wall
|
||||||
#LUA = /home/mark/src/lang/lua/lua-5.1-rc2
|
#LUA = /home/mark/src/lang/lua/lua-5.1-rc2
|
||||||
LUA = /home/mark/src/lang/lua/lua51
|
LUA = /home/mark/src/lang/lua/lua51
|
||||||
|
|
||||||
ex.so: ex.o; $(CC) -shared -o $@ ex.o
|
ex-OBJS = ex.o spawn.o
|
||||||
|
|
||||||
|
ex.so: $(ex-OBJS); $(CC) -shared -o $@ $(ex-OBJS)
|
||||||
|
|
||||||
#LIBS = -L$(LUA)/lib -llua51 spawn.a
|
#LIBS = -L$(LUA)/lib -llua51 spawn.a
|
||||||
ex.dll: ex.o $(LIBS); $(CC) -shared -L$(LUA)/bin/Cygwin -o $@ ex.o spawn.o -llua51
|
EXTRA = posix_spawn.o
|
||||||
|
ex.dll: $(ex-OBJS) $(LIBS); $(CC) -shared -L$(LUA)/bin/Cygwin -o $@ $(ex-OBJS) $(EXTRA) -llua51
|
||||||
|
|
||||||
|
ex.o: ex.c spawn.h
|
||||||
spawn.o: spawn.c spawn.h
|
spawn.o: spawn.c spawn.h
|
||||||
|
|
||||||
|
posix_spawn.o: posix_spawn.c posix_spawn.h
|
||||||
|
|||||||
@ -0,0 +1,135 @@
|
|||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "spawn.h"
|
||||||
|
|
||||||
|
extern int push_error(lua_State *L);
|
||||||
|
extern void *checkuserdata(lua_State *L, int index, const char *name);
|
||||||
|
|
||||||
|
/* filename ... */
|
||||||
|
void spawn_param_filename(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
/* XXX confusing */
|
||||||
|
p->command = luaL_checkstring(p->L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
void spawn_param_defaults(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
p->argv = lua_newuserdata(p->L, 2 * sizeof *p->argv);
|
||||||
|
p->argv[0] = p->command;
|
||||||
|
p->argv[1] = 0;
|
||||||
|
p->envp = (const char **)environ;
|
||||||
|
p->has_actions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts a Lua array of strings to a null-terminated array of char pointers.
|
||||||
|
* Pops a (0-based) Lua array and replaces it with a userdatum which is the
|
||||||
|
* null-terminated C array of char pointers. The elements of this array point
|
||||||
|
* to the strings in the Lua array. These strings should be associated with
|
||||||
|
* this userdatum via a weak table for GC purposes, but they are not here.
|
||||||
|
* Therefore, any function which calls this must make sure that these strings
|
||||||
|
* remain available until the userdatum is thrown away.
|
||||||
|
*/
|
||||||
|
/* ... array -- ... vector */
|
||||||
|
static const char **make_vector(lua_State *L)
|
||||||
|
{
|
||||||
|
size_t i, n = lua_objlen(L, -1);
|
||||||
|
const char **vec = lua_newuserdata(L, (n + 2) * sizeof *vec);
|
||||||
|
/* ... arr vec */
|
||||||
|
for (i = 0; i <= n; i++) {
|
||||||
|
lua_rawgeti(L, -2, i); /* ... arr vec elem */
|
||||||
|
vec[i] = lua_tostring(L, -1);
|
||||||
|
lua_pop(L, 1); /* ... arr vec */
|
||||||
|
}
|
||||||
|
vec[n + 1] = 0;
|
||||||
|
lua_replace(L, -2); /* ... vector */
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... argtab */
|
||||||
|
void spawn_param_args(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
const char **argv = make_vector(p->L);
|
||||||
|
if (!argv[0]) argv[0] = p->command;
|
||||||
|
p->argv = argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... envtab/nil */
|
||||||
|
void spawn_param_env(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
luaL_Buffer estr;
|
||||||
|
if (lua_isnil(p->L, -1)) {
|
||||||
|
p->envp = (const char **)environ;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
luaL_buffinit(p->L, &estr);
|
||||||
|
lua_newtable(p->L); /* ... envtab arr */
|
||||||
|
lua_pushnil(p->L); /* ... envtab arr nil */
|
||||||
|
for (i = 0; lua_next(p->L, -3); i++) { /* ... envtab arr k v */
|
||||||
|
luaL_prepbuffer(&estr);
|
||||||
|
lua_pushvalue(p->L, -2); /* ... envtab arr k v k */
|
||||||
|
luaL_addvalue(&estr);
|
||||||
|
luaL_putchar(&estr, '=');
|
||||||
|
lua_pop(p->L, 1); /* ... envtab arr k v */
|
||||||
|
luaL_addvalue(&estr);
|
||||||
|
lua_pop(p->L, 1); /* ... envtab arr k */
|
||||||
|
luaL_pushresult(&estr); /* ... envtab arr k estr */
|
||||||
|
lua_rawseti(p->L, -3, i); /* ... envtab arr[n]=estr k */
|
||||||
|
} /* ... envtab arr */
|
||||||
|
lua_replace(p->L, -2); /* ... arr */
|
||||||
|
make_vector(p->L); /* ... arr */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _ opts ... */
|
||||||
|
static int get_redirect(struct spawn_params *p, const char *stdname, int descriptor)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
lua_getfield(p->L, 2, stdname);
|
||||||
|
if ((ret = !lua_isnil(p->L, -1)))
|
||||||
|
/* XXX checkuserdata is confusing here */
|
||||||
|
posix_spawn_file_actions_adddup2(&p->file_actions,
|
||||||
|
fileno(checkuserdata(p->L, -1, LUA_FILEHANDLE)), descriptor);
|
||||||
|
lua_pop(p->L, 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _ opts ... */
|
||||||
|
void spawn_param_redirects(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
posix_spawn_file_actions_init(&p->file_actions);
|
||||||
|
p->has_actions = 1;
|
||||||
|
get_redirect(p, "stdin", STDIN_FILENO);
|
||||||
|
get_redirect(p, "stdout", STDOUT_FILENO);
|
||||||
|
get_redirect(p, "stderr", STDERR_FILENO);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawn_param_execute(struct spawn_params *p, struct process *proc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
proc->status = -1;
|
||||||
|
ret = posix_spawnp(&proc->pid, p->command, &p->file_actions, 0, (char *const *)p->argv, (char *const *)p->envp);
|
||||||
|
if (p->has_actions)
|
||||||
|
posix_spawn_file_actions_destroy(&p->file_actions);
|
||||||
|
return ret == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* proc -- exitcode/nil error */
|
||||||
|
int process_wait(lua_State *L)
|
||||||
|
{
|
||||||
|
struct process *p = checkuserdata(L, 1, PROCESS_HANDLE);
|
||||||
|
if (p->status == -1) {
|
||||||
|
int status;
|
||||||
|
if (-1 == waitpid(p->pid, &status, 0))
|
||||||
|
return push_error(L);
|
||||||
|
p->status = WEXITSTATUS(status);
|
||||||
|
}
|
||||||
|
lua_pushnumber(L, p->status);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef SPAWN_H
|
||||||
|
#define SPAWN_H
|
||||||
|
|
||||||
|
#ifdef MISSING_POSIX_SPAWN
|
||||||
|
#include "posix_spawn.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define PROCESS_HANDLE "process"
|
||||||
|
struct process {
|
||||||
|
int status;
|
||||||
|
pid_t pid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct spawn_params {
|
||||||
|
lua_State *L;
|
||||||
|
const char *command, **argv, **envp;
|
||||||
|
posix_spawn_file_actions_t file_actions;
|
||||||
|
int has_actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
void spawn_param_filename(struct spawn_params *p);
|
||||||
|
void spawn_param_defaults(struct spawn_params *p);
|
||||||
|
void spawn_param_args(struct spawn_params *p);
|
||||||
|
void spawn_param_env(struct spawn_params *p);
|
||||||
|
void spawn_param_redirects(struct spawn_params *p);
|
||||||
|
int spawn_param_execute(struct spawn_params *p, struct process *proc);
|
||||||
|
int process_wait(lua_State *L);
|
||||||
|
|
||||||
|
#endif/*SPAWN_H*/
|
||||||
@ -0,0 +1,153 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include "spawn.h"
|
||||||
|
|
||||||
|
extern void *checkuserdata(lua_State *L, int index, const char *name);
|
||||||
|
extern HANDLE get_handle(FILE *f);
|
||||||
|
|
||||||
|
static int needs_quoting(const char *s)
|
||||||
|
{
|
||||||
|
return s[0] != '"' && strchr(s, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filename ... */
|
||||||
|
void spawn_param_filename(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
/* XXX luaL_checkstring is confusing here */
|
||||||
|
p->cmdline = luaL_checkstring(p->L, 1);
|
||||||
|
if (needs_quoting(p->cmdline)) {
|
||||||
|
lua_pushliteral(p->L, "\""); /* cmd ... q */
|
||||||
|
lua_pushvalue(p->L, 1); /* cmd ... q cmd */
|
||||||
|
lua_pushvalue(p->L, -2); /* cmd ... q cmd q */
|
||||||
|
lua_concat(p->L, 3); /* cmd ... "cmd" */
|
||||||
|
lua_replace(p->L, 1); /* "cmd" ... */
|
||||||
|
p->cmdline = lua_tostring(p->L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
void spawn_param_defaults(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
p->environment = 0;
|
||||||
|
memset(&p->si, 0, sizeof p->si);
|
||||||
|
p->si.cb = sizeof p->si;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cmd opts ... argtab -- cmd opts ... cmdline */
|
||||||
|
void spawn_param_args(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
lua_State *L = p->L;
|
||||||
|
luaL_Buffer args;
|
||||||
|
luaL_buffinit(L, &args);
|
||||||
|
size_t i, n = lua_objlen(L, -1);
|
||||||
|
/* concatenate the arg array to a string */
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
int quote;
|
||||||
|
lua_rawgeti(L, -1, i); /* ... argtab arg */
|
||||||
|
/* XXX checkstring is confusing here */
|
||||||
|
quote = needs_quoting(luaL_checkstring(L, -1));
|
||||||
|
luaL_putchar(&args, ' ');
|
||||||
|
if (quote) luaL_putchar(&args, '"');
|
||||||
|
luaL_addvalue(&args);
|
||||||
|
if (quote) luaL_putchar(&args, '"');
|
||||||
|
lua_pop(L, 1); /* ... argtab */
|
||||||
|
}
|
||||||
|
luaL_pushresult(&args); /* ... argtab argstr */
|
||||||
|
lua_pushvalue(L, 1); /* cmd opts ... argtab argstr cmd */
|
||||||
|
lua_replace(L, -2); /* cmd opts ... argtab cmd argstr */
|
||||||
|
lua_concat(L, 2); /* cmd opts ... argtab cmdline */
|
||||||
|
lua_replace(L, -2); /* cmd opts ... cmdline */
|
||||||
|
p->cmdline = lua_tostring(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... envtab */
|
||||||
|
void spawn_param_env(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
lua_State *L = p->L;
|
||||||
|
luaL_Buffer env;
|
||||||
|
if (lua_isnil(L, -1)) {
|
||||||
|
p->environment = 0;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* convert env table to zstring list */
|
||||||
|
/* {nam1=val1,nam2=val2} => "nam1=val1\0nam2=val2\0\0" */
|
||||||
|
luaL_buffinit(L, &env);
|
||||||
|
lua_pushnil(L); /* ... envtab nil */
|
||||||
|
while (lua_next(L, -2)) { /* ... envtab k v */
|
||||||
|
/* XXX luaL_checktype is confusing here */
|
||||||
|
luaL_checktype(L, -2, LUA_TSTRING);
|
||||||
|
luaL_checktype(L, -1, LUA_TSTRING);
|
||||||
|
lua_pushvalue(L, -2); /* ... envtab k v k */
|
||||||
|
luaL_addvalue(&env);
|
||||||
|
luaL_putchar(&env, '=');
|
||||||
|
lua_pop(L, 1); /* ... envtab k v */
|
||||||
|
luaL_addvalue(&env);
|
||||||
|
luaL_putchar(&env, '\0');
|
||||||
|
lua_pop(L, 1); /* ... envtab k */
|
||||||
|
}
|
||||||
|
luaL_putchar(&env, '\0');
|
||||||
|
luaL_pushresult(&env); /* ... envtab envstr */
|
||||||
|
lua_replace(L, -2); /* ... envtab envstr */
|
||||||
|
p->environment = lua_tostring(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _ opts ... */
|
||||||
|
static int get_redirect(struct spawn_params *p, const char *stdname, HANDLE *ph)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
lua_getfield(p->L, 2, stdname);
|
||||||
|
if ((ret = !lua_isnil(p->L, -1))) {
|
||||||
|
/* XXX checkuserdata is confusing here */
|
||||||
|
FILE **pf = checkuserdata(p->L, -1, LUA_FILEHANDLE);
|
||||||
|
*ph = get_handle(*pf);
|
||||||
|
}
|
||||||
|
lua_pop(p->L, 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _ opts ... */
|
||||||
|
void spawn_param_redirects(struct spawn_params *p)
|
||||||
|
{
|
||||||
|
p->si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
p->si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
p->si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
if (get_redirect(p, "stdin", &p->si.hStdInput)
|
||||||
|
| get_redirect(p, "stdout", &p->si.hStdOutput)
|
||||||
|
| get_redirect(p, "stderr", &p->si.hStdError))
|
||||||
|
p->si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawn_param_execute(struct spawn_params *p, struct process *proc)
|
||||||
|
{
|
||||||
|
char *c = strdup(p->cmdline);
|
||||||
|
char *e = (char *)p->environment; // strdup(p->environment);
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
proc->status = -1;
|
||||||
|
/* XXX does CreateProcess modify its environment argument? */
|
||||||
|
int ret = CreateProcess(0, c, 0, 0, 0, 0, e, 0, &p->si, &pi);
|
||||||
|
if (e) free(e);
|
||||||
|
free(c);
|
||||||
|
if (ret) proc->hProcess = pi.hProcess;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* proc -- exitcode/nil error */
|
||||||
|
int process_wait(lua_State *L)
|
||||||
|
{
|
||||||
|
struct process *p = checkuserdata(L, 1, PROCESS_HANDLE);
|
||||||
|
if (p->status == -1) {
|
||||||
|
DWORD exitcode;
|
||||||
|
WaitForSingleObject(p->hProcess, INFINITE);
|
||||||
|
GetExitCodeProcess(p->hProcess, &exitcode);
|
||||||
|
p->status = exitcode;
|
||||||
|
}
|
||||||
|
lua_pushnumber(L, p->status);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef SPAWN_H
|
||||||
|
#define SPAWN_H
|
||||||
|
#include <lua.h>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
struct spawn_params {
|
||||||
|
lua_State *L;
|
||||||
|
const char *cmdline;
|
||||||
|
const char *environment;
|
||||||
|
STARTUPINFO si;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PROCESS_HANDLE "process"
|
||||||
|
struct process {
|
||||||
|
int status;
|
||||||
|
HANDLE hProcess;
|
||||||
|
};
|
||||||
|
|
||||||
|
void spawn_param_filename(struct spawn_params *p);
|
||||||
|
void spawn_param_defaults(struct spawn_params *p);
|
||||||
|
void spawn_param_args(struct spawn_params *p);
|
||||||
|
void spawn_param_env(struct spawn_params *p);
|
||||||
|
void spawn_param_redirects(struct spawn_params *p);
|
||||||
|
int spawn_param_execute(struct spawn_params *p, struct process *proc);
|
||||||
|
|
||||||
|
int process_wait(lua_State *L);
|
||||||
|
|
||||||
|
#endif/*SPAWN_H*/
|
||||||
Loading…
Reference in New Issue