1/* Author: Makarius 2 3Bash process with separate process group id. 4*/ 5 6#include <signal.h> 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <sys/resource.h> 11#include <sys/time.h> 12#include <sys/types.h> 13#include <sys/wait.h> 14#include <time.h> 15#include <unistd.h> 16 17static void fail(const char *msg) 18{ 19 fprintf(stderr, "%s\n", msg); 20 fflush(stderr); 21 exit(2); 22} 23 24static time_t now() 25{ 26 struct timeval tv; 27 if (gettimeofday(&tv, NULL) == 0) { 28 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 29 } 30 else { 31 return time(NULL) * 1000; 32 } 33} 34 35 36int main(int argc, char *argv[]) 37{ 38 /* args */ 39 40 if (argc < 3) { 41 fprintf(stderr, "Bad arguments: PID_FILE and TIMING_FILE required\n"); 42 fflush(stderr); 43 exit(1); 44 } 45 char *pid_name = argv[1]; 46 char *timing_name = argv[2]; 47 48 49 /* potential fork */ 50 51 time_t time_start = now(); 52 53 if (strlen(timing_name) > 0 || setsid() == -1) { 54 pid_t pid = fork(); 55 56 if (pid == -1) fail("Cannot set session id (failed to fork)"); 57 else if (pid != 0) { 58 int status; 59 60 // ingore SIGINT 61 struct sigaction sa; 62 memset(&sa, 0, sizeof(sa)); 63 sa.sa_handler = SIG_IGN; 64 sigaction(SIGINT, &sa, 0); 65 66 if (waitpid(pid, &status, 0) == -1) { 67 fail("Cannot join forked process"); 68 } 69 70 /* report timing */ 71 72 if (strlen(timing_name) > 0) { 73 long long timing_elapsed = now() - time_start; 74 75 struct rusage ru; 76 getrusage(RUSAGE_CHILDREN, &ru); 77 78 long long timing_cpu = 79 ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000 + 80 ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000; 81 82 FILE *timing_file = fopen(timing_name, "w"); 83 if (timing_file == NULL) fail("Cannot open timing file"); 84 fprintf(timing_file, "%lld %lld", timing_elapsed, timing_cpu); 85 fclose(timing_file); 86 } 87 88 if (WIFEXITED(status)) { 89 exit(WEXITSTATUS(status)); 90 } 91 else if (WIFSIGNALED(status)) { 92 exit(128 + WTERMSIG(status)); 93 } 94 else { 95 fail("Unknown status of forked process"); 96 } 97 } 98 else if (setsid() == -1) fail("Cannot set session id (after fork)"); 99 } 100 101 102 /* report pid */ 103 104 if (strcmp(pid_name, "-") == 0) { 105 fprintf(stdout, "%d\n", getpid()); 106 fflush(stdout); 107 } 108 else if (strlen(pid_name) > 0) { 109 FILE *pid_file; 110 pid_file = fopen(pid_name, "w"); 111 if (pid_file == NULL) fail("Cannot open pid file"); 112 fprintf(pid_file, "%d", getpid()); 113 fclose(pid_file); 114 } 115 116 117 /* shift command line */ 118 119 int i; 120 for (i = 3; i < argc; i++) { 121 argv[i - 3] = argv[i]; 122 } 123 argv[argc - 3] = NULL; 124 argv[argc - 2] = NULL; 125 argv[argc - 1] = NULL; 126 127 128 /* exec */ 129 130 execvp("bash", argv); 131 fail("Cannot exec process"); 132} 133