Permalink
Cannot retrieve contributors at this time
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?
mxq/mxq_reaper.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
126 lines (113 sloc)
3.52 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |