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