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