Compare commits
4 Commits
73efb42233
...
9b7832a44d
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b7832a44d | |||
| 713d30f9a2 | |||
| 0a5d7f83f6 | |||
| 4370b6ea99 |
Generated
-29
@@ -40,12 +40,6 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
@@ -58,15 +52,6 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "fork"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bcc4b4161e53d499e41af904acb23950adf85682c772921ef3957cf1ecc98b3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
@@ -86,10 +71,8 @@ dependencies = [
|
||||
name = "luad"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fork",
|
||||
"libc",
|
||||
"mlua",
|
||||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -126,18 +109,6 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.31.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
||||
@@ -4,7 +4,5 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
fork = "0.7.0"
|
||||
libc = "0.2.186"
|
||||
mlua = { version = "0.11.6", features = ["lua53"] }
|
||||
nix = { version = "0.31.2", features = ["process"] }
|
||||
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
static int sigchild_fd = -1;
|
||||
|
||||
static void handle_sigchld(int num) {
|
||||
if(sigchild_fd >= 0) {
|
||||
write(sigchild_fd, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int open_socket(char * pathname) {
|
||||
|
||||
struct sockaddr_un addr;
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, pathname, sizeof(addr.sun_path) - 1);
|
||||
|
||||
int fd = socket(AF_LOCAL, SOCK_DGRAM, PF_LOCAL);
|
||||
if(fd < 0) {
|
||||
perror("socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if((bind(fd, (struct sockaddr *) &addr, sizeof addr)) < 0) {
|
||||
perror("bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int * fds_from_msg(struct msghdr *msg, size_t peer_fds_count) {
|
||||
int *peer_fds = (int *) calloc(peer_fds_count, sizeof(int));
|
||||
for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg);
|
||||
cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if(cmsg->cmsg_level == SOL_SOCKET &&
|
||||
cmsg->cmsg_type == SCM_RIGHTS) {
|
||||
memcpy(peer_fds, CMSG_DATA(cmsg), peer_fds_count * sizeof(int));
|
||||
}
|
||||
}
|
||||
return peer_fds;
|
||||
}
|
||||
|
||||
int start_lua_child(lua_State *L,
|
||||
char * command_line, int command_line_length,
|
||||
int * fds, int fds_count) {
|
||||
char * word = command_line;
|
||||
char * command_line_end = command_line + command_line_length;
|
||||
char * pathname = NULL;
|
||||
int i = 0;
|
||||
|
||||
fflush(stdout); fflush(stderr);
|
||||
for(int i=0; i < fds_count; i++) {
|
||||
if(fds[i] > 0) dup2(fds[i], i);
|
||||
}
|
||||
|
||||
lua_newtable(L); /* arg */
|
||||
while(word < command_line_end) {
|
||||
char * word_end = memchr(word, '\0', command_line_end - word);
|
||||
if(!word_end) break;
|
||||
if(!pathname) {
|
||||
pathname = strndup(word, (word_end - word));
|
||||
}
|
||||
lua_pushlstring(L, word, (word_end - word));
|
||||
lua_seti(L, -2, i++);
|
||||
word = word_end + 1;
|
||||
}
|
||||
lua_setglobal(L, "arg");
|
||||
int status = luaL_dofile(L, pathname);
|
||||
if (status) {
|
||||
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pid_t fork_lua(lua_State *L,
|
||||
char * command_line, int command_line_length,
|
||||
int * fds, int fds_count) {
|
||||
pid_t pid = fork();
|
||||
if(pid == 0) {
|
||||
exit(start_lua_child(L, command_line, command_line_length,
|
||||
fds, fds_count));
|
||||
} else if(pid > 0) {
|
||||
free(command_line);
|
||||
return pid;
|
||||
} else {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct peer_entry {
|
||||
pid_t pid;
|
||||
int addrlen;
|
||||
struct sockaddr_un addr;
|
||||
};
|
||||
|
||||
int register_peer(struct peer_entry *table, pid_t pid, struct sockaddr_un *addr, int addrlen) {
|
||||
if(addrlen > sizeof (struct sockaddr_un))
|
||||
return -1;
|
||||
|
||||
struct peer_entry *p = table;
|
||||
while(p->pid != 0 && p->pid != -1)
|
||||
p++;
|
||||
if(p->pid == -1)
|
||||
return -1;
|
||||
p->pid = pid;
|
||||
p->addrlen = addrlen;
|
||||
memcpy(&(p->addr), addr, addrlen);
|
||||
}
|
||||
|
||||
struct peer_entry* find_peer(struct peer_entry *table, pid_t pid) {
|
||||
while(table->pid != -1) {
|
||||
if(table->pid == pid)
|
||||
return table;
|
||||
table++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int status;
|
||||
lua_State *L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
int sigpipe_fds[2];
|
||||
struct peer_entry * peer_table = calloc(501, sizeof (struct peer_entry));
|
||||
peer_table[500].pid = -1;
|
||||
|
||||
if(pipe(sigpipe_fds) < 0) {
|
||||
perror("pipe");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sigchild_fd = sigpipe_fds[1];
|
||||
|
||||
signal(SIGCHLD, handle_sigchld);
|
||||
|
||||
if (argc >= 2) {
|
||||
if (!access(argv[1], F_OK) == 0) {
|
||||
fprintf(stderr, "File %s does not exist!\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
status = luaL_dofile(L, argv[1]);
|
||||
if (status) {
|
||||
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int socket = open_socket("/tmp/mysock"); /* FIXME hardcoded */
|
||||
struct sockaddr_un peer_addr;
|
||||
socklen_t peer_addr_len;
|
||||
char buf[1025];
|
||||
struct iovec iov[1];
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = sizeof buf;
|
||||
struct cmsghdr* cmsg = (struct cmsghdr *) calloc(1000, 1);
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_name = &peer_addr,
|
||||
.msg_namelen = sizeof peer_addr,
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsg,
|
||||
.msg_controllen = 1000
|
||||
};
|
||||
|
||||
struct pollfd pollfds[2] = {
|
||||
{
|
||||
.fd = socket,
|
||||
.events = POLLIN,
|
||||
.revents = 0
|
||||
},
|
||||
{
|
||||
.fd = sigpipe_fds[0],
|
||||
.events = POLLIN,
|
||||
.revents = 0
|
||||
},
|
||||
};
|
||||
|
||||
while(1) {
|
||||
if(poll(pollfds, 2, 10000) == 0)
|
||||
continue;
|
||||
|
||||
if(pollfds[0].revents) {
|
||||
int len = recvmsg(socket, &msg , 0);
|
||||
int *peer_fds = fds_from_msg(&msg, 5);
|
||||
char *argline = malloc(len);
|
||||
memmove(argline, buf, len);
|
||||
|
||||
pid_t child_pid = fork_lua(L, argline, len, peer_fds, 5);
|
||||
if(child_pid >= 0) {
|
||||
register_peer(peer_table, child_pid, &peer_addr, msg.msg_namelen);
|
||||
}
|
||||
}
|
||||
|
||||
if(pollfds[1].revents) {
|
||||
pid_t pid;
|
||||
int wstatus;
|
||||
|
||||
read(pollfds[1].fd, buf, sizeof buf);
|
||||
while((pid=waitpid(0, &wstatus, WNOHANG)) > 0) {
|
||||
struct peer_entry *peer = find_peer(peer_table, pid);
|
||||
if(peer) {
|
||||
uint32_t ret = 0;
|
||||
if(WIFEXITED(wstatus)) {
|
||||
ret = htonl(WEXITSTATUS(wstatus));
|
||||
} else if(WIFSIGNALED(wstatus)) {
|
||||
ret = htonl(128 + WTERMSIG(wstatus));
|
||||
}
|
||||
sendto(socket, (void *) &ret, 4, 0,
|
||||
(const struct sockaddr *) &(peer->addr),
|
||||
peer->addrlen);
|
||||
peer->pid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+70
-14
@@ -23,11 +23,56 @@ use libc::{
|
||||
pollfd,
|
||||
poll,
|
||||
POLLIN,
|
||||
c_void
|
||||
};
|
||||
use nix::sys::wait::{wait,WaitStatus::{Exited,Signaled}};
|
||||
c_void,
|
||||
|
||||
use fork::{Fork, fork};
|
||||
// fork,
|
||||
pid_t,
|
||||
|
||||
// wait,
|
||||
c_int,
|
||||
|
||||
WIFEXITED,
|
||||
WIFSIGNALED,
|
||||
WEXITSTATUS,
|
||||
WTERMSIG
|
||||
};
|
||||
|
||||
|
||||
enum WaitStatus {
|
||||
Exited(pid_t, c_int),
|
||||
Signaled(pid_t, c_int),
|
||||
}
|
||||
use crate::WaitStatus::*;
|
||||
|
||||
enum Forked {
|
||||
Parent(pid_t),
|
||||
Child,
|
||||
Err(std::io::Error)
|
||||
}
|
||||
|
||||
fn fork() -> Forked {
|
||||
let child_pid = unsafe { libc::fork() };
|
||||
if child_pid > 0 {
|
||||
Forked::Parent(child_pid)
|
||||
} else if child_pid == 0 {
|
||||
Forked::Child
|
||||
} else {
|
||||
Forked::Err(std::io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
fn wait() -> Result<WaitStatus, std::io::Error> {
|
||||
let mut wstatus : c_int = 0;
|
||||
let pid = unsafe { libc::wait(&mut wstatus) };
|
||||
if pid >= 0 {
|
||||
if WIFEXITED(wstatus) {
|
||||
return Ok(WaitStatus::Exited(pid, WEXITSTATUS(wstatus)))
|
||||
} else if WIFSIGNALED(wstatus) {
|
||||
return Ok(WaitStatus::Signaled(pid, WTERMSIG(wstatus)))
|
||||
}
|
||||
}
|
||||
Err(std::io::Error::last_os_error())
|
||||
}
|
||||
|
||||
static mut sigchild_fd : i32 = -1;
|
||||
|
||||
@@ -47,17 +92,17 @@ fn fork_lua(lua : &Lua, args: Vec<String>, fds: Vec<i32>) -> Option<i32> {
|
||||
let path = Path::new(pathname);
|
||||
|
||||
match fork() {
|
||||
Ok(Fork::Parent(pid)) => Some(pid),
|
||||
Ok(Fork::Child) => {
|
||||
Forked::Parent(pid) => Some(pid),
|
||||
Forked::Child => {
|
||||
for (i, fd) in fds.iter().enumerate() {
|
||||
unsafe { libc::dup2(*fd, i.try_into().unwrap()); }
|
||||
};
|
||||
let globals = lua.globals();
|
||||
if let Ok(arg_table) = lua.create_table() {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
arg_table.set(i, arg.clone());
|
||||
arg_table.set(i, arg.clone()).expect("arg set failed");
|
||||
}
|
||||
globals.set("arg".to_string(), arg_table);
|
||||
globals.set("arg".to_string(), arg_table).expect("arg set failed");
|
||||
}
|
||||
|
||||
let chunk = lua.load(path);
|
||||
@@ -69,7 +114,7 @@ fn fork_lua(lua : &Lua, args: Vec<String>, fds: Vec<i32>) -> Option<i32> {
|
||||
},
|
||||
};
|
||||
},
|
||||
Err(e) => {
|
||||
Forked::Err(e) => {
|
||||
println!("fork error {:?}", e);
|
||||
None
|
||||
}
|
||||
@@ -111,10 +156,22 @@ fn main() -> std::io::Result<()> {
|
||||
|
||||
unsafe {
|
||||
sigchild_fd = sigchild_writer.as_raw_fd();
|
||||
libc::signal(libc::SIGCHLD, handle_sigchld as libc::sighandler_t);
|
||||
libc::signal(libc::SIGCHLD, handle_sigchld as *const () as libc::sighandler_t);
|
||||
};
|
||||
let lua = unsafe { Lua::unsafe_new() };
|
||||
|
||||
let mut argv = env::args();
|
||||
argv.next();
|
||||
|
||||
if let Some(prelude) = argv.next() {
|
||||
let path = Path::new(&prelude);
|
||||
println!("preloading {:?}", path);
|
||||
lua.load(path).exec().expect("load prelude failed");
|
||||
} else {
|
||||
println!("no preload");
|
||||
}
|
||||
|
||||
|
||||
let sock = UnixDatagram::bind(sock_path)?;
|
||||
|
||||
let mut peers : HashMap<i32, SocketAddr> = HashMap::new();
|
||||
@@ -165,11 +222,10 @@ fn main() -> std::io::Result<()> {
|
||||
if let Some((pid, ret)) =
|
||||
match wstatus {
|
||||
Exited(pid, code) => Some((pid, code as u32)),
|
||||
Signaled(pid, sig, _) => Some((pid, (sig as u32) + 128)),
|
||||
_ => None
|
||||
Signaled(pid, sig) => Some((pid, (sig as u32) + 128))
|
||||
} {
|
||||
if let Some(addr) = peers.get(&pid.as_raw()) {
|
||||
sock.send_to_addr(&ret.to_be_bytes(), addr);
|
||||
if let Some(addr) = peers.get(&pid) {
|
||||
let _ = sock.send_to_addr(&ret.to_be_bytes(), addr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user