commit 9b7832a44d2e19ea39b249287ca0c872246366dc
parent 713d30f9a2f42bcc43c7f5bba53d962fcba207cf
Author: Daniel Barlow <dan@telent.net>
Date: Thu, 14 May 2026 23:20:11 +0100
WIP rewrite in C
$ ls -l result/bin/luad src/luad
-r-xr-xr-x 1 root root 415032 Jan 1 1970 result/bin/luad
-rwxr-xr-x 1 dan users 21872 May 14 23:18 src/luad
it's difficult to argue against that size saving, and we weren't
doing much except calling libraries written in C anyway
this is WIP as in it's functional mostly but it's a first pass, may
contain bugs, needs lint, hardcodes the socket path
Diffstat:
| A | src/luad.c | | | 242 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 242 insertions(+), 0 deletions(-)
diff --git a/src/luad.c b/src/luad.c
@@ -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;
+}