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