1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
3 #include "kwsysPrivate.h"
4 #include KWSYS_HEADER(Process.h)
5 #include KWSYS_HEADER(Encoding.h)
6
7 /* Work-around CMake dependency scanning limitation. This must
8 duplicate the above list of headers. */
9 #if 0
10 #include "Encoding.h.in"
11 #include "Process.h.in"
12 #endif
13
14 /*
15
16 Implementation for Windows
17
18 On windows, a thread is created to wait for data on each pipe. The
19 threads are synchronized with the main thread to simulate the use of
20 a UNIX-style select system call.
21
22 */
23
24 #ifdef _MSC_VER
25 #pragma warning(push, 1)
26 #endif
27 #include <windows.h> /* Windows API */
28 #if defined(_MSC_VER) && _MSC_VER >= 1800
29 #define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
30 #endif
31 #include <io.h> /* _unlink */
32 #include <stdio.h> /* sprintf */
33 #include <string.h> /* strlen, strdup */
34 #ifdef __WATCOMC__
35 #define _unlink unlink
36 #endif
37
38 #ifndef _MAX_FNAME
39 #define _MAX_FNAME 4096
40 #endif
41 #ifndef _MAX_PATH
42 #define _MAX_PATH 4096
43 #endif
44
45 #ifdef _MSC_VER
46 #pragma warning(pop)
47 #pragma warning(disable : 4514)
48 #pragma warning(disable : 4706)
49 #endif
50
51 #if defined(__BORLANDC__)
52 #pragma warn - 8004 /* assigned a value that is never used */
53 #pragma warn - 8060 /* Assignment inside if() condition. */
54 #endif
55
56 /* There are pipes for the process pipeline's stdout and stderr. */
57 #define KWSYSPE_PIPE_COUNT 2
58 #define KWSYSPE_PIPE_STDOUT 0
59 #define KWSYSPE_PIPE_STDERR 1
60
61 /* The maximum amount to read from a pipe at a time. */
62 #define KWSYSPE_PIPE_BUFFER_SIZE 1024
63
64 /* Debug output macro. */
65 #if 0
66 #define KWSYSPE_DEBUG(x) \
67 ((void*)cp == (void*)0x00226DE0 \
68 ? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp, \
69 __LINE__), \
70 fprintf x, fflush(stderr), 1) \
71 : (1))
72 #else
73 #define KWSYSPE_DEBUG(x) (void)1
74 #endif
75
76 typedef LARGE_INTEGER kwsysProcessTime;
77
78 typedef struct kwsysProcessCreateInformation_s
79 {
80 /* Windows child startup control data. */
81 STARTUPINFOW StartupInfo;
82
83 /* Original handles before making inherited duplicates. */
84 HANDLE hStdInput;
85 HANDLE hStdOutput;
86 HANDLE hStdError;
87 } kwsysProcessCreateInformation;
88
89 typedef struct kwsysProcessPipeData_s kwsysProcessPipeData;
90 static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd);
91 static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp,
92 kwsysProcessPipeData* td);
93 static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd);
94 static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
95 kwsysProcessPipeData* td);
96 static int kwsysProcessInitialize(kwsysProcess* cp);
97 static DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
98 kwsysProcessCreateInformation* si);
99 static void kwsysProcessDestroy(kwsysProcess* cp, int event);
100 static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
101 static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
102 static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle);
103 static void kwsysProcessCleanupHandle(PHANDLE h);
104 static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error);
105 static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
106 static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
107 kwsysProcessTime* timeoutTime);
108 static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
109 double* userTimeout,
110 kwsysProcessTime* timeoutLength);
111 static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
112 static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t);
113 static double kwsysProcessTimeToDouble(kwsysProcessTime t);
114 static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
115 static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
116 static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
117 kwsysProcessTime in2);
118 static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
119 kwsysProcessTime in2);
120 static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
121 static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code,
122 int idx);
123 static void kwsysProcessKillTree(int pid);
124 static void kwsysProcessDisablePipeThreads(kwsysProcess* cp);
125 static int kwsysProcessesInitialize(void);
126 static int kwsysTryEnterCreateProcessSection(void);
127 static void kwsysLeaveCreateProcessSection(void);
128 static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId,
129 int newProcessGroup);
130 static void kwsysProcessesRemove(HANDLE hProcess);
131 static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType);
132
133 /* A structure containing synchronization data for each thread. */
134 typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync;
135 struct kwsysProcessPipeSync_s
136 {
137 /* Handle to the thread. */
138 HANDLE Thread;
139
140 /* Semaphore indicating to the thread that a process has started. */
141 HANDLE Ready;
142
143 /* Semaphore indicating to the thread that it should begin work. */
144 HANDLE Go;
145
146 /* Semaphore indicating thread has reset for another process. */
147 HANDLE Reset;
148 };
149
150 /* A structure containing data for each pipe's threads. */
151 struct kwsysProcessPipeData_s
152 {
153 /* ------------- Data managed per instance of kwsysProcess ------------- */
154
155 /* Synchronization data for reading thread. */
156 kwsysProcessPipeSync Reader;
157
158 /* Synchronization data for waking thread. */
159 kwsysProcessPipeSync Waker;
160
161 /* Index of this pipe. */
162 int Index;
163
164 /* The kwsysProcess instance owning this pipe. */
165 kwsysProcess* Process;
166
167 /* ------------- Data managed per call to Execute ------------- */
168
169 /* Buffer for data read in this pipe's thread. */
170 char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
171
172 /* The length of the data stored in the buffer. */
173 DWORD DataLength;
174
175 /* Whether the pipe has been closed. */
176 int Closed;
177
178 /* Handle for the read end of this pipe. */
179 HANDLE Read;
180
181 /* Handle for the write end of this pipe. */
182 HANDLE Write;
183 };
184
185 /* A structure containing results data for each process. */
186 typedef struct kwsysProcessResults_s kwsysProcessResults;
187 struct kwsysProcessResults_s
188 {
189 /* The status of the process. */
190 int State;
191
192 /* The exceptional behavior that terminated the process, if any. */
193 int ExitException;
194
195 /* The process exit code. */
196 DWORD ExitCode;
197
198 /* The process return code, if any. */
199 int ExitValue;
200
201 /* Description for the ExitException. */
202 char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1];
203 };
204
205 /* Structure containing data used to implement the child's execution. */
206 struct kwsysProcess_s
207 {
208 /* ------------- Data managed per instance of kwsysProcess ------------- */
209
210 /* The status of the process structure. */
211 int State;
212
213 /* The command lines to execute. */
214 wchar_t** Commands;
215 int NumberOfCommands;
216
217 /* The exit code of each command. */
218 DWORD* CommandExitCodes;
219
220 /* The working directory for the child process. */
221 wchar_t* WorkingDirectory;
222
223 /* Whether to create the child as a detached process. */
224 int OptionDetach;
225
226 /* Whether the child was created as a detached process. */
227 int Detached;
228
229 /* Whether to hide the child process's window. */
230 int HideWindow;
231
232 /* Whether to treat command lines as verbatim. */
233 int Verbatim;
234
235 /* Whether to merge stdout/stderr of the child. */
236 int MergeOutput;
237
238 /* Whether to create the process in a new process group. */
239 int CreateProcessGroup;
240
241 /* Mutex to protect the shared index used by threads to report data. */
242 HANDLE SharedIndexMutex;
243
244 /* Semaphore used by threads to signal data ready. */
245 HANDLE Full;
246
247 /* Whether we are currently deleting this kwsysProcess instance. */
248 int Deleting;
249
250 /* Data specific to each pipe and its thread. */
251 kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
252
253 /* Name of files to which stdin and stdout pipes are attached. */
254 char* PipeFileSTDIN;
255 char* PipeFileSTDOUT;
256 char* PipeFileSTDERR;
257
258 /* Whether each pipe is shared with the parent process. */
259 int PipeSharedSTDIN;
260 int PipeSharedSTDOUT;
261 int PipeSharedSTDERR;
262
263 /* Native pipes provided by the user. */
264 HANDLE PipeNativeSTDIN[2];
265 HANDLE PipeNativeSTDOUT[2];
266 HANDLE PipeNativeSTDERR[2];
267
268 /* ------------- Data managed per call to Execute ------------- */
269
270 /* Index of last pipe to report data, if any. */
271 int CurrentIndex;
272
273 /* Index shared by threads to report data. */
274 int SharedIndex;
275
276 /* The timeout length. */
277 double Timeout;
278
279 /* Time at which the child started. */
280 kwsysProcessTime StartTime;
281
282 /* Time at which the child will timeout. Negative for no timeout. */
283 kwsysProcessTime TimeoutTime;
284
285 /* Flag for whether the process was killed. */
286 int Killed;
287
288 /* Flag for whether the timeout expired. */
289 int TimeoutExpired;
290
291 /* Flag for whether the process has terminated. */
292 int Terminated;
293
294 /* The number of pipes still open during execution and while waiting
295 for pipes to close after process termination. */
296 int PipesLeft;
297
298 /* Buffer for error messages. */
299 char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1];
300
301 /* process results. */
302 kwsysProcessResults* ProcessResults;
303
304 /* Windows process information data. */
305 PROCESS_INFORMATION* ProcessInformation;
306
307 /* Data and process termination events for which to wait. */
308 PHANDLE ProcessEvents;
309 int ProcessEventsLength;
310
311 /* Real working directory of our own process. */
312 DWORD RealWorkingDirectoryLength;
313 wchar_t* RealWorkingDirectory;
314
315 /* Own handles for the child's ends of the pipes in the parent process.
316 Used temporarily during process creation. */
317 HANDLE PipeChildStd[3];
318 };
319
kwsysProcess_New(void)320 kwsysProcess* kwsysProcess_New(void)
321 {
322 int i;
323
324 /* Process control structure. */
325 kwsysProcess* cp;
326
327 /* Windows version number data. */
328 OSVERSIONINFO osv;
329
330 /* Initialize list of processes before we get any farther. It's especially
331 important that the console Ctrl handler be added BEFORE starting the
332 first process. This prevents the risk of an orphaned process being
333 started by the main thread while the default Ctrl handler is in
334 progress. */
335 if (!kwsysProcessesInitialize()) {
336 return 0;
337 }
338
339 /* Allocate a process control structure. */
340 cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
341 if (!cp) {
342 /* Could not allocate memory for the control structure. */
343 return 0;
344 }
345 ZeroMemory(cp, sizeof(*cp));
346
347 /* Share stdin with the parent process by default. */
348 cp->PipeSharedSTDIN = 1;
349
350 /* Set initial status. */
351 cp->State = kwsysProcess_State_Starting;
352
353 /* Choose a method of running the child based on version of
354 windows. */
355 ZeroMemory(&osv, sizeof(osv));
356 osv.dwOSVersionInfoSize = sizeof(osv);
357 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
358 #pragma warning(push)
359 #ifdef __INTEL_COMPILER
360 #pragma warning(disable : 1478)
361 #else
362 #pragma warning(disable : 4996)
363 #endif
364 #endif
365 GetVersionEx(&osv);
366 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
367 #pragma warning(pop)
368 #endif
369 if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
370 /* Win9x no longer supported. */
371 kwsysProcess_Delete(cp);
372 return 0;
373 }
374
375 /* Initially no thread owns the mutex. Initialize semaphore to 1. */
376 if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) {
377 kwsysProcess_Delete(cp);
378 return 0;
379 }
380
381 /* Initially no data are available. Initialize semaphore to 0. */
382 if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) {
383 kwsysProcess_Delete(cp);
384 return 0;
385 }
386
387 /* Create the thread to read each pipe. */
388 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
389 DWORD dummy = 0;
390
391 /* Assign the thread its index. */
392 cp->Pipe[i].Index = i;
393
394 /* Give the thread a pointer back to the kwsysProcess instance. */
395 cp->Pipe[i].Process = cp;
396
397 /* No process is yet running. Initialize semaphore to 0. */
398 if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) {
399 kwsysProcess_Delete(cp);
400 return 0;
401 }
402
403 /* The pipe is not yet reset. Initialize semaphore to 0. */
404 if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) {
405 kwsysProcess_Delete(cp);
406 return 0;
407 }
408
409 /* The thread's buffer is initially empty. Initialize semaphore to 1. */
410 if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) {
411 kwsysProcess_Delete(cp);
412 return 0;
413 }
414
415 /* Create the reading thread. It will block immediately. The
416 thread will not make deeply nested calls, so we need only a
417 small stack. */
418 if (!(cp->Pipe[i].Reader.Thread = CreateThread(
419 0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) {
420 kwsysProcess_Delete(cp);
421 return 0;
422 }
423
424 /* No process is yet running. Initialize semaphore to 0. */
425 if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) {
426 kwsysProcess_Delete(cp);
427 return 0;
428 }
429
430 /* The pipe is not yet reset. Initialize semaphore to 0. */
431 if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) {
432 kwsysProcess_Delete(cp);
433 return 0;
434 }
435
436 /* The waker should not wake immediately. Initialize semaphore to 0. */
437 if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) {
438 kwsysProcess_Delete(cp);
439 return 0;
440 }
441
442 /* Create the waking thread. It will block immediately. The
443 thread will not make deeply nested calls, so we need only a
444 small stack. */
445 if (!(cp->Pipe[i].Waker.Thread = CreateThread(
446 0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) {
447 kwsysProcess_Delete(cp);
448 return 0;
449 }
450 }
451 for (i = 0; i < 3; ++i) {
452 cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
453 }
454
455 return cp;
456 }
457
kwsysProcess_Delete(kwsysProcess * cp)458 void kwsysProcess_Delete(kwsysProcess* cp)
459 {
460 int i;
461
462 /* Make sure we have an instance. */
463 if (!cp) {
464 return;
465 }
466
467 /* If the process is executing, wait for it to finish. */
468 if (cp->State == kwsysProcess_State_Executing) {
469 if (cp->Detached) {
470 kwsysProcess_Disown(cp);
471 } else {
472 kwsysProcess_WaitForExit(cp, 0);
473 }
474 }
475
476 /* We are deleting the kwsysProcess instance. */
477 cp->Deleting = 1;
478
479 /* Terminate each of the threads. */
480 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
481 /* Terminate this reading thread. */
482 if (cp->Pipe[i].Reader.Thread) {
483 /* Signal the thread we are ready for it. It will terminate
484 immediately since Deleting is set. */
485 ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
486
487 /* Wait for the thread to exit. */
488 WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE);
489
490 /* Close the handle to the thread. */
491 kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread);
492 }
493
494 /* Terminate this waking thread. */
495 if (cp->Pipe[i].Waker.Thread) {
496 /* Signal the thread we are ready for it. It will terminate
497 immediately since Deleting is set. */
498 ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
499
500 /* Wait for the thread to exit. */
501 WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE);
502
503 /* Close the handle to the thread. */
504 kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread);
505 }
506
507 /* Cleanup the pipe's semaphores. */
508 kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready);
509 kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go);
510 kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset);
511 kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready);
512 kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go);
513 kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset);
514 }
515
516 /* Close the shared semaphores. */
517 kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
518 kwsysProcessCleanupHandle(&cp->Full);
519
520 /* Free memory. */
521 kwsysProcess_SetCommand(cp, 0);
522 kwsysProcess_SetWorkingDirectory(cp, 0);
523 kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
524 kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
525 kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
526 free(cp->CommandExitCodes);
527 free(cp->ProcessResults);
528 free(cp);
529 }
530
kwsysProcess_SetCommand(kwsysProcess * cp,char const * const * command)531 int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
532 {
533 int i;
534 if (!cp) {
535 return 0;
536 }
537 for (i = 0; i < cp->NumberOfCommands; ++i) {
538 free(cp->Commands[i]);
539 }
540 cp->NumberOfCommands = 0;
541 if (cp->Commands) {
542 free(cp->Commands);
543 cp->Commands = 0;
544 }
545 if (command) {
546 return kwsysProcess_AddCommand(cp, command);
547 }
548 return 1;
549 }
550
kwsysProcess_AddCommand(kwsysProcess * cp,char const * const * command)551 int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
552 {
553 int newNumberOfCommands;
554 wchar_t** newCommands;
555
556 /* Make sure we have a command to add. */
557 if (!cp || !command || !*command) {
558 return 0;
559 }
560
561 /* Allocate a new array for command pointers. */
562 newNumberOfCommands = cp->NumberOfCommands + 1;
563 if (!(newCommands =
564 (wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands))) {
565 /* Out of memory. */
566 return 0;
567 }
568
569 /* Copy any existing commands into the new array. */
570 {
571 int i;
572 for (i = 0; i < cp->NumberOfCommands; ++i) {
573 newCommands[i] = cp->Commands[i];
574 }
575 }
576
577 if (cp->Verbatim) {
578 /* Copy the verbatim command line into the buffer. */
579 newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command);
580 } else {
581 /* Encode the arguments so CommandLineToArgvW can decode
582 them from the command line string in the child. */
583 char buffer[32768]; /* CreateProcess max command-line length. */
584 char* end = buffer + sizeof(buffer);
585 char* out = buffer;
586 char const* const* a;
587 for (a = command; *a; ++a) {
588 int quote = !**a; /* Quote the empty string. */
589 int slashes = 0;
590 char const* c;
591 if (a != command && out != end) {
592 *out++ = ' ';
593 }
594 for (c = *a; !quote && *c; ++c) {
595 quote = (*c == ' ' || *c == '\t');
596 }
597 if (quote && out != end) {
598 *out++ = '"';
599 }
600 for (c = *a; *c; ++c) {
601 if (*c == '\\') {
602 ++slashes;
603 } else {
604 if (*c == '"') {
605 // Add n+1 backslashes to total 2n+1 before internal '"'.
606 while (slashes-- >= 0 && out != end) {
607 *out++ = '\\';
608 }
609 }
610 slashes = 0;
611 }
612 if (out != end) {
613 *out++ = *c;
614 }
615 }
616 if (quote) {
617 // Add n backslashes to total 2n before ending '"'.
618 while (slashes-- > 0 && out != end) {
619 *out++ = '\\';
620 }
621 if (out != end) {
622 *out++ = '"';
623 }
624 }
625 }
626 if (out != end) {
627 *out = '\0';
628 newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer);
629 } else {
630 newCommands[cp->NumberOfCommands] = 0;
631 }
632 }
633 if (!newCommands[cp->NumberOfCommands]) {
634 /* Out of memory or command line too long. */
635 free(newCommands);
636 return 0;
637 }
638
639 /* Save the new array of commands. */
640 free(cp->Commands);
641 cp->Commands = newCommands;
642 cp->NumberOfCommands = newNumberOfCommands;
643 return 1;
644 }
645
kwsysProcess_SetTimeout(kwsysProcess * cp,double timeout)646 void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
647 {
648 if (!cp) {
649 return;
650 }
651 cp->Timeout = timeout;
652 if (cp->Timeout < 0) {
653 cp->Timeout = 0;
654 }
655 // Force recomputation of TimeoutTime.
656 cp->TimeoutTime.QuadPart = -1;
657 }
658
kwsysProcess_SetWorkingDirectory(kwsysProcess * cp,const char * dir)659 int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
660 {
661 if (!cp) {
662 return 0;
663 }
664 if (cp->WorkingDirectory) {
665 free(cp->WorkingDirectory);
666 cp->WorkingDirectory = 0;
667 }
668 if (dir && dir[0]) {
669 wchar_t* wdir = kwsysEncoding_DupToWide(dir);
670 /* We must convert the working directory to a full path. */
671 DWORD length = GetFullPathNameW(wdir, 0, 0, 0);
672 if (length > 0) {
673 wchar_t* work_dir = malloc(length * sizeof(wchar_t));
674 if (!work_dir) {
675 free(wdir);
676 return 0;
677 }
678 if (!GetFullPathNameW(wdir, length, work_dir, 0)) {
679 free(work_dir);
680 free(wdir);
681 return 0;
682 }
683 cp->WorkingDirectory = work_dir;
684 }
685 free(wdir);
686 }
687 return 1;
688 }
689
kwsysProcess_SetPipeFile(kwsysProcess * cp,int pipe,const char * file)690 int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
691 {
692 char** pfile;
693 if (!cp) {
694 return 0;
695 }
696 switch (pipe) {
697 case kwsysProcess_Pipe_STDIN:
698 pfile = &cp->PipeFileSTDIN;
699 break;
700 case kwsysProcess_Pipe_STDOUT:
701 pfile = &cp->PipeFileSTDOUT;
702 break;
703 case kwsysProcess_Pipe_STDERR:
704 pfile = &cp->PipeFileSTDERR;
705 break;
706 default:
707 return 0;
708 }
709 if (*pfile) {
710 free(*pfile);
711 *pfile = 0;
712 }
713 if (file) {
714 *pfile = strdup(file);
715 if (!*pfile) {
716 return 0;
717 }
718 }
719
720 /* If we are redirecting the pipe, do not share it or use a native
721 pipe. */
722 if (*pfile) {
723 kwsysProcess_SetPipeNative(cp, pipe, 0);
724 kwsysProcess_SetPipeShared(cp, pipe, 0);
725 }
726
727 return 1;
728 }
729
kwsysProcess_SetPipeShared(kwsysProcess * cp,int pipe,int shared)730 void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
731 {
732 if (!cp) {
733 return;
734 }
735
736 switch (pipe) {
737 case kwsysProcess_Pipe_STDIN:
738 cp->PipeSharedSTDIN = shared ? 1 : 0;
739 break;
740 case kwsysProcess_Pipe_STDOUT:
741 cp->PipeSharedSTDOUT = shared ? 1 : 0;
742 break;
743 case kwsysProcess_Pipe_STDERR:
744 cp->PipeSharedSTDERR = shared ? 1 : 0;
745 break;
746 default:
747 return;
748 }
749
750 /* If we are sharing the pipe, do not redirect it to a file or use a
751 native pipe. */
752 if (shared) {
753 kwsysProcess_SetPipeFile(cp, pipe, 0);
754 kwsysProcess_SetPipeNative(cp, pipe, 0);
755 }
756 }
757
kwsysProcess_SetPipeNative(kwsysProcess * cp,int pipe,HANDLE p[2])758 void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, HANDLE p[2])
759 {
760 HANDLE* pPipeNative = 0;
761
762 if (!cp) {
763 return;
764 }
765
766 switch (pipe) {
767 case kwsysProcess_Pipe_STDIN:
768 pPipeNative = cp->PipeNativeSTDIN;
769 break;
770 case kwsysProcess_Pipe_STDOUT:
771 pPipeNative = cp->PipeNativeSTDOUT;
772 break;
773 case kwsysProcess_Pipe_STDERR:
774 pPipeNative = cp->PipeNativeSTDERR;
775 break;
776 default:
777 return;
778 }
779
780 /* Copy the native pipe handles provided. */
781 if (p) {
782 pPipeNative[0] = p[0];
783 pPipeNative[1] = p[1];
784 } else {
785 pPipeNative[0] = 0;
786 pPipeNative[1] = 0;
787 }
788
789 /* If we are using a native pipe, do not share it or redirect it to
790 a file. */
791 if (p) {
792 kwsysProcess_SetPipeFile(cp, pipe, 0);
793 kwsysProcess_SetPipeShared(cp, pipe, 0);
794 }
795 }
796
kwsysProcess_GetOption(kwsysProcess * cp,int optionId)797 int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
798 {
799 if (!cp) {
800 return 0;
801 }
802
803 switch (optionId) {
804 case kwsysProcess_Option_Detach:
805 return cp->OptionDetach;
806 case kwsysProcess_Option_HideWindow:
807 return cp->HideWindow;
808 case kwsysProcess_Option_MergeOutput:
809 return cp->MergeOutput;
810 case kwsysProcess_Option_Verbatim:
811 return cp->Verbatim;
812 case kwsysProcess_Option_CreateProcessGroup:
813 return cp->CreateProcessGroup;
814 default:
815 return 0;
816 }
817 }
818
kwsysProcess_SetOption(kwsysProcess * cp,int optionId,int value)819 void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
820 {
821 if (!cp) {
822 return;
823 }
824
825 switch (optionId) {
826 case kwsysProcess_Option_Detach:
827 cp->OptionDetach = value;
828 break;
829 case kwsysProcess_Option_HideWindow:
830 cp->HideWindow = value;
831 break;
832 case kwsysProcess_Option_MergeOutput:
833 cp->MergeOutput = value;
834 break;
835 case kwsysProcess_Option_Verbatim:
836 cp->Verbatim = value;
837 break;
838 case kwsysProcess_Option_CreateProcessGroup:
839 cp->CreateProcessGroup = value;
840 break;
841 default:
842 break;
843 }
844 }
845
kwsysProcess_GetState(kwsysProcess * cp)846 int kwsysProcess_GetState(kwsysProcess* cp)
847 {
848 return cp ? cp->State : kwsysProcess_State_Error;
849 }
850
kwsysProcess_GetExitException(kwsysProcess * cp)851 int kwsysProcess_GetExitException(kwsysProcess* cp)
852 {
853 return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
854 ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException
855 : kwsysProcess_Exception_Other;
856 }
857
kwsysProcess_GetExitValue(kwsysProcess * cp)858 int kwsysProcess_GetExitValue(kwsysProcess* cp)
859 {
860 return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
861 ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue
862 : -1;
863 }
864
kwsysProcess_GetExitCode(kwsysProcess * cp)865 int kwsysProcess_GetExitCode(kwsysProcess* cp)
866 {
867 return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0))
868 ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode
869 : 0;
870 }
871
kwsysProcess_GetErrorString(kwsysProcess * cp)872 const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
873 {
874 if (!cp) {
875 return "Process management structure could not be allocated";
876 } else if (cp->State == kwsysProcess_State_Error) {
877 return cp->ErrorMessage;
878 }
879 return "Success";
880 }
881
kwsysProcess_GetExceptionString(kwsysProcess * cp)882 const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
883 {
884 if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) {
885 return "GetExceptionString called with NULL process management structure";
886 } else if (cp->State == kwsysProcess_State_Exception) {
887 return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString;
888 }
889 return "No exception";
890 }
891
892 /* the index should be in array bound. */
893 #define KWSYSPE_IDX_CHK(RET) \
894 if (!cp || idx >= cp->NumberOfCommands || idx < 0) { \
895 KWSYSPE_DEBUG((stderr, "array index out of bound\n")); \
896 return RET; \
897 }
898
kwsysProcess_GetStateByIndex(kwsysProcess * cp,int idx)899 int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx)
900 {
901 KWSYSPE_IDX_CHK(kwsysProcess_State_Error)
902 return cp->ProcessResults[idx].State;
903 }
904
kwsysProcess_GetExitExceptionByIndex(kwsysProcess * cp,int idx)905 int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx)
906 {
907 KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other)
908 return cp->ProcessResults[idx].ExitException;
909 }
910
kwsysProcess_GetExitValueByIndex(kwsysProcess * cp,int idx)911 int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx)
912 {
913 KWSYSPE_IDX_CHK(-1)
914 return cp->ProcessResults[idx].ExitValue;
915 }
916
kwsysProcess_GetExitCodeByIndex(kwsysProcess * cp,int idx)917 int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx)
918 {
919 KWSYSPE_IDX_CHK(-1)
920 return cp->CommandExitCodes[idx];
921 }
922
kwsysProcess_GetExceptionStringByIndex(kwsysProcess * cp,int idx)923 const char* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx)
924 {
925 KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management "
926 "structure or index out of bound")
927 if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) {
928 return cp->ProcessResults[idx].ExitExceptionString;
929 }
930 return "No exception";
931 }
932
933 #undef KWSYSPE_IDX_CHK
934
kwsysProcess_Execute(kwsysProcess * cp)935 void kwsysProcess_Execute(kwsysProcess* cp)
936 {
937 int i;
938
939 /* Do not execute a second time. */
940 if (!cp || cp->State == kwsysProcess_State_Executing) {
941 return;
942 }
943
944 /* Make sure we have something to run. */
945 if (cp->NumberOfCommands < 1) {
946 strcpy(cp->ErrorMessage, "No command");
947 cp->State = kwsysProcess_State_Error;
948 return;
949 }
950
951 /* Initialize the control structure for a new process. */
952 if (!kwsysProcessInitialize(cp)) {
953 strcpy(cp->ErrorMessage, "Out of memory");
954 cp->State = kwsysProcess_State_Error;
955 return;
956 }
957
958 /* Save the real working directory of this process and change to
959 the working directory for the child processes. This is needed
960 to make pipe file paths evaluate correctly. */
961 if (cp->WorkingDirectory) {
962 if (!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength,
963 cp->RealWorkingDirectory)) {
964 kwsysProcessCleanup(cp, GetLastError());
965 return;
966 }
967 SetCurrentDirectoryW(cp->WorkingDirectory);
968 }
969
970 /* Setup the stdin pipe for the first process. */
971 if (cp->PipeFileSTDIN) {
972 /* Create a handle to read a file for stdin. */
973 wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN);
974 DWORD error;
975 cp->PipeChildStd[0] =
976 CreateFileW(wstdin, GENERIC_READ | GENERIC_WRITE,
977 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
978 error = GetLastError(); /* Check now in case free changes this. */
979 free(wstdin);
980 if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) {
981 kwsysProcessCleanup(cp, error);
982 return;
983 }
984 } else if (cp->PipeSharedSTDIN) {
985 /* Share this process's stdin with the child. */
986 kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]);
987 } else if (cp->PipeNativeSTDIN[0]) {
988 /* Use the provided native pipe. */
989 kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]);
990 } else {
991 /* Explicitly give the child no stdin. */
992 cp->PipeChildStd[0] = INVALID_HANDLE_VALUE;
993 }
994
995 /* Create the output pipe for the last process.
996 We always create this so the pipe thread can run even if we
997 do not end up giving the write end to the child below. */
998 if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read,
999 &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) {
1000 kwsysProcessCleanup(cp, GetLastError());
1001 return;
1002 }
1003
1004 if (cp->PipeFileSTDOUT) {
1005 /* Use a file for stdout. */
1006 DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1],
1007 cp->PipeFileSTDOUT);
1008 if (error) {
1009 kwsysProcessCleanup(cp, error);
1010 return;
1011 }
1012 } else if (cp->PipeSharedSTDOUT) {
1013 /* Use the parent stdout. */
1014 kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]);
1015 } else if (cp->PipeNativeSTDOUT[1]) {
1016 /* Use the given handle for stdout. */
1017 kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]);
1018 } else {
1019 /* Use our pipe for stdout. Duplicate the handle since our waker
1020 thread will use the original. Do not make it inherited yet. */
1021 if (!DuplicateHandle(GetCurrentProcess(),
1022 cp->Pipe[KWSYSPE_PIPE_STDOUT].Write,
1023 GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE,
1024 DUPLICATE_SAME_ACCESS)) {
1025 kwsysProcessCleanup(cp, GetLastError());
1026 return;
1027 }
1028 }
1029
1030 /* Create stderr pipe to be shared by all processes in the pipeline.
1031 We always create this so the pipe thread can run even if we do not
1032 end up giving the write end to the child below. */
1033 if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
1034 &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) {
1035 kwsysProcessCleanup(cp, GetLastError());
1036 return;
1037 }
1038
1039 if (cp->PipeFileSTDERR) {
1040 /* Use a file for stderr. */
1041 DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2],
1042 cp->PipeFileSTDERR);
1043 if (error) {
1044 kwsysProcessCleanup(cp, error);
1045 return;
1046 }
1047 } else if (cp->PipeSharedSTDERR) {
1048 /* Use the parent stderr. */
1049 kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]);
1050 } else if (cp->PipeNativeSTDERR[1]) {
1051 /* Use the given handle for stderr. */
1052 kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]);
1053 } else {
1054 /* Use our pipe for stderr. Duplicate the handle since our waker
1055 thread will use the original. Do not make it inherited yet. */
1056 if (!DuplicateHandle(GetCurrentProcess(),
1057 cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
1058 GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE,
1059 DUPLICATE_SAME_ACCESS)) {
1060 kwsysProcessCleanup(cp, GetLastError());
1061 return;
1062 }
1063 }
1064
1065 /* Create the pipeline of processes. */
1066 {
1067 /* Child startup control data. */
1068 kwsysProcessCreateInformation si;
1069 HANDLE nextStdInput = cp->PipeChildStd[0];
1070
1071 /* Initialize startup info data. */
1072 ZeroMemory(&si, sizeof(si));
1073 si.StartupInfo.cb = sizeof(si.StartupInfo);
1074
1075 /* Decide whether a child window should be shown. */
1076 si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
1077 si.StartupInfo.wShowWindow =
1078 (unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT);
1079
1080 /* Connect the child's output pipes to the threads. */
1081 si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
1082
1083 for (i = 0; i < cp->NumberOfCommands; ++i) {
1084 /* Setup the process's pipes. */
1085 si.hStdInput = nextStdInput;
1086 if (i == cp->NumberOfCommands - 1) {
1087 /* The last child gets the overall stdout. */
1088 nextStdInput = INVALID_HANDLE_VALUE;
1089 si.hStdOutput = cp->PipeChildStd[1];
1090 } else {
1091 /* Create a pipe to sit between the children. */
1092 HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
1093 if (!CreatePipe(&p[0], &p[1], 0, 0)) {
1094 DWORD error = GetLastError();
1095 if (nextStdInput != cp->PipeChildStd[0]) {
1096 kwsysProcessCleanupHandle(&nextStdInput);
1097 }
1098 kwsysProcessCleanup(cp, error);
1099 return;
1100 }
1101 nextStdInput = p[0];
1102 si.hStdOutput = p[1];
1103 }
1104 si.hStdError =
1105 cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2];
1106
1107 {
1108 DWORD error = kwsysProcessCreate(cp, i, &si);
1109
1110 /* Close our copies of pipes used between children. */
1111 if (si.hStdInput != cp->PipeChildStd[0]) {
1112 kwsysProcessCleanupHandle(&si.hStdInput);
1113 }
1114 if (si.hStdOutput != cp->PipeChildStd[1]) {
1115 kwsysProcessCleanupHandle(&si.hStdOutput);
1116 }
1117 if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) {
1118 kwsysProcessCleanupHandle(&si.hStdError);
1119 }
1120 if (!error) {
1121 cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess;
1122 } else {
1123 if (nextStdInput != cp->PipeChildStd[0]) {
1124 kwsysProcessCleanupHandle(&nextStdInput);
1125 }
1126 kwsysProcessCleanup(cp, error);
1127 return;
1128 }
1129 }
1130 }
1131 }
1132
1133 /* The parent process does not need the child's pipe ends. */
1134 for (i = 0; i < 3; ++i) {
1135 kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
1136 }
1137
1138 /* Restore the working directory. */
1139 if (cp->RealWorkingDirectory) {
1140 SetCurrentDirectoryW(cp->RealWorkingDirectory);
1141 free(cp->RealWorkingDirectory);
1142 cp->RealWorkingDirectory = 0;
1143 }
1144
1145 /* The timeout period starts now. */
1146 cp->StartTime = kwsysProcessTimeGetCurrent();
1147 cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
1148
1149 /* All processes in the pipeline have been started in suspended
1150 mode. Resume them all now. */
1151 for (i = 0; i < cp->NumberOfCommands; ++i) {
1152 ResumeThread(cp->ProcessInformation[i].hThread);
1153 }
1154
1155 /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */
1156 /* Tell the pipe threads that a process has started. */
1157 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
1158 ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
1159 ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
1160 }
1161
1162 /* We don't care about the children's main threads. */
1163 for (i = 0; i < cp->NumberOfCommands; ++i) {
1164 kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
1165 }
1166
1167 /* No pipe has reported data. */
1168 cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1169 cp->PipesLeft = KWSYSPE_PIPE_COUNT;
1170
1171 /* The process has now started. */
1172 cp->State = kwsysProcess_State_Executing;
1173 cp->Detached = cp->OptionDetach;
1174 }
1175
kwsysProcess_Disown(kwsysProcess * cp)1176 void kwsysProcess_Disown(kwsysProcess* cp)
1177 {
1178 int i;
1179
1180 /* Make sure we are executing a detached process. */
1181 if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing ||
1182 cp->TimeoutExpired || cp->Killed || cp->Terminated) {
1183 return;
1184 }
1185
1186 /* Disable the reading threads. */
1187 kwsysProcessDisablePipeThreads(cp);
1188
1189 /* Wait for all pipe threads to reset. */
1190 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
1191 WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
1192 WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
1193 }
1194
1195 /* We will not wait for exit, so cleanup now. */
1196 kwsysProcessCleanup(cp, 0);
1197
1198 /* The process has been disowned. */
1199 cp->State = kwsysProcess_State_Disowned;
1200 }
1201
kwsysProcess_WaitForData(kwsysProcess * cp,char ** data,int * length,double * userTimeout)1202 int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
1203 double* userTimeout)
1204 {
1205 kwsysProcessTime userStartTime;
1206 kwsysProcessTime timeoutLength;
1207 kwsysProcessTime timeoutTime;
1208 DWORD timeout;
1209 int user;
1210 int done = 0;
1211 int expired = 0;
1212 int pipeId = kwsysProcess_Pipe_None;
1213 DWORD w;
1214
1215 /* Make sure we are executing a process. */
1216 if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
1217 cp->TimeoutExpired) {
1218 return kwsysProcess_Pipe_None;
1219 }
1220
1221 /* Record the time at which user timeout period starts. */
1222 userStartTime = kwsysProcessTimeGetCurrent();
1223
1224 /* Calculate the time at which a timeout will expire, and whether it
1225 is the user or process timeout. */
1226 user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
1227
1228 /* Loop until we have a reason to return. */
1229 while (!done && cp->PipesLeft > 0) {
1230 /* If we previously got data from a thread, let it know we are
1231 done with the data. */
1232 if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
1233 KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
1234 ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
1235 cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1236 }
1237
1238 /* Setup a timeout if required. */
1239 if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0,
1240 &timeoutLength)) {
1241 /* Timeout has already expired. */
1242 expired = 1;
1243 break;
1244 }
1245 if (timeoutTime.QuadPart < 0) {
1246 timeout = INFINITE;
1247 } else {
1248 timeout = kwsysProcessTimeToDWORD(timeoutLength);
1249 }
1250
1251 /* Wait for a pipe's thread to signal or a process to terminate. */
1252 w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0,
1253 timeout);
1254 if (w == WAIT_TIMEOUT) {
1255 /* Timeout has expired. */
1256 expired = 1;
1257 done = 1;
1258 } else if (w == WAIT_OBJECT_0) {
1259 /* Save the index of the reporting thread and release the mutex.
1260 The thread will block until we signal its Empty mutex. */
1261 cp->CurrentIndex = cp->SharedIndex;
1262 ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
1263
1264 /* Data are available or a pipe closed. */
1265 if (cp->Pipe[cp->CurrentIndex].Closed) {
1266 /* The pipe closed at the write end. Close the read end and
1267 inform the wakeup thread it is done with this process. */
1268 kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
1269 ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0);
1270 KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex));
1271 --cp->PipesLeft;
1272 } else if (data && length) {
1273 /* Report this data. */
1274 *data = cp->Pipe[cp->CurrentIndex].DataBuffer;
1275 *length = cp->Pipe[cp->CurrentIndex].DataLength;
1276 switch (cp->CurrentIndex) {
1277 case KWSYSPE_PIPE_STDOUT:
1278 pipeId = kwsysProcess_Pipe_STDOUT;
1279 break;
1280 case KWSYSPE_PIPE_STDERR:
1281 pipeId = kwsysProcess_Pipe_STDERR;
1282 break;
1283 }
1284 done = 1;
1285 }
1286 } else {
1287 /* A process has terminated. */
1288 kwsysProcessDestroy(cp, w - WAIT_OBJECT_0);
1289 }
1290 }
1291
1292 /* Update the user timeout. */
1293 if (userTimeout) {
1294 kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
1295 kwsysProcessTime difference =
1296 kwsysProcessTimeSubtract(userEndTime, userStartTime);
1297 double d = kwsysProcessTimeToDouble(difference);
1298 *userTimeout -= d;
1299 if (*userTimeout < 0) {
1300 *userTimeout = 0;
1301 }
1302 }
1303
1304 /* Check what happened. */
1305 if (pipeId) {
1306 /* Data are ready on a pipe. */
1307 return pipeId;
1308 } else if (expired) {
1309 /* A timeout has expired. */
1310 if (user) {
1311 /* The user timeout has expired. It has no time left. */
1312 return kwsysProcess_Pipe_Timeout;
1313 } else {
1314 /* The process timeout has expired. Kill the child now. */
1315 KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n"));
1316 kwsysProcess_Kill(cp);
1317 cp->TimeoutExpired = 1;
1318 cp->Killed = 0;
1319 return kwsysProcess_Pipe_None;
1320 }
1321 } else {
1322 /* The children have terminated and no more data are available. */
1323 return kwsysProcess_Pipe_None;
1324 }
1325 }
1326
kwsysProcess_WaitForExit(kwsysProcess * cp,double * userTimeout)1327 int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
1328 {
1329 int i;
1330 int pipe;
1331
1332 /* Make sure we are executing a process. */
1333 if (!cp || cp->State != kwsysProcess_State_Executing) {
1334 return 1;
1335 }
1336
1337 /* Wait for the process to terminate. Ignore all data. */
1338 while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) {
1339 if (pipe == kwsysProcess_Pipe_Timeout) {
1340 /* The user timeout has expired. */
1341 return 0;
1342 }
1343 }
1344
1345 KWSYSPE_DEBUG((stderr, "no more data\n"));
1346
1347 /* When the last pipe closes in WaitForData, the loop terminates
1348 without releasing the pipe's thread. Release it now. */
1349 if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
1350 KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
1351 ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
1352 cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1353 }
1354
1355 /* Wait for all pipe threads to reset. */
1356 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
1357 KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i));
1358 WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
1359 KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i));
1360 WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
1361 }
1362
1363 /* ---- It is now safe again to call kwsysProcessCleanup. ----- */
1364 /* Close all the pipes. */
1365 kwsysProcessCleanup(cp, 0);
1366
1367 /* Determine the outcome. */
1368 if (cp->Killed) {
1369 /* We killed the child. */
1370 cp->State = kwsysProcess_State_Killed;
1371 } else if (cp->TimeoutExpired) {
1372 /* The timeout expired. */
1373 cp->State = kwsysProcess_State_Expired;
1374 } else {
1375 /* The children exited. Report the outcome of the child processes. */
1376 for (i = 0; i < cp->NumberOfCommands; ++i) {
1377 cp->ProcessResults[i].ExitCode = cp->CommandExitCodes[i];
1378 if ((cp->ProcessResults[i].ExitCode & 0xF0000000) == 0xC0000000) {
1379 /* Child terminated due to exceptional behavior. */
1380 cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exception;
1381 cp->ProcessResults[i].ExitValue = 1;
1382 kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode,
1383 i);
1384 } else {
1385 /* Child exited without exception. */
1386 cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exited;
1387 cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None;
1388 cp->ProcessResults[i].ExitValue = cp->ProcessResults[i].ExitCode;
1389 }
1390 }
1391 /* support legacy state status value */
1392 cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State;
1393 }
1394
1395 return 1;
1396 }
1397
kwsysProcess_Interrupt(kwsysProcess * cp)1398 void kwsysProcess_Interrupt(kwsysProcess* cp)
1399 {
1400 int i;
1401 /* Make sure we are executing a process. */
1402 if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
1403 cp->Killed) {
1404 KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n"));
1405 return;
1406 }
1407
1408 /* Skip actually interrupting the child if it has already terminated. */
1409 if (cp->Terminated) {
1410 KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n"));
1411 return;
1412 }
1413
1414 /* Interrupt the children. */
1415 if (cp->CreateProcessGroup) {
1416 if (cp->ProcessInformation) {
1417 for (i = 0; i < cp->NumberOfCommands; ++i) {
1418 /* Make sure the process handle isn't closed (e.g. from disowning). */
1419 if (cp->ProcessInformation[i].hProcess) {
1420 /* The user created a process group for this process. The group ID
1421 is the process ID for the original process in the group. Note
1422 that we have to use Ctrl+Break: Ctrl+C is not allowed for process
1423 groups. */
1424 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
1425 cp->ProcessInformation[i].dwProcessId);
1426 }
1427 }
1428 }
1429 } else {
1430 /* No process group was created. Kill our own process group... */
1431 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0);
1432 }
1433 }
1434
kwsysProcess_Kill(kwsysProcess * cp)1435 void kwsysProcess_Kill(kwsysProcess* cp)
1436 {
1437 int i;
1438 /* Make sure we are executing a process. */
1439 if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
1440 cp->Killed) {
1441 KWSYSPE_DEBUG((stderr, "kill: child not executing\n"));
1442 return;
1443 }
1444
1445 /* Disable the reading threads. */
1446 KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n"));
1447 kwsysProcessDisablePipeThreads(cp);
1448
1449 /* Skip actually killing the child if it has already terminated. */
1450 if (cp->Terminated) {
1451 KWSYSPE_DEBUG((stderr, "kill: child already terminated\n"));
1452 return;
1453 }
1454
1455 /* Kill the children. */
1456 cp->Killed = 1;
1457 for (i = 0; i < cp->NumberOfCommands; ++i) {
1458 kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
1459 /* Remove from global list of processes and close handles. */
1460 kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
1461 kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
1462 kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
1463 }
1464
1465 /* We are killing the children and ignoring all data. Do not wait
1466 for them to exit. */
1467 }
1468
kwsysProcess_KillPID(unsigned long process_id)1469 void kwsysProcess_KillPID(unsigned long process_id)
1470 {
1471 kwsysProcessKillTree((DWORD)process_id);
1472 }
1473
1474 /*
1475 Function executed for each pipe's thread. Argument is a pointer to
1476 the kwsysProcessPipeData instance for this thread.
1477 */
kwsysProcessPipeThreadRead(LPVOID ptd)1478 DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd)
1479 {
1480 kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
1481 kwsysProcess* cp = td->Process;
1482
1483 /* Wait for a process to be ready. */
1484 while ((WaitForSingleObject(td->Reader.Ready, INFINITE), !cp->Deleting)) {
1485 /* Read output from the process for this thread's pipe. */
1486 kwsysProcessPipeThreadReadPipe(cp, td);
1487
1488 /* Signal the main thread we have reset for a new process. */
1489 ReleaseSemaphore(td->Reader.Reset, 1, 0);
1490 }
1491 return 0;
1492 }
1493
1494 /*
1495 Function called in each pipe's thread to handle data for one
1496 execution of a subprocess.
1497 */
kwsysProcessPipeThreadReadPipe(kwsysProcess * cp,kwsysProcessPipeData * td)1498 void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td)
1499 {
1500 /* Wait for space in the thread's buffer. */
1501 while ((KWSYSPE_DEBUG((stderr, "wait for read %d\n", td->Index)),
1502 WaitForSingleObject(td->Reader.Go, INFINITE), !td->Closed)) {
1503 KWSYSPE_DEBUG((stderr, "reading %d\n", td->Index));
1504
1505 /* Read data from the pipe. This may block until data are available. */
1506 if (!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE,
1507 &td->DataLength, 0)) {
1508 if (GetLastError() != ERROR_BROKEN_PIPE) {
1509 /* UNEXPECTED failure to read the pipe. */
1510 }
1511
1512 /* The pipe closed. There are no more data to read. */
1513 td->Closed = 1;
1514 KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index));
1515 }
1516
1517 KWSYSPE_DEBUG((stderr, "read %d\n", td->Index));
1518
1519 /* Wait for our turn to be handled by the main thread. */
1520 WaitForSingleObject(cp->SharedIndexMutex, INFINITE);
1521
1522 KWSYSPE_DEBUG((stderr, "reporting read %d\n", td->Index));
1523
1524 /* Tell the main thread we have something to report. */
1525 cp->SharedIndex = td->Index;
1526 ReleaseSemaphore(cp->Full, 1, 0);
1527 }
1528
1529 /* We were signalled to exit with our buffer empty. Reset the
1530 mutex for a new process. */
1531 KWSYSPE_DEBUG((stderr, "self releasing reader %d\n", td->Index));
1532 ReleaseSemaphore(td->Reader.Go, 1, 0);
1533 }
1534
1535 /*
1536 Function executed for each pipe's thread. Argument is a pointer to
1537 the kwsysProcessPipeData instance for this thread.
1538 */
kwsysProcessPipeThreadWake(LPVOID ptd)1539 DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd)
1540 {
1541 kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
1542 kwsysProcess* cp = td->Process;
1543
1544 /* Wait for a process to be ready. */
1545 while ((WaitForSingleObject(td->Waker.Ready, INFINITE), !cp->Deleting)) {
1546 /* Wait for a possible wakeup. */
1547 kwsysProcessPipeThreadWakePipe(cp, td);
1548
1549 /* Signal the main thread we have reset for a new process. */
1550 ReleaseSemaphore(td->Waker.Reset, 1, 0);
1551 }
1552 return 0;
1553 }
1554
1555 /*
1556 Function called in each pipe's thread to handle reading thread
1557 wakeup for one execution of a subprocess.
1558 */
kwsysProcessPipeThreadWakePipe(kwsysProcess * cp,kwsysProcessPipeData * td)1559 void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td)
1560 {
1561 (void)cp;
1562
1563 /* Wait for a possible wake command. */
1564 KWSYSPE_DEBUG((stderr, "wait for wake %d\n", td->Index));
1565 WaitForSingleObject(td->Waker.Go, INFINITE);
1566 KWSYSPE_DEBUG((stderr, "waking %d\n", td->Index));
1567
1568 /* If the pipe is not closed, we need to wake up the reading thread. */
1569 if (!td->Closed) {
1570 DWORD dummy;
1571 KWSYSPE_DEBUG((stderr, "waker %d writing byte\n", td->Index));
1572 WriteFile(td->Write, "", 1, &dummy, 0);
1573 KWSYSPE_DEBUG((stderr, "waker %d wrote byte\n", td->Index));
1574 }
1575 }
1576
1577 /* Initialize a process control structure for kwsysProcess_Execute. */
kwsysProcessInitialize(kwsysProcess * cp)1578 int kwsysProcessInitialize(kwsysProcess* cp)
1579 {
1580 int i;
1581 /* Reset internal status flags. */
1582 cp->TimeoutExpired = 0;
1583 cp->Terminated = 0;
1584 cp->Killed = 0;
1585
1586 free(cp->ProcessResults);
1587 /* Allocate process result information for each process. */
1588 cp->ProcessResults = (kwsysProcessResults*)malloc(
1589 sizeof(kwsysProcessResults) * (cp->NumberOfCommands));
1590 if (!cp->ProcessResults) {
1591 return 0;
1592 }
1593 ZeroMemory(cp->ProcessResults,
1594 sizeof(kwsysProcessResults) * cp->NumberOfCommands);
1595 for (i = 0; i < cp->NumberOfCommands; i++) {
1596 cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None;
1597 cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting;
1598 cp->ProcessResults[i].ExitCode = 1;
1599 cp->ProcessResults[i].ExitValue = 1;
1600 strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception");
1601 }
1602
1603 /* Allocate process information for each process. */
1604 free(cp->ProcessInformation);
1605 cp->ProcessInformation = (PROCESS_INFORMATION*)malloc(
1606 sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
1607 if (!cp->ProcessInformation) {
1608 return 0;
1609 }
1610 ZeroMemory(cp->ProcessInformation,
1611 sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
1612 free(cp->CommandExitCodes);
1613 cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands);
1614 if (!cp->CommandExitCodes) {
1615 return 0;
1616 }
1617 ZeroMemory(cp->CommandExitCodes, sizeof(DWORD) * cp->NumberOfCommands);
1618
1619 /* Allocate event wait array. The first event is cp->Full, the rest
1620 are the process termination events. */
1621 cp->ProcessEvents =
1622 (PHANDLE)malloc(sizeof(HANDLE) * (cp->NumberOfCommands + 1));
1623 if (!cp->ProcessEvents) {
1624 return 0;
1625 }
1626 ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands + 1));
1627 cp->ProcessEvents[0] = cp->Full;
1628 cp->ProcessEventsLength = cp->NumberOfCommands + 1;
1629
1630 /* Allocate space to save the real working directory of this process. */
1631 if (cp->WorkingDirectory) {
1632 cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0);
1633 if (cp->RealWorkingDirectoryLength > 0) {
1634 cp->RealWorkingDirectory =
1635 malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t));
1636 if (!cp->RealWorkingDirectory) {
1637 return 0;
1638 }
1639 }
1640 }
1641 {
1642 for (i = 0; i < 3; ++i) {
1643 cp->PipeChildStd[i] = INVALID_HANDLE_VALUE;
1644 }
1645 }
1646
1647 return 1;
1648 }
1649
kwsysProcessCreateChildHandle(PHANDLE out,HANDLE in,int isStdIn)1650 static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn)
1651 {
1652 DWORD flags;
1653
1654 /* Check whether the handle is valid for this process. */
1655 if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags)) {
1656 /* Use the handle as-is if it is already inherited. */
1657 if (flags & HANDLE_FLAG_INHERIT) {
1658 *out = in;
1659 return ERROR_SUCCESS;
1660 }
1661
1662 /* Create an inherited copy of this handle. */
1663 if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, 0,
1664 TRUE, DUPLICATE_SAME_ACCESS)) {
1665 return ERROR_SUCCESS;
1666 } else {
1667 return GetLastError();
1668 }
1669 } else {
1670 /* The given handle is not valid for this process. Some child
1671 processes may break if they do not have a valid standard handle,
1672 so open NUL to give to the child. */
1673 SECURITY_ATTRIBUTES sa;
1674 ZeroMemory(&sa, sizeof(sa));
1675 sa.nLength = (DWORD)sizeof(sa);
1676 sa.bInheritHandle = 1;
1677 *out = CreateFileW(
1678 L"NUL",
1679 (isStdIn ? GENERIC_READ : (GENERIC_WRITE | FILE_READ_ATTRIBUTES)),
1680 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0);
1681 return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError();
1682 }
1683 }
1684
kwsysProcessCreate(kwsysProcess * cp,int index,kwsysProcessCreateInformation * si)1685 DWORD kwsysProcessCreate(kwsysProcess* cp, int index,
1686 kwsysProcessCreateInformation* si)
1687 {
1688 DWORD creationFlags;
1689 DWORD error = ERROR_SUCCESS;
1690
1691 /* Check if we are currently exiting. */
1692 if (!kwsysTryEnterCreateProcessSection()) {
1693 /* The Ctrl handler is currently working on exiting our process. Rather
1694 than return an error code, which could cause incorrect conclusions to be
1695 reached by the caller, we simply hang. (For example, a CMake try_run
1696 configure step might cause the project to configure wrong.) */
1697 Sleep(INFINITE);
1698 }
1699
1700 /* Create the child in a suspended state so we can wait until all
1701 children have been created before running any one. */
1702 creationFlags = CREATE_SUSPENDED;
1703 if (cp->CreateProcessGroup) {
1704 creationFlags |= CREATE_NEW_PROCESS_GROUP;
1705 }
1706
1707 /* Create inherited copies of the handles. */
1708 (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput,
1709 si->hStdInput, 1)) ||
1710 (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput,
1711 si->hStdOutput, 0)) ||
1712 (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError,
1713 si->hStdError, 0)) ||
1714 /* Create the process. */
1715 (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, 0,
1716 &si->StartupInfo, &cp->ProcessInformation[index]) &&
1717 (error = GetLastError()));
1718
1719 /* Close the inherited copies of the handles. */
1720 if (si->StartupInfo.hStdInput != si->hStdInput) {
1721 kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
1722 }
1723 if (si->StartupInfo.hStdOutput != si->hStdOutput) {
1724 kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
1725 }
1726 if (si->StartupInfo.hStdError != si->hStdError) {
1727 kwsysProcessCleanupHandle(&si->StartupInfo.hStdError);
1728 }
1729
1730 /* Add the process to the global list of processes. */
1731 if (!error &&
1732 !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess,
1733 cp->ProcessInformation[index].dwProcessId,
1734 cp->CreateProcessGroup)) {
1735 /* This failed for some reason. Kill the suspended process. */
1736 TerminateProcess(cp->ProcessInformation[index].hProcess, 1);
1737 /* And clean up... */
1738 kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
1739 kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread);
1740 strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed");
1741 error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason. */
1742 }
1743
1744 /* If the console Ctrl handler is waiting for us, this will release it... */
1745 kwsysLeaveCreateProcessSection();
1746 return error;
1747 }
1748
kwsysProcessDestroy(kwsysProcess * cp,int event)1749 void kwsysProcessDestroy(kwsysProcess* cp, int event)
1750 {
1751 int i;
1752 int index;
1753
1754 /* Find the process index for the termination event. */
1755 for (index = 0; index < cp->NumberOfCommands; ++index) {
1756 if (cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event]) {
1757 break;
1758 }
1759 }
1760
1761 /* Check the exit code of the process. */
1762 GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
1763 &cp->CommandExitCodes[index]);
1764
1765 /* Remove from global list of processes. */
1766 kwsysProcessesRemove(cp->ProcessInformation[index].hProcess);
1767
1768 /* Close the process handle for the terminated process. */
1769 kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
1770
1771 /* Remove the process from the available events. */
1772 cp->ProcessEventsLength -= 1;
1773 for (i = event; i < cp->ProcessEventsLength; ++i) {
1774 cp->ProcessEvents[i] = cp->ProcessEvents[i + 1];
1775 }
1776
1777 /* Check if all processes have terminated. */
1778 if (cp->ProcessEventsLength == 1) {
1779 cp->Terminated = 1;
1780
1781 /* Close our copies of the pipe write handles so the pipe threads
1782 can detect end-of-data. */
1783 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
1784 /* TODO: If the child created its own child (our grandchild)
1785 which inherited a copy of the pipe write-end then the pipe
1786 may not close and we will still need the waker write pipe.
1787 However we still want to be able to detect end-of-data in the
1788 normal case. The reader thread will have to switch to using
1789 PeekNamedPipe to read the last bit of data from the pipe
1790 without blocking. This is equivalent to using a non-blocking
1791 read on posix. */
1792 KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i));
1793 kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
1794 }
1795 }
1796 }
1797
kwsysProcessSetupOutputPipeFile(PHANDLE phandle,const char * name)1798 DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
1799 {
1800 HANDLE fout;
1801 wchar_t* wname;
1802 DWORD error;
1803 if (!name) {
1804 return ERROR_INVALID_PARAMETER;
1805 }
1806
1807 /* Close the existing handle. */
1808 kwsysProcessCleanupHandle(phandle);
1809
1810 /* Create a handle to write a file for the pipe. */
1811 wname = kwsysEncoding_DupToWide(name);
1812 fout =
1813 CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
1814 error = GetLastError();
1815 free(wname);
1816 if (fout == INVALID_HANDLE_VALUE) {
1817 return error;
1818 }
1819
1820 /* Assign the replacement handle. */
1821 *phandle = fout;
1822 return ERROR_SUCCESS;
1823 }
1824
kwsysProcessSetupSharedPipe(DWORD nStdHandle,PHANDLE handle)1825 void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle)
1826 {
1827 /* Close the existing handle. */
1828 kwsysProcessCleanupHandle(handle);
1829 /* Store the new standard handle. */
1830 *handle = GetStdHandle(nStdHandle);
1831 }
1832
kwsysProcessSetupPipeNative(HANDLE native,PHANDLE handle)1833 void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle)
1834 {
1835 /* Close the existing handle. */
1836 kwsysProcessCleanupHandle(handle);
1837 /* Store the new given handle. */
1838 *handle = native;
1839 }
1840
1841 /* Close the given handle if it is open. Reset its value to 0. */
kwsysProcessCleanupHandle(PHANDLE h)1842 void kwsysProcessCleanupHandle(PHANDLE h)
1843 {
1844 if (h && *h && *h != INVALID_HANDLE_VALUE &&
1845 *h != GetStdHandle(STD_INPUT_HANDLE) &&
1846 *h != GetStdHandle(STD_OUTPUT_HANDLE) &&
1847 *h != GetStdHandle(STD_ERROR_HANDLE)) {
1848 CloseHandle(*h);
1849 *h = INVALID_HANDLE_VALUE;
1850 }
1851 }
1852
1853 /* Close all handles created by kwsysProcess_Execute. */
kwsysProcessCleanup(kwsysProcess * cp,DWORD error)1854 void kwsysProcessCleanup(kwsysProcess* cp, DWORD error)
1855 {
1856 int i;
1857 /* If this is an error case, report the error. */
1858 if (error) {
1859 /* Construct an error message if one has not been provided already. */
1860 if (cp->ErrorMessage[0] == 0) {
1861 /* Format the error message. */
1862 wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE];
1863 DWORD length = FormatMessageW(
1864 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error,
1865 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg,
1866 KWSYSPE_PIPE_BUFFER_SIZE, 0);
1867 if (length < 1) {
1868 /* FormatMessage failed. Use a default message. */
1869 _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
1870 "Process execution failed with error 0x%X. "
1871 "FormatMessage failed with error 0x%X",
1872 error, GetLastError());
1873 }
1874 if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage,
1875 KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) {
1876 /* WideCharToMultiByte failed. Use a default message. */
1877 _snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
1878 "Process execution failed with error 0x%X. "
1879 "WideCharToMultiByte failed with error 0x%X",
1880 error, GetLastError());
1881 }
1882 }
1883
1884 /* Remove trailing period and newline, if any. */
1885 kwsysProcessCleanErrorMessage(cp);
1886
1887 /* Set the error state. */
1888 cp->State = kwsysProcess_State_Error;
1889
1890 /* Cleanup any processes already started in a suspended state. */
1891 if (cp->ProcessInformation) {
1892 for (i = 0; i < cp->NumberOfCommands; ++i) {
1893 if (cp->ProcessInformation[i].hProcess) {
1894 TerminateProcess(cp->ProcessInformation[i].hProcess, 255);
1895 WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE);
1896 }
1897 }
1898 for (i = 0; i < cp->NumberOfCommands; ++i) {
1899 /* Remove from global list of processes and close handles. */
1900 kwsysProcessesRemove(cp->ProcessInformation[i].hProcess);
1901 kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
1902 kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
1903 }
1904 }
1905
1906 /* Restore the working directory. */
1907 if (cp->RealWorkingDirectory) {
1908 SetCurrentDirectoryW(cp->RealWorkingDirectory);
1909 }
1910 }
1911
1912 /* Free memory. */
1913 if (cp->ProcessInformation) {
1914 free(cp->ProcessInformation);
1915 cp->ProcessInformation = 0;
1916 }
1917 if (cp->ProcessEvents) {
1918 free(cp->ProcessEvents);
1919 cp->ProcessEvents = 0;
1920 }
1921 if (cp->RealWorkingDirectory) {
1922 free(cp->RealWorkingDirectory);
1923 cp->RealWorkingDirectory = 0;
1924 }
1925
1926 /* Close each pipe. */
1927 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
1928 kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
1929 kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
1930 cp->Pipe[i].Closed = 0;
1931 }
1932 for (i = 0; i < 3; ++i) {
1933 kwsysProcessCleanupHandle(&cp->PipeChildStd[i]);
1934 }
1935 }
1936
kwsysProcessCleanErrorMessage(kwsysProcess * cp)1937 void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
1938 {
1939 /* Remove trailing period and newline, if any. */
1940 size_t length = strlen(cp->ErrorMessage);
1941 if (cp->ErrorMessage[length - 1] == '\n') {
1942 cp->ErrorMessage[length - 1] = 0;
1943 --length;
1944 if (length > 0 && cp->ErrorMessage[length - 1] == '\r') {
1945 cp->ErrorMessage[length - 1] = 0;
1946 --length;
1947 }
1948 }
1949 if (length > 0 && cp->ErrorMessage[length - 1] == '.') {
1950 cp->ErrorMessage[length - 1] = 0;
1951 }
1952 }
1953
1954 /* Get the time at which either the process or user timeout will
1955 expire. Returns 1 if the user timeout is first, and 0 otherwise. */
kwsysProcessGetTimeoutTime(kwsysProcess * cp,double * userTimeout,kwsysProcessTime * timeoutTime)1956 int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
1957 kwsysProcessTime* timeoutTime)
1958 {
1959 /* The first time this is called, we need to calculate the time at
1960 which the child will timeout. */
1961 if (cp->Timeout && cp->TimeoutTime.QuadPart < 0) {
1962 kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
1963 cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
1964 }
1965
1966 /* Start with process timeout. */
1967 *timeoutTime = cp->TimeoutTime;
1968
1969 /* Check if the user timeout is earlier. */
1970 if (userTimeout) {
1971 kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
1972 kwsysProcessTime userTimeoutLength =
1973 kwsysProcessTimeFromDouble(*userTimeout);
1974 kwsysProcessTime userTimeoutTime =
1975 kwsysProcessTimeAdd(currentTime, userTimeoutLength);
1976 if (timeoutTime->QuadPart < 0 ||
1977 kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) {
1978 *timeoutTime = userTimeoutTime;
1979 return 1;
1980 }
1981 }
1982 return 0;
1983 }
1984
1985 /* Get the length of time before the given timeout time arrives.
1986 Returns 1 if the time has already arrived, and 0 otherwise. */
kwsysProcessGetTimeoutLeft(kwsysProcessTime * timeoutTime,double * userTimeout,kwsysProcessTime * timeoutLength)1987 int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
1988 double* userTimeout,
1989 kwsysProcessTime* timeoutLength)
1990 {
1991 if (timeoutTime->QuadPart < 0) {
1992 /* No timeout time has been requested. */
1993 return 0;
1994 } else {
1995 /* Calculate the remaining time. */
1996 kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
1997 *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime);
1998
1999 if (timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0) {
2000 /* Caller has explicitly requested a zero timeout. */
2001 timeoutLength->QuadPart = 0;
2002 }
2003
2004 if (timeoutLength->QuadPart < 0) {
2005 /* Timeout has already expired. */
2006 return 1;
2007 } else {
2008 /* There is some time left. */
2009 return 0;
2010 }
2011 }
2012 }
2013
kwsysProcessTimeGetCurrent()2014 kwsysProcessTime kwsysProcessTimeGetCurrent()
2015 {
2016 kwsysProcessTime current;
2017 FILETIME ft;
2018 GetSystemTimeAsFileTime(&ft);
2019 current.LowPart = ft.dwLowDateTime;
2020 current.HighPart = ft.dwHighDateTime;
2021 return current;
2022 }
2023
kwsysProcessTimeToDWORD(kwsysProcessTime t)2024 DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t)
2025 {
2026 return (DWORD)(t.QuadPart * 0.0001);
2027 }
2028
kwsysProcessTimeToDouble(kwsysProcessTime t)2029 double kwsysProcessTimeToDouble(kwsysProcessTime t)
2030 {
2031 return t.QuadPart * 0.0000001;
2032 }
2033
kwsysProcessTimeFromDouble(double d)2034 kwsysProcessTime kwsysProcessTimeFromDouble(double d)
2035 {
2036 kwsysProcessTime t;
2037 t.QuadPart = (LONGLONG)(d * 10000000);
2038 return t;
2039 }
2040
kwsysProcessTimeLess(kwsysProcessTime in1,kwsysProcessTime in2)2041 int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
2042 {
2043 return in1.QuadPart < in2.QuadPart;
2044 }
2045
kwsysProcessTimeAdd(kwsysProcessTime in1,kwsysProcessTime in2)2046 kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1,
2047 kwsysProcessTime in2)
2048 {
2049 kwsysProcessTime out;
2050 out.QuadPart = in1.QuadPart + in2.QuadPart;
2051 return out;
2052 }
2053
kwsysProcessTimeSubtract(kwsysProcessTime in1,kwsysProcessTime in2)2054 kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1,
2055 kwsysProcessTime in2)
2056 {
2057 kwsysProcessTime out;
2058 out.QuadPart = in1.QuadPart - in2.QuadPart;
2059 return out;
2060 }
2061
2062 #define KWSYSPE_CASE(type, str) \
2063 cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type; \
2064 strcpy(cp->ProcessResults[idx].ExitExceptionString, str)
kwsysProcessSetExitExceptionByIndex(kwsysProcess * cp,int code,int idx)2065 static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code,
2066 int idx)
2067 {
2068 switch (code) {
2069 case STATUS_CONTROL_C_EXIT:
2070 KWSYSPE_CASE(Interrupt, "User interrupt");
2071 break;
2072
2073 case STATUS_FLOAT_DENORMAL_OPERAND:
2074 KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)");
2075 break;
2076 case STATUS_FLOAT_DIVIDE_BY_ZERO:
2077 KWSYSPE_CASE(Numerical, "Divide-by-zero");
2078 break;
2079 case STATUS_FLOAT_INEXACT_RESULT:
2080 KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)");
2081 break;
2082 case STATUS_FLOAT_INVALID_OPERATION:
2083 KWSYSPE_CASE(Numerical, "Invalid floating-point operation");
2084 break;
2085 case STATUS_FLOAT_OVERFLOW:
2086 KWSYSPE_CASE(Numerical, "Floating-point overflow");
2087 break;
2088 case STATUS_FLOAT_STACK_CHECK:
2089 KWSYSPE_CASE(Numerical, "Floating-point stack check failed");
2090 break;
2091 case STATUS_FLOAT_UNDERFLOW:
2092 KWSYSPE_CASE(Numerical, "Floating-point underflow");
2093 break;
2094 #ifdef STATUS_FLOAT_MULTIPLE_FAULTS
2095 case STATUS_FLOAT_MULTIPLE_FAULTS:
2096 KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)");
2097 break;
2098 #endif
2099 #ifdef STATUS_FLOAT_MULTIPLE_TRAPS
2100 case STATUS_FLOAT_MULTIPLE_TRAPS:
2101 KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)");
2102 break;
2103 #endif
2104 case STATUS_INTEGER_DIVIDE_BY_ZERO:
2105 KWSYSPE_CASE(Numerical, "Integer divide-by-zero");
2106 break;
2107 case STATUS_INTEGER_OVERFLOW:
2108 KWSYSPE_CASE(Numerical, "Integer overflow");
2109 break;
2110
2111 case STATUS_DATATYPE_MISALIGNMENT:
2112 KWSYSPE_CASE(Fault, "Datatype misalignment");
2113 break;
2114 case STATUS_ACCESS_VIOLATION:
2115 KWSYSPE_CASE(Fault, "Access violation");
2116 break;
2117 case STATUS_IN_PAGE_ERROR:
2118 KWSYSPE_CASE(Fault, "In-page error");
2119 break;
2120 case STATUS_INVALID_HANDLE:
2121 KWSYSPE_CASE(Fault, "Invalid hanlde");
2122 break;
2123 case STATUS_NONCONTINUABLE_EXCEPTION:
2124 KWSYSPE_CASE(Fault, "Noncontinuable exception");
2125 break;
2126 case STATUS_INVALID_DISPOSITION:
2127 KWSYSPE_CASE(Fault, "Invalid disposition");
2128 break;
2129 case STATUS_ARRAY_BOUNDS_EXCEEDED:
2130 KWSYSPE_CASE(Fault, "Array bounds exceeded");
2131 break;
2132 case STATUS_STACK_OVERFLOW:
2133 KWSYSPE_CASE(Fault, "Stack overflow");
2134 break;
2135
2136 case STATUS_ILLEGAL_INSTRUCTION:
2137 KWSYSPE_CASE(Illegal, "Illegal instruction");
2138 break;
2139 case STATUS_PRIVILEGED_INSTRUCTION:
2140 KWSYSPE_CASE(Illegal, "Privileged instruction");
2141 break;
2142
2143 case STATUS_NO_MEMORY:
2144 default:
2145 cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other;
2146 _snprintf(cp->ProcessResults[idx].ExitExceptionString,
2147 KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code);
2148 break;
2149 }
2150 }
2151 #undef KWSYSPE_CASE
2152
2153 typedef struct kwsysProcess_List_s kwsysProcess_List;
2154 static kwsysProcess_List* kwsysProcess_List_New(void);
2155 static void kwsysProcess_List_Delete(kwsysProcess_List* self);
2156 static int kwsysProcess_List_Update(kwsysProcess_List* self);
2157 static int kwsysProcess_List_NextProcess(kwsysProcess_List* self);
2158 static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self);
2159 static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self);
2160
2161 /* Windows NT 4 API definitions. */
2162 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
2163 typedef LONG NTSTATUS;
2164 typedef LONG KPRIORITY;
2165 typedef struct _UNICODE_STRING UNICODE_STRING;
2166 struct _UNICODE_STRING
2167 {
2168 USHORT Length;
2169 USHORT MaximumLength;
2170 PWSTR Buffer;
2171 };
2172
2173 /* The process information structure. Declare only enough to get
2174 process identifiers. The rest may be ignored because we use the
2175 NextEntryDelta to move through an array of instances. */
2176 typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION;
2177 typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION;
2178 struct _SYSTEM_PROCESS_INFORMATION
2179 {
2180 ULONG NextEntryDelta;
2181 ULONG ThreadCount;
2182 ULONG Reserved1[6];
2183 LARGE_INTEGER CreateTime;
2184 LARGE_INTEGER UserTime;
2185 LARGE_INTEGER KernelTime;
2186 UNICODE_STRING ProcessName;
2187 KPRIORITY BasePriority;
2188 ULONG ProcessId;
2189 ULONG InheritedFromProcessId;
2190 };
2191
2192 /* Toolhelp32 API definitions. */
2193 #define TH32CS_SNAPPROCESS 0x00000002
2194 #if defined(_WIN64)
2195 typedef unsigned __int64 ProcessULONG_PTR;
2196 #else
2197 typedef unsigned long ProcessULONG_PTR;
2198 #endif
2199 typedef struct tagPROCESSENTRY32 PROCESSENTRY32;
2200 typedef PROCESSENTRY32* LPPROCESSENTRY32;
2201 struct tagPROCESSENTRY32
2202 {
2203 DWORD dwSize;
2204 DWORD cntUsage;
2205 DWORD th32ProcessID;
2206 ProcessULONG_PTR th32DefaultHeapID;
2207 DWORD th32ModuleID;
2208 DWORD cntThreads;
2209 DWORD th32ParentProcessID;
2210 LONG pcPriClassBase;
2211 DWORD dwFlags;
2212 char szExeFile[MAX_PATH];
2213 };
2214
2215 /* Windows API function types. */
2216 typedef HANDLE(WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD);
2217 typedef BOOL(WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32);
2218 typedef BOOL(WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32);
2219 typedef NTSTATUS(WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID, ULONG,
2220 PULONG);
2221
2222 static int kwsysProcess_List__New_NT4(kwsysProcess_List* self);
2223 static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self);
2224 static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self);
2225 static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self);
2226 static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self);
2227 static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self);
2228 static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self);
2229 static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self);
2230 static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self);
2231 static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self);
2232 static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self);
2233 static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self);
2234
2235 struct kwsysProcess_List_s
2236 {
2237 /* Implementation switches at runtime based on version of Windows. */
2238 int NT4;
2239
2240 /* Implementation functions and data for NT 4. */
2241 ZwQuerySystemInformationType P_ZwQuerySystemInformation;
2242 char* Buffer;
2243 int BufferSize;
2244 PSYSTEM_PROCESS_INFORMATION CurrentInfo;
2245
2246 /* Implementation functions and data for other Windows versions. */
2247 CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot;
2248 Process32FirstType P_Process32First;
2249 Process32NextType P_Process32Next;
2250 HANDLE Snapshot;
2251 PROCESSENTRY32 CurrentEntry;
2252 };
2253
kwsysProcess_List_New(void)2254 static kwsysProcess_List* kwsysProcess_List_New(void)
2255 {
2256 OSVERSIONINFO osv;
2257 kwsysProcess_List* self;
2258
2259 /* Allocate and initialize the list object. */
2260 if (!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List)))) {
2261 return 0;
2262 }
2263 memset(self, 0, sizeof(*self));
2264
2265 /* Select an implementation. */
2266 ZeroMemory(&osv, sizeof(osv));
2267 osv.dwOSVersionInfoSize = sizeof(osv);
2268 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
2269 #pragma warning(push)
2270 #ifdef __INTEL_COMPILER
2271 #pragma warning(disable : 1478)
2272 #else
2273 #pragma warning(disable : 4996)
2274 #endif
2275 #endif
2276 GetVersionEx(&osv);
2277 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
2278 #pragma warning(pop)
2279 #endif
2280 self->NT4 =
2281 (osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1
2282 : 0;
2283
2284 /* Initialize the selected implementation. */
2285 if (!(self->NT4 ? kwsysProcess_List__New_NT4(self)
2286 : kwsysProcess_List__New_Snapshot(self))) {
2287 kwsysProcess_List_Delete(self);
2288 return 0;
2289 }
2290
2291 /* Update to the current set of processes. */
2292 if (!kwsysProcess_List_Update(self)) {
2293 kwsysProcess_List_Delete(self);
2294 return 0;
2295 }
2296 return self;
2297 }
2298
kwsysProcess_List_Delete(kwsysProcess_List * self)2299 static void kwsysProcess_List_Delete(kwsysProcess_List* self)
2300 {
2301 if (self) {
2302 if (self->NT4) {
2303 kwsysProcess_List__Delete_NT4(self);
2304 } else {
2305 kwsysProcess_List__Delete_Snapshot(self);
2306 }
2307 free(self);
2308 }
2309 }
2310
kwsysProcess_List_Update(kwsysProcess_List * self)2311 static int kwsysProcess_List_Update(kwsysProcess_List* self)
2312 {
2313 return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self)
2314 : kwsysProcess_List__Update_Snapshot(self))
2315 : 0;
2316 }
2317
kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List * self)2318 static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self)
2319 {
2320 return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self)
2321 : kwsysProcess_List__GetProcessId_Snapshot(self))
2322 : -1;
2323 }
2324
kwsysProcess_List_GetCurrentParentId(kwsysProcess_List * self)2325 static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self)
2326 {
2327 return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self)
2328 : kwsysProcess_List__GetParentId_Snapshot(self))
2329 : -1;
2330 }
2331
kwsysProcess_List_NextProcess(kwsysProcess_List * self)2332 static int kwsysProcess_List_NextProcess(kwsysProcess_List* self)
2333 {
2334 return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self)
2335 : kwsysProcess_List__Next_Snapshot(self))
2336 : 0);
2337 }
2338
kwsysProcess_List__New_NT4(kwsysProcess_List * self)2339 static int kwsysProcess_List__New_NT4(kwsysProcess_List* self)
2340 {
2341 /* Get a handle to the NT runtime module that should already be
2342 loaded in this program. This does not actually increment the
2343 reference count to the module so we do not need to close the
2344 handle. */
2345 HMODULE hNT = GetModuleHandleW(L"ntdll.dll");
2346 if (hNT) {
2347 /* Get pointers to the needed API functions. */
2348 self->P_ZwQuerySystemInformation =
2349 ((ZwQuerySystemInformationType)GetProcAddress(
2350 hNT, "ZwQuerySystemInformation"));
2351 }
2352 if (!self->P_ZwQuerySystemInformation) {
2353 return 0;
2354 }
2355
2356 /* Allocate an initial process information buffer. */
2357 self->BufferSize = 32768;
2358 self->Buffer = (char*)malloc(self->BufferSize);
2359 return self->Buffer ? 1 : 0;
2360 }
2361
kwsysProcess_List__Delete_NT4(kwsysProcess_List * self)2362 static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self)
2363 {
2364 /* Free the process information buffer. */
2365 free(self->Buffer);
2366 }
2367
kwsysProcess_List__Update_NT4(kwsysProcess_List * self)2368 static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self)
2369 {
2370 self->CurrentInfo = 0;
2371 for (;;) {
2372 /* Query number 5 is for system process list. */
2373 NTSTATUS status =
2374 self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0);
2375 if (status == STATUS_INFO_LENGTH_MISMATCH) {
2376 /* The query requires a bigger buffer. */
2377 int newBufferSize = self->BufferSize * 2;
2378 char* newBuffer = (char*)malloc(newBufferSize);
2379 if (newBuffer) {
2380 free(self->Buffer);
2381 self->Buffer = newBuffer;
2382 self->BufferSize = newBufferSize;
2383 } else {
2384 return 0;
2385 }
2386 } else if (status >= 0) {
2387 /* The query succeeded. Initialize traversal of the process list. */
2388 self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer;
2389 return 1;
2390 } else {
2391 /* The query failed. */
2392 return 0;
2393 }
2394 }
2395 }
2396
kwsysProcess_List__Next_NT4(kwsysProcess_List * self)2397 static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
2398 {
2399 if (self->CurrentInfo) {
2400 if (self->CurrentInfo->NextEntryDelta > 0) {
2401 self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)(
2402 (char*)self->CurrentInfo + self->CurrentInfo->NextEntryDelta));
2403 return 1;
2404 }
2405 self->CurrentInfo = 0;
2406 }
2407 return 0;
2408 }
2409
kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List * self)2410 static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self)
2411 {
2412 return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1;
2413 }
2414
kwsysProcess_List__GetParentId_NT4(kwsysProcess_List * self)2415 static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self)
2416 {
2417 return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1;
2418 }
2419
kwsysProcess_List__New_Snapshot(kwsysProcess_List * self)2420 static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self)
2421 {
2422 /* Get a handle to the Windows runtime module that should already be
2423 loaded in this program. This does not actually increment the
2424 reference count to the module so we do not need to close the
2425 handle. */
2426 HMODULE hKernel = GetModuleHandleW(L"kernel32.dll");
2427 if (hKernel) {
2428 self->P_CreateToolhelp32Snapshot =
2429 ((CreateToolhelp32SnapshotType)GetProcAddress(
2430 hKernel, "CreateToolhelp32Snapshot"));
2431 self->P_Process32First =
2432 ((Process32FirstType)GetProcAddress(hKernel, "Process32First"));
2433 self->P_Process32Next =
2434 ((Process32NextType)GetProcAddress(hKernel, "Process32Next"));
2435 }
2436 return (self->P_CreateToolhelp32Snapshot && self->P_Process32First &&
2437 self->P_Process32Next)
2438 ? 1
2439 : 0;
2440 }
2441
kwsysProcess_List__Delete_Snapshot(kwsysProcess_List * self)2442 static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self)
2443 {
2444 if (self->Snapshot) {
2445 CloseHandle(self->Snapshot);
2446 }
2447 }
2448
kwsysProcess_List__Update_Snapshot(kwsysProcess_List * self)2449 static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self)
2450 {
2451 if (self->Snapshot) {
2452 CloseHandle(self->Snapshot);
2453 }
2454 if (!(self->Snapshot =
2455 self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) {
2456 return 0;
2457 }
2458 ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry));
2459 self->CurrentEntry.dwSize = sizeof(self->CurrentEntry);
2460 if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) {
2461 CloseHandle(self->Snapshot);
2462 self->Snapshot = 0;
2463 return 0;
2464 }
2465 return 1;
2466 }
2467
kwsysProcess_List__Next_Snapshot(kwsysProcess_List * self)2468 static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self)
2469 {
2470 if (self->Snapshot) {
2471 if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) {
2472 return 1;
2473 }
2474 CloseHandle(self->Snapshot);
2475 self->Snapshot = 0;
2476 }
2477 return 0;
2478 }
2479
kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List * self)2480 static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self)
2481 {
2482 return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1;
2483 }
2484
kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List * self)2485 static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self)
2486 {
2487 return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1;
2488 }
2489
kwsysProcessKill(DWORD pid)2490 static void kwsysProcessKill(DWORD pid)
2491 {
2492 HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
2493 if (h) {
2494 TerminateProcess(h, 255);
2495 WaitForSingleObject(h, INFINITE);
2496 CloseHandle(h);
2497 }
2498 }
2499
kwsysProcessKillTree(int pid)2500 static void kwsysProcessKillTree(int pid)
2501 {
2502 kwsysProcess_List* plist = kwsysProcess_List_New();
2503 kwsysProcessKill(pid);
2504 if (plist) {
2505 do {
2506 if (kwsysProcess_List_GetCurrentParentId(plist) == pid) {
2507 int ppid = kwsysProcess_List_GetCurrentProcessId(plist);
2508 kwsysProcessKillTree(ppid);
2509 }
2510 } while (kwsysProcess_List_NextProcess(plist));
2511 kwsysProcess_List_Delete(plist);
2512 }
2513 }
2514
kwsysProcessDisablePipeThreads(kwsysProcess * cp)2515 static void kwsysProcessDisablePipeThreads(kwsysProcess* cp)
2516 {
2517 int i;
2518
2519 /* If data were just reported data, release the pipe's thread. */
2520 if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) {
2521 KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex));
2522 ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
2523 cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
2524 }
2525
2526 /* Wakeup all reading threads that are not on closed pipes. */
2527 for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) {
2528 /* The wakeup threads will write one byte to the pipe write ends.
2529 If there are no data in the pipe then this is enough to wakeup
2530 the reading threads. If there are already data in the pipe
2531 this may block. We cannot use PeekNamedPipe to check whether
2532 there are data because an outside process might still be
2533 writing data if we are disowning it. Also, PeekNamedPipe will
2534 block if checking a pipe on which the reading thread is
2535 currently calling ReadPipe. Therefore we need a separate
2536 thread to call WriteFile. If it blocks, that is okay because
2537 it will unblock when we close the read end and break the pipe
2538 below. */
2539 if (cp->Pipe[i].Read) {
2540 KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i));
2541 ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0);
2542 }
2543 }
2544
2545 /* Tell pipe threads to reset until we run another process. */
2546 while (cp->PipesLeft > 0) {
2547 /* The waking threads will cause all reading threads to report.
2548 Wait for the next one and save its index. */
2549 KWSYSPE_DEBUG((stderr, "waiting for reader\n"));
2550 WaitForSingleObject(cp->Full, INFINITE);
2551 cp->CurrentIndex = cp->SharedIndex;
2552 ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
2553 KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex));
2554
2555 /* We are done reading this pipe. Close its read handle. */
2556 cp->Pipe[cp->CurrentIndex].Closed = 1;
2557 kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read);
2558 --cp->PipesLeft;
2559
2560 /* Tell the reading thread we are done with the data. It will
2561 reset immediately because the pipe is closed. */
2562 ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
2563 }
2564 }
2565
2566 /* Global set of executing processes for use by the Ctrl handler.
2567 This global instance will be zero-initialized by the compiler.
2568
2569 Note that the console Ctrl handler runs on a background thread and so
2570 everything it does must be thread safe. Here, we track the hProcess
2571 HANDLEs directly instead of kwsysProcess instances, so that we don't have
2572 to make kwsysProcess thread safe. */
2573 typedef struct kwsysProcessInstance_s
2574 {
2575 HANDLE hProcess;
2576 DWORD dwProcessId;
2577 int NewProcessGroup; /* Whether the process was created in a new group. */
2578 } kwsysProcessInstance;
2579
2580 typedef struct kwsysProcessInstances_s
2581 {
2582 /* Whether we have initialized key fields below, like critical sections. */
2583 int Initialized;
2584
2585 /* Ctrl handler runs on a different thread, so we must sync access. */
2586 CRITICAL_SECTION Lock;
2587
2588 int Exiting;
2589 size_t Count;
2590 size_t Size;
2591 kwsysProcessInstance* Processes;
2592 } kwsysProcessInstances;
2593 static kwsysProcessInstances kwsysProcesses;
2594
2595 /* Initialize critial section and set up console Ctrl handler. You MUST call
2596 this before using any other kwsysProcesses* functions below. */
kwsysProcessesInitialize(void)2597 static int kwsysProcessesInitialize(void)
2598 {
2599 /* Initialize everything if not done already. */
2600 if (!kwsysProcesses.Initialized) {
2601 InitializeCriticalSection(&kwsysProcesses.Lock);
2602
2603 /* Set up console ctrl handler. */
2604 if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) {
2605 return 0;
2606 }
2607
2608 kwsysProcesses.Initialized = 1;
2609 }
2610 return 1;
2611 }
2612
2613 /* The Ctrl handler waits on the global list of processes. To prevent an
2614 orphaned process, do not create a new process if the Ctrl handler is
2615 already running. Do so by using this function to check if it is ok to
2616 create a process. */
kwsysTryEnterCreateProcessSection(void)2617 static int kwsysTryEnterCreateProcessSection(void)
2618 {
2619 /* Enter main critical section; this means creating a process and the Ctrl
2620 handler are mutually exclusive. */
2621 EnterCriticalSection(&kwsysProcesses.Lock);
2622 /* Indicate to the caller if they can create a process. */
2623 if (kwsysProcesses.Exiting) {
2624 LeaveCriticalSection(&kwsysProcesses.Lock);
2625 return 0;
2626 } else {
2627 return 1;
2628 }
2629 }
2630
2631 /* Matching function on successful kwsysTryEnterCreateProcessSection return.
2632 Make sure you called kwsysProcessesAdd if applicable before calling this.*/
kwsysLeaveCreateProcessSection(void)2633 static void kwsysLeaveCreateProcessSection(void)
2634 {
2635 LeaveCriticalSection(&kwsysProcesses.Lock);
2636 }
2637
2638 /* Add new process to global process list. The Ctrl handler will wait for
2639 the process to exit before it returns. Do not close the process handle
2640 until after calling kwsysProcessesRemove. The newProcessGroup parameter
2641 must be set if the process was created with CREATE_NEW_PROCESS_GROUP. */
kwsysProcessesAdd(HANDLE hProcess,DWORD dwProcessid,int newProcessGroup)2642 static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid,
2643 int newProcessGroup)
2644 {
2645 if (!kwsysProcessesInitialize() || !hProcess ||
2646 hProcess == INVALID_HANDLE_VALUE) {
2647 return 0;
2648 }
2649
2650 /* Enter the critical section. */
2651 EnterCriticalSection(&kwsysProcesses.Lock);
2652
2653 /* Make sure there is enough space for the new process handle. */
2654 if (kwsysProcesses.Count == kwsysProcesses.Size) {
2655 size_t newSize;
2656 kwsysProcessInstance* newArray;
2657 /* Start with enough space for a small number of process handles
2658 and double the size each time more is needed. */
2659 newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4;
2660
2661 /* Try allocating the new block of memory. */
2662 if (newArray = (kwsysProcessInstance*)malloc(
2663 newSize * sizeof(kwsysProcessInstance))) {
2664 /* Copy the old process handles to the new memory. */
2665 if (kwsysProcesses.Count > 0) {
2666 memcpy(newArray, kwsysProcesses.Processes,
2667 kwsysProcesses.Count * sizeof(kwsysProcessInstance));
2668 }
2669 } else {
2670 /* Failed to allocate memory for the new process handle set. */
2671 LeaveCriticalSection(&kwsysProcesses.Lock);
2672 return 0;
2673 }
2674
2675 /* Free original array. */
2676 free(kwsysProcesses.Processes);
2677
2678 /* Update original structure with new allocation. */
2679 kwsysProcesses.Size = newSize;
2680 kwsysProcesses.Processes = newArray;
2681 }
2682
2683 /* Append the new process information to the set. */
2684 kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess;
2685 kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid;
2686 kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup =
2687 newProcessGroup;
2688
2689 /* Leave critical section and return success. */
2690 LeaveCriticalSection(&kwsysProcesses.Lock);
2691
2692 return 1;
2693 }
2694
2695 /* Removes process to global process list. */
kwsysProcessesRemove(HANDLE hProcess)2696 static void kwsysProcessesRemove(HANDLE hProcess)
2697 {
2698 size_t i;
2699
2700 if (!hProcess || hProcess == INVALID_HANDLE_VALUE) {
2701 return;
2702 }
2703
2704 EnterCriticalSection(&kwsysProcesses.Lock);
2705
2706 /* Find the given process in the set. */
2707 for (i = 0; i < kwsysProcesses.Count; ++i) {
2708 if (kwsysProcesses.Processes[i].hProcess == hProcess) {
2709 break;
2710 }
2711 }
2712 if (i < kwsysProcesses.Count) {
2713 /* Found it! Remove the process from the set. */
2714 --kwsysProcesses.Count;
2715 for (; i < kwsysProcesses.Count; ++i) {
2716 kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1];
2717 }
2718
2719 /* If this was the last process, free the array. */
2720 if (kwsysProcesses.Count == 0) {
2721 kwsysProcesses.Size = 0;
2722 free(kwsysProcesses.Processes);
2723 kwsysProcesses.Processes = 0;
2724 }
2725 }
2726
2727 LeaveCriticalSection(&kwsysProcesses.Lock);
2728 }
2729
kwsysCtrlHandler(DWORD dwCtrlType)2730 static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType)
2731 {
2732 size_t i;
2733 (void)dwCtrlType;
2734 /* Enter critical section. */
2735 EnterCriticalSection(&kwsysProcesses.Lock);
2736
2737 /* Set flag indicating that we are exiting. */
2738 kwsysProcesses.Exiting = 1;
2739
2740 /* If some of our processes were created in a new process group, we must
2741 manually interrupt them. They won't otherwise receive a Ctrl+C/Break. */
2742 for (i = 0; i < kwsysProcesses.Count; ++i) {
2743 if (kwsysProcesses.Processes[i].NewProcessGroup) {
2744 DWORD groupId = kwsysProcesses.Processes[i].dwProcessId;
2745 if (groupId) {
2746 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId);
2747 }
2748 }
2749 }
2750
2751 /* Wait for each child process to exit. This is the key step that prevents
2752 us from leaving several orphaned children processes running in the
2753 background when the user presses Ctrl+C. */
2754 for (i = 0; i < kwsysProcesses.Count; ++i) {
2755 WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE);
2756 }
2757
2758 /* Leave critical section. */
2759 LeaveCriticalSection(&kwsysProcesses.Lock);
2760
2761 /* Continue on to default Ctrl handler (which calls ExitProcess). */
2762 return FALSE;
2763 }
2764
kwsysProcess_ResetStartTime(kwsysProcess * cp)2765 void kwsysProcess_ResetStartTime(kwsysProcess* cp)
2766 {
2767 if (!cp) {
2768 return;
2769 }
2770 /* Reset start time. */
2771 cp->StartTime = kwsysProcessTimeGetCurrent();
2772 }
2773