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