diff --git a/.gitignore b/.gitignore index 61b51d6d..7a5de194 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ parser.tab.o test_parser.o test_parser ppidcache.o +mxq_reaper.o mxqsub /mxqsub.1 @@ -44,6 +45,7 @@ test_mx_log test_mx_mysq test_mxqd_control test_keywordset +mxq_reaper /web/pages/mxq/mxq web/lighttpd.conf diff --git a/Makefile b/Makefile index 4acc4afc..2f7a6c0f 100644 --- a/Makefile +++ b/Makefile @@ -656,6 +656,13 @@ build: mxqps clean: CLEAN += mxqps +### mxqps ------------------------------------------------------------- + +clean: CLEAN += mxq_reaper.o mxq_reaper +build: mxq_reaper +install:: mxq_reaper + $(call quiet-install,0755,$^,${DESTDIR}${LIBEXECDIR}/mxq/mxq_reaper) + ### script helper ----------------------------------------------------- install:: helper/tmpdir-setup diff --git a/mxq_reaper.c b/mxq_reaper.c new file mode 100644 index 00000000..f843980a --- /dev/null +++ b/mxq_reaper.c @@ -0,0 +1,104 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char REAPER_PNAME[] = "mxqd reaper"; + +__attribute__((noreturn)) static void die(char *msg) { + perror(msg); + _exit(1); +} + +int main(int argc, char **argv) { + + if (argc < 5 || strcmp(argv[3], "--") != 0) { + fprintf(stderr, "usage: %s UID SPOOLFILENAME -- CMD [ARGS...]\n", argv[0]); + exit(1); + } + + uid_t uid = atoi(argv[1]); + char *spoolfilename = argv[2]; + char **user_argv = &argv[4]; + + pid_t user_pid; + int user_status = -1; + struct rusage user_rusage; + struct timeval user_time; + + struct timeval starttime; + struct timeval endtime; + + if (prctl(PR_SET_NAME, REAPER_PNAME, NULL, NULL, NULL) == -1) + die("PR_SET_NAME"); + user_pid = fork(); + if (user_pid == 0) { + if (setreuid(uid, uid) == -1) + die("setreuid"); + execvp(user_argv[0], user_argv); + die(user_argv[0]); + } + if (user_pid == -1) + die("fork"); + if (gettimeofday(&starttime, NULL) == -1) + die("gettimeofday"); + while (1) { + int status; + pid_t pid = wait(&status); + if (pid < 0 && errno == ECHILD) + break; + if (pid == user_pid) + user_status = status; + } + if (gettimeofday(&endtime, NULL) == -1) + die("gettimeofday"); + timersub(&endtime, &starttime, &user_time); + if (getrusage(RUSAGE_CHILDREN, &user_rusage) == -1) + die("getrusage"); + + if (user_time.tv_sec<30) { + int wait=30-user_time.tv_sec; + sleep(wait); + } + + char *tmpfilename; + if (asprintf(&tmpfilename, "%s.tmp", spoolfilename) == -1) + die(""); + + FILE *out = fopen(tmpfilename,"w"); + if (out == NULL) + die(tmpfilename); + fprintf(out,"1 %d %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n", + getpid(), + user_status, + user_time.tv_sec, user_time.tv_usec, + user_rusage.ru_utime.tv_sec, user_rusage.ru_utime.tv_usec, + user_rusage.ru_stime.tv_sec, user_rusage.ru_stime.tv_usec, + user_rusage.ru_maxrss, + user_rusage.ru_ixrss, + user_rusage.ru_idrss, + user_rusage.ru_isrss, + user_rusage.ru_minflt, + user_rusage.ru_majflt, + user_rusage.ru_nswap, + user_rusage.ru_inblock, + user_rusage.ru_oublock, + user_rusage.ru_msgsnd, + user_rusage.ru_msgrcv, + user_rusage.ru_nsignals, + user_rusage.ru_nvcsw, + user_rusage.ru_nivcsw + ); + fflush(out); + fsync(fileno(out)); + fclose(out); + if (rename(tmpfilename, spoolfilename) == -1) + die(spoolfilename); + return 0; +}