59 static int verbose= 0;
60 static char safe_process_name[32]= {0};
67 fprintf(stderr,
"%s: ", safe_process_name);
69 vfprintf(stderr, fmt, args);
70 fprintf(stderr,
"\n");
76 static void die(
const char* fmt, ...)
78 DWORD last_err= GetLastError();
80 fprintf(stderr,
"%s: FATAL ERROR, ", safe_process_name);
82 vfprintf(stderr, fmt, args);
83 fprintf(stderr,
"\n");
88 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
89 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_err , 0, (LPSTR)&message_text,
92 fprintf(stderr,
"error: %d, %s\n",last_err, message_text);
93 LocalFree(message_text);
98 fprintf(stderr,
"error:%d\n", last_err);
106 DWORD get_parent_pid(DWORD pid)
109 DWORD parent_pid= -1;
111 pe32.dwSize=
sizeof(PROCESSENTRY32);
113 snapshot= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
114 if (snapshot == INVALID_HANDLE_VALUE)
115 die(
"CreateToolhelp32Snapshot failed");
117 if (!Process32First(snapshot, &pe32))
119 CloseHandle(snapshot);
120 die(
"Process32First failed");
125 if (pe32.th32ProcessID == pid)
126 parent_pid= pe32.th32ParentProcessID;
127 }
while(Process32Next( snapshot, &pe32));
128 CloseHandle(snapshot);
130 if (parent_pid == -1)
131 die(
"Could not find parent pid");
145 HANDLE shutdown_event;
146 void handle_signal (
int signal)
148 message(
"Got signal: %d", signal);
149 if(SetEvent(shutdown_event) == 0) {
151 die(
"Failed to SetEvent");
156 int main(
int argc,
const char** argv )
158 char child_args[4096]= {0};
159 DWORD pid= GetCurrentProcessId();
160 DWORD parent_pid= get_parent_pid(pid);
162 HANDLE wait_handles[NUM_HANDLES]= {0};
163 PROCESS_INFORMATION process_info= {0};
166 sprintf(safe_process_name,
"safe_process[%d]", pid);
170 CreateEvent(NULL, TRUE, FALSE, safe_process_name)) == NULL)
171 die(
"Failed to create shutdown_event");
172 wait_handles[EVENT]= shutdown_event;
174 signal(SIGINT, handle_signal);
175 signal(SIGBREAK, handle_signal);
176 signal(SIGTERM, handle_signal);
181 for (
int i= 1;
i < argc;
i++) {
182 const char* arg= argv[
i];
183 char*
to= child_args;
184 if (strcmp(arg,
"--") == 0 && strlen(arg) == 2) {
187 die(
"No real args -> nothing to do");
189 for (
int j=
i+1; j < argc; j++) {
191 if (strchr (arg,
' ') &&
193 arg[strlen(arg)] !=
'\"')
196 to+= _snprintf(to, child_args +
sizeof(child_args) - to,
201 to+= _snprintf(to, child_args +
sizeof(child_args) - to,
207 if (strcmp(arg,
"--verbose") == 0)
209 else if (strncmp(arg,
"--parent-pid", 10) == 0)
213 if ((start= strstr(arg,
"=")) == NULL)
214 die(
"Could not find start of option value in '%s'", arg);
216 if ((parent_pid= atoi(start)) == 0)
217 die(
"Invalid value '%s' passed to --parent-id", start);
219 else if (strcmp(arg,
"--nocore") == 0)
223 else if ( strncmp (arg,
"--env ", 6) == 0 )
225 putenv(strdup(arg+6));
228 die(
"Unknown option: %s", arg);
231 if (*child_args ==
'\0')
232 die(
"nothing to do");
235 message(
"parent_pid: %d", parent_pid);
236 if (parent_pid == pid)
237 die(
"parent_pid is equal to own pid!");
239 if ((wait_handles[PARENT]=
240 OpenProcess(SYNCHRONIZE, FALSE, parent_pid)) == NULL)
241 die(
"Failed to open parent process with pid: %d", parent_pid);
244 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
245 STARTUPINFO si = { 0 };
252 if ((job_handle= CreateJobObject(NULL, NULL)) == NULL)
253 die(
"CreateJobObject failed");
259 #ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
260 #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
263 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
264 if (SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation,
265 &jeli,
sizeof(jeli)) == 0)
266 message(
"SetInformationJobObject failed, continue anyway...");
270 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX
271 | SEM_NOOPENFILEERRORBOX);
275 si.dwFlags= STARTF_USESTDHANDLES;
276 si.hStdInput= GetStdHandle(STD_INPUT_HANDLE);
277 si.hStdOutput= GetStdHandle(STD_OUTPUT_HANDLE);
278 si.hStdError= GetStdHandle(STD_ERROR_HANDLE);
297 DWORD create_flags[]= {CREATE_BREAKAWAY_FROM_JOB, CREATE_NEW_PROCESS_GROUP, 0};
298 BOOL process_created= FALSE;
299 BOOL jobobject_assigned= FALSE;
301 for (
int i=0;
i <
sizeof(create_flags)/
sizeof(create_flags[0]);
i++)
303 process_created= CreateProcess(NULL, (LPSTR)child_args,
307 CREATE_SUSPENDED | create_flags[
i],
314 jobobject_assigned= AssignProcessToJobObject(job_handle, process_info.hProcess);
319 if (!process_created)
321 die(
"CreateProcess failed");
323 ResumeThread(process_info.hThread);
324 CloseHandle(process_info.hThread);
326 wait_handles[CHILD]= process_info.hProcess;
328 message(
"Started child %d", process_info.dwProcessId);
331 DWORD child_exit_code= 1;
332 DWORD wait_res= WaitForMultipleObjects(NUM_HANDLES, wait_handles,
336 case WAIT_OBJECT_0 + PARENT:
339 case WAIT_OBJECT_0 + CHILD:
340 if (GetExitCodeProcess(wait_handles[CHILD], &child_exit_code) == 0)
341 message(
"Child exit: could not get exit_code");
343 message(
"Child exit: exit_code: %d", child_exit_code);
345 case WAIT_OBJECT_0 + EVENT:
346 message(
"Wake up from shutdown_event");
350 message(
"Unexpected result %d from WaitForMultipleObjects", wait_res);
353 message(
"Exiting, child: %d", process_info.dwProcessId);
355 if (TerminateJobObject(job_handle, 201) == 0)
356 message(
"TerminateJobObject failed");
357 CloseHandle(job_handle);
358 message(
"Job terminated and closed");
360 if (!jobobject_assigned)
362 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, process_info.dwProcessId);
363 TerminateProcess(process_info.hProcess, 202);
366 if (wait_res != WAIT_OBJECT_0 + CHILD)
369 message(
"waiting for child to exit");
370 if ((wait_res= WaitForSingleObject(wait_handles[CHILD], INFINITE))
373 message(
"child wait failed: %d", wait_res);
377 message(
"child wait succeeded");
383 for (
int i= 0;
i < NUM_HANDLES;
i++)
384 CloseHandle(wait_handles[
i]);
386 message(
"Exiting, exit_code: %d", child_exit_code);
387 exit(child_exit_code);