Skip to content
Permalink
b798aee151
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
126 lines (113 sloc) 3.52 KB
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
static const char REAPER_PNAME[] = "mxqd reaper";
__attribute__ ((noreturn))
__attribute__ ((format (printf, 1, 2)))
static void die(const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
_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: %m\n");
user_pid = fork();
if (user_pid == 0) {
if (setreuid(uid, uid) == -1)
die("setreuid: %m\n");
execvp(user_argv[0], user_argv);
die("%s: %m\n", user_argv[0]);
}
if (user_pid == -1)
die("fork: %m\n");
if (gettimeofday(&starttime, NULL) == -1)
die("gettimeofday: %m\n");
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: %m\n");
timersub(&endtime, &starttime, &user_time);
if (getrusage(RUSAGE_CHILDREN, &user_rusage) == -1)
die("getrusage: %m\n");
if (user_time.tv_sec<30) {
int wait=30-user_time.tv_sec;
sleep(wait);
}
while (1) {
// if anything fails, do not write to stderr, as this is the users
// stderr, just wait and retry.
char *tmpfilename;
if (asprintf(&tmpfilename, "%s.tmp", spoolfilename) == -1)
goto retry_1;
FILE *out = fopen(tmpfilename, "w");
if (out == NULL)
goto retry_2;
if (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) < 0)
goto retry_3;
if (fflush(out) == EOF)
goto retry_3;
if (fsync(fileno(out)) == -1)
goto retry_3;
if (fclose(out) == EOF)
goto retry_2;
if (rename(tmpfilename, spoolfilename) == -1)
goto retry_2;
break;
retry_3:
fclose(out);
retry_2:
free(tmpfilename);
retry_1:
sleep(10);
}
return 0;
}