Compare commits

...

4 Commits

Author SHA1 Message Date
dan 262fc6437c die with sensible error message if socket path too long 2026-05-18 23:29:23 +01:00
dan 9569ba3cfa update README 2026-05-18 23:21:25 +01:00
dan 79313f1d55 consult env var to find socket path 2026-05-18 23:13:38 +01:00
dan a0e760884d improve error reporting 2026-05-18 23:11:13 +01:00
3 changed files with 46 additions and 31 deletions
+9 -5
View File
@@ -17,6 +17,15 @@ Liminix, but it may be useful elsewhere too.
* accept unix datagram socket commands
* fork a child for each peer socket and run the requested lua script
## how to use it
$ LUAD_SOCKET_PATH=/var/run/luad/socket luad prelude.lua
$ LUAD_SOCKET_PATH=/var/run/luad/socket luac script.lua arg1 arg2 ...
The pathname of a Lua script may optionally be passed to luad. It will
be loaded into the interpreter before it is forked, so whatever it
does will be available in the children.
## small print
@@ -25,8 +34,3 @@ Liminix, but it may be useful elsewhere too.
* tested only on Linux. Needs SCM_RIGHTS to send unix file descriptors
across processes, which seems to be have [implementation quirks on
different unix flavours](https://gist.github.com/kentonv/bc7592af98c68ba2738f4436920868dc)
## TO DO
[.] implement luac
+18 -13
View File
@@ -12,6 +12,11 @@
#include <arpa/inet.h>
#include <error.h>
#include <errno.h>
#define die(...) error(EXIT_FAILURE, errno, __VA_ARGS__)
// copied from OpenBSD
// https://github.com/openbsd/src/blob/master/lib/libc/string/strlcpy.c
@@ -47,23 +52,20 @@ size_t strlcpy(char *dst, const char *src, size_t dsize)
int open_socket(struct sockaddr_un *addr, struct sockaddr_un * peer_addr) {
int fd = socket(AF_LOCAL, SOCK_DGRAM, PF_LOCAL);
if(fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
die("can't create socket");
}
// local address is in the abstract namespace and ok to include
// trailing nul bytes
if((bind(fd, (struct sockaddr *) addr, sizeof (struct sockaddr_un))) < 0) {
perror("bind");
exit(EXIT_FAILURE);
die("can't bind socket local address");
}
// peer address is in the actual filesystem, so we need to pass
// the real length
int namelen = sizeof peer_addr->sun_family + strlen(peer_addr->sun_path);
if((connect(fd, (struct sockaddr *) peer_addr, namelen)) < 0) {
perror("connect");
exit(EXIT_FAILURE);
die("can't connect socket to \"%s\"", peer_addr->sun_path);
}
return fd;
@@ -76,8 +78,7 @@ int encode_args(char * buf, int len, int argc, char ** argv) {
for (int i = 1; i < argc; i++) {
p += strlcpy(p, argv[i], buf_end - p);
if(p >= buf_end) {
fprintf(stderr, "comand line too long\n");
exit(1);
error(1, 0, "comand line too long");
}
p++;
}
@@ -102,6 +103,11 @@ int main(int argc, char **argv)
exit(1);
}
char * socket_path = getenv("LUAD_SOCKET_PATH");
if(! socket_path) {
error(1, 0, "Missing required environment variable LUAD_SOCKET_PATH");
}
char * iobuf = (char *) calloc(1024, sizeof(char));
if(!iobuf) return 1;
int iobuf_len = encode_args(iobuf, 1024, argc, argv);
@@ -117,7 +123,8 @@ int main(int argc, char **argv)
memcpy(my_addr.sun_path + 1, (void *) &mypid, sizeof mypid);
memcpy(my_addr.sun_path + 1 + sizeof mypid, iobuf, maxnamelen - sizeof mypid - 1);
struct sockaddr_un peer_addr = { AF_UNIX, "/tmp/mysock" };
struct sockaddr_un peer_addr = { AF_UNIX };
strlcpy(peer_addr.sun_path, socket_path, sizeof peer_addr.sun_path);
int socket = open_socket(&my_addr, &peer_addr);
struct cmsghdr *cmsg;
@@ -147,10 +154,8 @@ int main(int argc, char **argv)
cmsg->cmsg_len = CMSG_LEN(sizeof(myfds));
memcpy(CMSG_DATA(cmsg), myfds, sizeof(myfds));
int bytes = sendmsg(socket, &msg, 0);
if(bytes <= 0) {
perror("sendmsg");
exit(1);
if(sendmsg(socket, &msg, 0) <= 0) {
die("sendmsg failed");
}
uint32_t exitstatus = 0;
+19 -13
View File
@@ -8,6 +8,8 @@
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <error.h>
#include <sys/un.h>
#include <signal.h>
@@ -25,22 +27,24 @@ static void handle_sigchld(int num) {
}
}
#define die(...) error(EXIT_FAILURE, errno, __VA_ARGS__)
int open_socket(char * pathname) {
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, pathname, sizeof(addr.sun_path) - 1);
if(strlen(pathname) > sizeof(addr.sun_path)) {
die("pathname \"%s\" is too long to bind as unix socket (max %lu)",
pathname, sizeof(addr.sun_path));
}
strcpy(addr.sun_path, pathname);
int fd = socket(AF_LOCAL, SOCK_DGRAM, PF_LOCAL);
if(fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
die("can't create socket \"%s\"", pathname);
}
if((bind(fd, (struct sockaddr *) &addr, sizeof addr)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
die("can't bind socket \"%s\"", pathname);
}
return fd;
}
@@ -103,8 +107,7 @@ pid_t fork_lua(lua_State *L,
free(command_line);
return pid;
} else {
perror("fork");
return -1;
die("fork failed");
}
}
@@ -148,9 +151,13 @@ int main(int argc, char **argv)
struct peer_entry * peer_table = calloc(501, sizeof (struct peer_entry));
peer_table[500].pid = -1;
char * socket_path = getenv("LUAD_SOCKET_PATH");
if(! socket_path) {
error(1, 0, "Missing required environment variable LUAD_SOCKET_PATH");
}
if(pipe(sigpipe_fds) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
die("can't create pipe");
}
sigchild_fd = sigpipe_fds[1];
@@ -159,12 +166,11 @@ int main(int argc, char **argv)
if (argc >= 2) {
status = luaL_dofile(L, argv[1]);
if (status) {
fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
return 1;
error(1, 0, "Error: %s", lua_tostring(L, -1));
}
}
int socket = open_socket("/tmp/mysock"); /* FIXME hardcoded */
int socket = open_socket(socket_path);
struct sockaddr_un peer_addr;
socklen_t peer_addr_len;
char buf[1025];