shithub: moonfish

Download patch

ref: 11bcdbc521b17d7104d5118806c3891092b6979d
parent: 7b9f83e03f011c5c384e066214a81544d296c157
author: zamfofex <zamfofex@twdb.moe>
date: Mon Jun 24 19:36:14 EDT 2024

add daemon to spawn processes

(to avoid leaking resources)

--- a/tools/analyse.c
+++ b/tools/analyse.c
@@ -572,6 +572,8 @@
 	char *value;
 	char **options;
 	
+	moonfish_spawner(argv[0]);
+	
 	command = moonfish_args(args, format, argc, argv);
 	command_count = argc - (command - argv);
 	if (command_count < 1) moonfish_usage(args, format, argv[0]);
@@ -646,7 +648,7 @@
 	fancy->x = 0;
 	fancy->y = 0;
 	
-	moonfish_spawn(argv[0], command, &fancy->in, &fancy->out, NULL);
+	moonfish_spawn(command, &fancy->in, &fancy->out, NULL);
 	
 	fancy->i = 0;
 	fancy->count = 1;
--- a/tools/battle.c
+++ b/tools/battle.c
@@ -183,7 +183,7 @@
 	if (*command != NULL && !strcmp(*command, "--"))
 		command++;
 	
-	moonfish_spawn(argv0, command, &bot->in, &bot->out, NULL);
+	moonfish_spawn(command, &bot->in, &bot->out, NULL);
 	
 	if (bot->ugi) fprintf(bot->in, "ugi\n");
 	else fprintf(bot->in, "uci\n");
@@ -441,7 +441,9 @@
 	
 	char *argv0;
 	
-	if (argc < 1) return 1;
+	(void) argc;
+	
+	moonfish_spawner(argv[0]);
 	
 	battle.fen = NULL;
 	
--- a/tools/book.c
+++ b/tools/book.c
@@ -60,6 +60,8 @@
 	int error;
 	pthread_t thread;
 	
+	moonfish_spawner(argv[0]);
+	
 	command = moonfish_args(args, format, argc, argv);
 	if (args[0].value == NULL) moonfish_usage(args, format, argv[0]);
 	
@@ -134,7 +136,7 @@
 	
 	if (i == 0) fprintf(stderr, "%s: Empty book.\n", argv[0]);
 	
-	moonfish_spawn(argv[0], command, &in, &out, NULL);
+	moonfish_spawn(command, &in, &out, NULL);
 	
 	error = pthread_create(&thread, NULL, moonfish_book_start, out);
 	if (error != 0)
--- a/tools/chat.c
+++ b/tools/chat.c
@@ -174,7 +174,7 @@
 	
 	moonfish_chess(&chess);
 	
-	moonfish_spawn(argv0, command, &in, &out, NULL);
+	moonfish_spawn(command, &in, &out, NULL);
 	fprintf(in, "uci\n");
 	moonfish_wait(out, "uciok");
 	
@@ -352,6 +352,8 @@
 	};
 	
 	char **options, **command;
+	
+	moonfish_spawner(argv[0]);
 	
 	/* todo: validate nickname & channels*/
 	options = moonfish_args(args, format, argc, argv);
--- a/tools/lichess.c
+++ b/tools/lichess.c
@@ -274,7 +274,7 @@
 	
 	game = data;
 	
-	moonfish_spawn(game->argv0, game->argv, &in, &out, NULL);
+	moonfish_spawn(game->argv, &in, &out, NULL);
 	tls = moonfish_connect(game->argv0, game->host, game->port);
 	
 	snprintf(request, sizeof request, "GET /api/bot/game/stream/%s", game->id);
@@ -505,6 +505,8 @@
 	int command_count;
 	struct tls *tls;
 	char *username;
+	
+	moonfish_spawner(argv[0]);
 	
 	command = moonfish_args(args, format, argc, argv);
 	command_count = argc - (command - argv);
--- a/tools/play.c
+++ b/tools/play.c
@@ -319,6 +319,8 @@
 	char **command;
 	int command_count;
 	
+	moonfish_spawner(argv[0]);
+	
 	command = moonfish_args(args, format, argc, argv);
 	command_count = argc - (command - argv);
 	if (command_count < 1) moonfish_usage(args, format, argv[0]);
@@ -325,7 +327,7 @@
 	
 	name = names;
 	
-	moonfish_spawn(argv[0], command, &in, &out, NULL);
+	moonfish_spawn(command, &in, &out, NULL);
 	
 	if (tcgetattr(0, &moonfish_termios))
 	{
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -15,7 +15,9 @@
 	char *description;
 };
 
-void moonfish_spawn(char *argv0, char **argv, FILE **in, FILE **out, char *directory);
+void moonfish_spawner(char *argv0);
+void moonfish_spawn(char **argv, FILE **in, FILE **out, char *directory);
+
 char *moonfish_next(FILE *file);
 char *moonfish_wait(FILE *file, char *name);
 char **moonfish_args(struct moonfish_arg *args, char *rest_format, int argc, char **argv);
