Select Git revision
maxima_fork.c
maxima_fork.c 5.16 KiB
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <pwd.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <bsd/unistd.h>
#include <limits.h>
#include <grp.h>
#define N_SLOT 16
#define RNOFILE 256
#define FILEPATH_LEN (PATH_MAX + 1)
char filepath[FILEPATH_LEN];
// inits a maxima process for web service:
// changes gid/uid to maxima-{slot}
// redirects input/output, creates temporary subdirectories
char *fork_new_process() {
fflush(stdout);
// send an S for Synchronization, so that
// the server process doesn't accidentally write into
// sbcl's buffer
// the server should not write anything before it has read this
write(STDOUT_FILENO, "S", 1);
// while the loop is running, the SIGCHLD handler
// is deactivated so that children are automatically reaped
// after that, it is again restored
struct sigaction old, new;
new.sa_handler = SIG_IGN;
sigemptyset(&new.sa_mask);
new.sa_flags = SA_NOCLDWAIT;
char *ret = NULL;
if (sigaction(SIGCHLD, &new, &old) == -1) {
perror("Could not set signal error for children");
return NULL;
}
// when sbcl spawns a child process through lisp, sbcl tries to close all
// filedescriptors until RLIMIT_NOFILE
// in docker containers, this is by standard quite high, so it takes long
// which is remediated here by setting it lower manually
struct rlimit nofile = { .rlim_cur = RNOFILE, .rlim_max = RNOFILE };
if (setrlimit(RLIMIT_NOFILE, &nofile) == -1) {
perror("Error setting rlimit_nofile");
sigaction(SIGCHLD, &old, NULL);
return NULL;
}
for (;;) {
// can't flush enough
fflush(stdout);
int slot;
// the slot number and temp directory is sent to the process
// over stdin in the format "%d%s", where %s can contain anything
// but newlines and musn't start with a number, which isn't a
// problem for absolute paths
if (scanf("%d", &slot) == EOF) {
if (errno != 0) {
perror("Error getting slot number from stdin");
ret = NULL;