1 /*
   2  * undef USE_JOB_CONTROL on systems less than 2000,XP
   3  * These systems don't support this API, but as a consequence,
   4  * the running time won't be limited.
   5  */
   6 #define USE_JOB_CONTROL
   7 
   8 /* This program is licensed under GPL v2.
   9 	Written by:
  10 		Johannes Berg
  11 		Alexander Schremmer
  12 */
  13 
  14 /* Usage:
  15 runlimit CPUTIME DIRECTORY EXECUTABLE [OPTS]
  16 	This will run "EXECUTABLE OPTS" in the directory DIRECTORY.
  17 	The process will be killed if it does not terminate in CPUTIME seconds.
  18 */
  19 
  20 
  21 int main(int argc, char** argv) {
  22 	char cmdlinebuffer[CMDLINE_MAX], cmdlinebuffer2[CMDLINE_MAX];
  23 	char* cmdline = NULL;
  24 
  25 	STARTUPINFO startupinfo;
  26 	PROCESS_INFORMATION processinfo;
  27 	DWORD exitcode;
  28 	unsigned int joblimit; /* need to parse parameter even if not using job limits */
  29 #ifdef USE_JOB_CONTROL
  30 	JOBOBJECT_BASIC_LIMIT_INFORMATION lpJobObjectInfo;
  31 	DWORD cbJobObjectInfoLength = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
  32 	LARGE_INTEGER large_int;
  33 
  34 	lpJobObjectInfo.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_TIME;
  35 
  36 	HANDLE job = CreateJobObject(NULL, NULL);
  37 
  38 	if (job == NULL) {
  39 		fprintf(stderr, "Failed to create job object\n");
  40 		return 2;
  41 	}
  42 #endif
  43 	startupinfo.cb = sizeof(STARTUPINFO);
  44 	startupinfo.lpReserved=NULL;
  45 	startupinfo.lpDesktop=NULL;
  46 	startupinfo.lpTitle=NULL;
  47 	startupinfo.dwFlags=0;
  48 	startupinfo.wShowWindow=0;
  49 	startupinfo.cbReserved2=0;
  50 	startupinfo.lpReserved2=NULL;
  51 
  52 	cmdlinebuffer[0] = '\0';
  53 
  54 	_dup2(1,2);
  55 
  56 	if (argc < 3)
  57 		return 2; /* bah. nothing to do */
  58 
  59 	joblimit = atoi(argv[1]);
  60 	if (!joblimit)
  61 		return 2;
  62 
  63 
  64 #ifdef USE_JOB_CONTROL
  65 	large_int.QuadPart = 10000000 * joblimit;
  66 	lpJobObjectInfo.PerProcessUserTimeLimit = large_int; 
  67 #endif
  68 
  69 	if (argc > 3) {
  70                 _snprintf(cmdlinebuffer, CMDLINE_MAX-1, "\"%s\"", argv[3]);
  71 		for (int i = 4; i < argc; i++) {
  72                         memcpy(cmdlinebuffer2, cmdlinebuffer, CMDLINE_MAX);
  73 			_snprintf(cmdlinebuffer, CMDLINE_MAX-1, "%s \"%s\"", cmdlinebuffer2, argv[i]);
  74 		}
  75 		cmdline = &cmdlinebuffer[0];
  76 	}
  77 	if (!CreateProcess (NULL, 
  78 		cmdline, 
  79 		NULL, 
  80 		NULL, 
  81 		FALSE, 
  82 		CREATE_BREAKAWAY_FROM_JOB,
  83 		NULL, 
  84 		argv[2], 
  85 		&startupinfo, 
  86 		&processinfo)) {
  87 			fprintf(stderr, "CreateProcess failed: %i\n", GetLastError());
  88 			return 2;
  89 	} else {
  90 		CloseHandle(processinfo.hThread);
  91 	}
  92 
  93 #ifdef USE_JOB_CONTROL
  94 	if (!SetInformationJobObject(job, JobObjectBasicLimitInformation,
  95 		&lpJobObjectInfo, cbJobObjectInfoLength)) {
  96 			fprintf(stderr, "SetInformationJobObject failed, process running uncontrolled!\n");
  97 	}
  98 
  99 	if (!AssignProcessToJobObject(job, processinfo.hProcess)) {
 100 		fprintf(stderr, "AssignProcessToJobObject failed, process running uncontrolled!\n");
 101 	}
 102 #endif
 103 
 104 	if (WaitForSingleObject(processinfo.hProcess, INFINITE) == WAIT_FAILED) {
 105 		fprintf(stderr, "WaitForSingleObject failed with code %d\n", GetLastError());
 106 	}
 107 	if (!GetExitCodeProcess(processinfo.hProcess, &exitcode)) {
 108 		fprintf(stderr, "GetExitCodeProcess failed with %d\n", GetLastError());
 109                 exitcode = 2;
 110 	}
 111 
 112 	CloseHandle(processinfo.hProcess);
 113 #ifdef USE_JOB_CONTROL
 114 	CloseHandle(job);
 115 #endif
 116 	return exitcode;
 117 }