--- a/tools/ugi.c
+++ b/tools/ugi.c
@@ -44,7 +44,8 @@
 	void *(*start1)(void *data);
 	void *(*start2)(void *data);
 	
-	moonfish_spawn(argv0, argv, &in, &out, NULL);
+	moonfish_spawner(argv0);
+	moonfish_spawn(argv, &in, &out, NULL);
 	
 	for (;;)
 	{
--- a/tools/utils.c
+++ b/tools/utils.c
@@ -6,87 +6,417 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/un.h>
 
 #include "tools.h"
 
-static int moonfish_fork(char *argv0, char **argv, int *in_fd, int *out_fd, char *directory)
+static pid_t moonfish_spawner_pid;
+static char *moonfish_spawner_argv0;
+static int moonfish_spawner_fd;
+static char *moonfish_spawner_dir_name;
+static char *moonfish_spawner_socket_name;
+
+static void *moonfish_read_pipe(void *data)
 {
-	int p1[2], p2[2];
-	int pid;
+	char ch;
+	int *fds;
+	fds = data;
+	while (read(fds[0], &ch, 1) > 0) { }
+	if (moonfish_spawner_socket_name != NULL)
+	{
+		if (unlink(moonfish_spawner_socket_name) != 0)
+			perror(moonfish_spawner_argv0);
+	}
+	if (moonfish_spawner_dir_name != NULL)
+	{
+		if (rmdir(moonfish_spawner_dir_name) != 0)
+			perror(moonfish_spawner_argv0);
+	}
+	exit(0);
+}
+
+void moonfish_spawner(char *argv0)
+{
+	int fd;
+	FILE *in, *out;
+	pid_t pid;
+	int i, count, length;
+	char **argv;
+	char *directory;
+	struct sigaction action;
+	pthread_t thread;
+	int fds[2];
+	struct sockaddr_un address = {0};
 	
-	if (pipe(p1) < 0) return 1;
-	if (pipe(p2) < 0) return 1;
+	moonfish_spawner_argv0 = argv0;
 	
-	pid = fork();
-	if (pid < 0) return 1;
+	moonfish_spawner_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (moonfish_spawner_fd < 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
 	
-	if (pid)
+	if (pipe(fds) != 0)
 	{
-		*in_fd = p1[1];
-		*out_fd = p2[0];
-		close(p1[0]);
-		close(p2[1]);
-		return 0;
+		perror(argv0);
+		exit(1);
 	}
 	
-	if (directory != NULL)
+	moonfish_spawner_pid = fork();
+	if (moonfish_spawner_pid < 0)
 	{
-		if (chdir(directory))
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (moonfish_spawner_pid != 0)
+		return;
+	
+	close(fds[1]);
+	
+	pthread_create(&thread, NULL, &moonfish_read_pipe, fds);
+	
+	action.sa_flags = SA_NOCLDWAIT;
+	action.sa_handler = SIG_DFL;
+	if (sigemptyset(&action.sa_mask))
+	{
+		perror(argv0);
+		exit(1);
+	}
+	if (sigaction(SIGCHLD, &action, NULL))
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	address.sun_family = AF_UNIX;
+	strcpy(address.sun_path, "/tmp/moon-XXXXXX");
+	
+	if (mkdtemp(address.sun_path) == NULL)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	moonfish_spawner_dir_name = strdup(address.sun_path);
+	if (moonfish_spawner_dir_name == NULL)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	strcat(address.sun_path, "/socket");
+	
+	moonfish_spawner_socket_name = strdup(address.sun_path);
+	if (moonfish_spawner_socket_name == NULL)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (bind(moonfish_spawner_fd, (void *) &address, sizeof address) != 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (listen(moonfish_spawner_fd, 8) < 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	for (;;)
+	{
+		fd = accept(moonfish_spawner_fd, NULL, NULL);
+		if (fd < 0)
 		{
 			perror(argv0);
 			exit(1);
 		}
+		
+		pid = fork();
+		if (pid < 0)
+		{
+			perror(argv0);
+			exit(1);
+		}
+		
+		if (pid == 0) break;
+		close(fd);
 	}
 	
-	dup2(p1[0], 0);
-	dup2(p2[1], 1);
-	dup2(p2[1], 2);
+	close(fds[0]);
+	close(moonfish_spawner_fd);
 	
-	close(p1[0]);
-	close(p1[1]);
-	close(p2[0]);
-	close(p2[1]);
+	in = fdopen(fd, "r");
+	if (in == NULL)
+	{
+		perror(argv0);
+		exit(1);
+	}
 	
+	out = fdopen(fd, "w");
+	if (out == NULL)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (setvbuf(in, NULL, _IONBF, 0) != 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (setvbuf(out, NULL, _IONBF, 0) != 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	pid = getpid();
+	if (fwrite(&pid, sizeof pid, 1, out) != 1)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (fread(&length, sizeof length, 1, in) != 1)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (length < 0)
+	{
+		fprintf(stderr, "%s: invalid length\n", argv0);
+		exit(1);
+	}
+	
+	if (length > 0)
+	{
+		directory = malloc(length + 1);
+		if (directory == NULL)
+		{
+			perror(argv0);
+			exit(1);
+		}
+		
+		directory[length] = 0;
+		
+		if (fread(directory, length, 1, in) != 1)
+		{
+			perror(argv0);
+			exit(1);
+		}
+		
+		if (chdir(directory) != 0)
+		{
+			perror(argv0);
+			exit(1);
+		}
+	}
+	
+	if (fread(&count, sizeof count, 1, in) != 1)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (count < 1)
+	{
+		fprintf(stderr, "%s: too few arguments\n", argv0);
+		exit(1);
+	}
+	
+	argv = malloc(sizeof *argv * (count + 1));
+	if (argv == NULL)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	argv[count] = NULL;
+	
+	for (i = 0 ; i < count ; i++)
+	{
+		if (fread(&length, sizeof length, 1, in) != 1)
+		{
+			perror(argv0);
+			exit(1);
+		}
+		
+		argv[i] = malloc(length + 1);
+		if (argv[i] == NULL)
+		{
+			perror(argv0);
+			exit(1);
+		}
+		argv[i][length] = 0;
+		
+		if (fread(argv[i], length, 1, in) != 1)
+		{
+			perror(argv0);
+			exit(1);
+		}
+	}
+	
+	if (dup2(fd, 0) < 0 || dup2(fd, 1) < 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	close(fd);
+	
+	fd = open("/dev/null", O_WRONLY);
+	if (fd < 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
+	if (dup2(fd, 2) < 0)
+	{
+		perror(argv0);
+		exit(1);
+	}
+	
 	execvp(argv[0], argv);
 	fprintf(stderr, "%s: %s: %s\n", argv0, argv[0], strerror(errno));
 	exit(1);
 }
 
-void moonfish_spawn(char *argv0, char **argv, FILE **in, FILE **out, char *directory)
+void moonfish_spawn(char **argv, FILE **in, FILE **out, char *directory)
 {
-	int in_fd, out_fd;
+	pid_t pid;
+	int fd;
+	int i, count;
+	struct sockaddr_un address;
+	socklen_t length;
 	
-	if (moonfish_fork(argv0, argv, &in_fd, &out_fd, directory))
+	pid = waitpid(moonfish_spawner_pid, NULL, WNOHANG);
+	if (pid < 0)
 	{
-		perror(argv0);
+		perror(moonfish_spawner_argv0);
 		exit(1);
 	}
+	if (pid != 0)
+	{
+		fprintf(stderr, "%s: spawner exited\n", moonfish_spawner_argv0);
+		exit(1);
+	}
 	
-	*in = fdopen(in_fd, "w");
+	length = sizeof address;
+	if (getsockname(moonfish_spawner_fd, (void *) &address, &length) != 0)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	if (connect(fd, (void *) &address, length) != 0)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	*in = fdopen(dup(fd), "w");
 	if (*in == NULL)
 	{
-		perror(argv0);
+		perror(moonfish_spawner_argv0);
 		exit(1);
 	}
 	
-	*out = fdopen(out_fd, "r");
+	*out = fdopen(dup(fd), "r");
 	if (*out == NULL)
 	{
-		perror(argv0);
+		perror(moonfish_spawner_argv0);
 		exit(1);
 	}
 	
-	errno = 0;
-	if (setvbuf(*in, NULL, _IOLBF, 0))
+	close(fd);
+	
+	if (setvbuf(*in, NULL, _IONBF, 0) != 0)
 	{
-		if (errno) perror(argv0);
+		perror(moonfish_spawner_argv0);
 		exit(1);
 	}
 	
-	errno = 0;
-	if (setvbuf(*out, NULL, _IOLBF, 0))
+	if (setvbuf(*out, NULL, _IONBF, 0) != 0)
 	{
-		if (errno) perror(argv0);
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	if (directory == NULL) directory = "";
+	count = strlen(directory);
+	if (fwrite(&count, sizeof count, 1, *in) != 1)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	if (fwrite(directory, count, 1, *in) != 1)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	count = 0;
+	while (argv[count] != NULL)
+		count++;
+	
+	if (fwrite(&count, sizeof count, 1, *in) != 1)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	for (i = 0 ; argv[i] != NULL ; i++)
+	{
+		count = strlen(argv[i]);
+		if (fwrite(&count, sizeof count, 1, *in) != 1)
+		{
+			perror(moonfish_spawner_argv0);
+			exit(1);
+		}
+		
+		if (fwrite(argv[i], count, 1, *in) != 1)
+		{
+			perror(moonfish_spawner_argv0);
+			exit(1);
+		}
+	}
+	
+	if (fread(&pid, sizeof pid, 1, *out) != 1)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	if (setvbuf(*in, NULL, _IOLBF, 0) != 0)
+	{
+		perror(moonfish_spawner_argv0);
+		exit(1);
+	}
+	
+	if (setvbuf(*out, NULL, _IOLBF, 0) != 0)
+	{
+		perror(moonfish_spawner_argv0);
 		exit(1);
 	}
 }
--