1
/*=========================================================================
3
Program: KWSys - Kitware System Library
4
Module: $RCSfile: ProcessWin32.c,v $
6
Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
7
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
This software is distributed WITHOUT ANY WARRANTY; without even
10
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11
PURPOSE. See the above copyright notices for more information.
13
=========================================================================*/
14
#define KWSYS_IN_PROCESS_C
15
#include "kwsysPrivate.h"
16
#include KWSYS_HEADER(Process.h)
20
Implementation for Windows
22
On windows, a thread is created to wait for data on each pipe. The
23
threads are synchronized with the main thread to simulate the use of
24
a UNIX-style select system call.
26
On Windows9x platforms, a small WIN32 console application is spawned
27
in-between the calling process and the actual child to be executed.
28
This is to work-around a problem with connecting pipes from WIN16
29
console applications to WIN32 applications.
31
For more information, please check Microsoft Knowledge Base Articles
37
#pragma warning (push, 1)
39
#include <windows.h> /* Windows API */
40
#include <string.h> /* strlen, strdup */
41
#include <stdio.h> /* sprintf */
42
#include <io.h> /* _unlink */
45
#define _MAX_FNAME 4096
48
#define _MAX_PATH 4096
53
#pragma warning (disable: 4514)
54
#pragma warning (disable: 4706)
57
/* There are pipes for the process pipeline's stdout and stderr. */
58
#define KWSYSPE_PIPE_COUNT 2
59
#define KWSYSPE_PIPE_STDOUT 0
60
#define KWSYSPE_PIPE_STDERR 1
62
/* The maximum amount to read from a pipe at a time. */
63
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
65
#define kwsysEncodedWriteArrayProcessFwd9x kwsys_ns(EncodedWriteArrayProcessFwd9x)
67
typedef LARGE_INTEGER kwsysProcessTime;
69
typedef struct kwsysProcessCreateInformation_s
71
/* Windows child startup control data. */
72
STARTUPINFO StartupInfo;
74
/* Special error reporting pipe for Win9x forwarding executable. */
76
HANDLE ErrorPipeWrite;
77
} kwsysProcessCreateInformation;
79
/*--------------------------------------------------------------------------*/
80
typedef struct kwsysProcessPipeData_s kwsysProcessPipeData;
81
static DWORD WINAPI kwsysProcessPipeThread(LPVOID ptd);
82
static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td);
83
static int kwsysProcessInitialize(kwsysProcess* cp);
84
static int kwsysProcessCreate(kwsysProcess* cp, int index,
85
kwsysProcessCreateInformation* si,
87
static void kwsysProcessDestroy(kwsysProcess* cp, int event);
88
static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
89
static void kwsysProcessCleanupHandle(PHANDLE h);
90
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
91
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
92
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
93
kwsysProcessTime* timeoutTime);
94
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
95
kwsysProcessTime* timeoutLength);
96
static kwsysProcessTime kwsysProcessTimeGetCurrent();
97
static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t);
98
static double kwsysProcessTimeToDouble(kwsysProcessTime t);
99
static kwsysProcessTime kwsysProcessTimeFromDouble(double d);
100
static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2);
101
static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2);
102
static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2);
103
static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
104
static void kwsysProcessKillTree(int pid);
105
extern kwsysEXPORT int kwsysEncodedWriteArrayProcessFwd9x(const char* fname);
107
/*--------------------------------------------------------------------------*/
108
/* A structure containing data for each pipe's thread. */
109
struct kwsysProcessPipeData_s
111
/* ------------- Data managed per instance of kwsysProcess ------------- */
113
/* Handle for the thread for this pipe. */
116
/* Semaphore indicating a process and pipe are available. */
119
/* Semaphore indicating when this thread's buffer is empty. */
122
/* Semaphore indicating a pipe thread has reset for another process. */
125
/* Index of this pipe. */
128
/* The kwsysProcess instance owning this pipe. */
129
kwsysProcess* Process;
131
/* ------------- Data managed per call to Execute ------------- */
133
/* Buffer for data read in this pipe's thread. */
134
char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
136
/* The length of the data stored in the buffer. */
139
/* Whether the pipe has been closed. */
142
/* Handle for the read end of this pipe. */
145
/* Handle for the write end of this pipe. */
149
/*--------------------------------------------------------------------------*/
150
/* Structure containing data used to implement the child's execution. */
151
struct kwsysProcess_s
153
/* ------------- Data managed per instance of kwsysProcess ------------- */
155
/* The status of the process structure. */
158
/* The command lines to execute. */
160
int NumberOfCommands;
162
/* The exit code of each command. */
163
DWORD* CommandExitCodes;
165
/* The working directory for the child process. */
166
char* WorkingDirectory;
168
/* Whether to hide the child process's window. */
171
/* On Win9x platforms, the path to the forwarding executable. */
174
/* On Win9x platforms, the resume event for the forwarding executable. */
175
HANDLE Win9xResumeEvent;
177
/* On Win9x platforms, the kill event for the forwarding executable. */
178
HANDLE Win9xKillEvent;
180
/* Mutex to protect the shared index used by threads to report data. */
181
HANDLE SharedIndexMutex;
183
/* Semaphore used by threads to signal data ready. */
186
/* Whether we are currently deleting this kwsysProcess instance. */
189
/* Data specific to each pipe and its thread. */
190
kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
192
/* Name of files to which stdin and stdout pipes are attached. */
194
char* PipeFileSTDOUT;
195
char* PipeFileSTDERR;
197
/* Whether each pipe is shared with the parent process. */
199
int PipeSharedSTDOUT;
200
int PipeSharedSTDERR;
202
/* Handle to automatically delete the Win9x forwarding executable. */
205
/* ------------- Data managed per call to Execute ------------- */
207
/* The exceptional behavior that terminated the process, if any. */
210
/* The process exit code. */
213
/* The process return code, if any. */
216
/* Index of last pipe to report data, if any. */
219
/* Index shared by threads to report data. */
222
/* The timeout length. */
225
/* Time at which the child started. */
226
kwsysProcessTime StartTime;
228
/* Time at which the child will timeout. Negative for no timeout. */
229
kwsysProcessTime TimeoutTime;
231
/* Flag for whether the process was killed. */
234
/* Flag for whether the timeout expired. */
237
/* Flag for whether the process has terminated. */
240
/* The number of pipes still open during execution and while waiting
241
for pipes to close after process termination. */
244
/* Buffer for error messages (possibly from Win9x child). */
245
char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
247
/* Description for the ExitException. */
248
char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1];
250
/* Windows process information data. */
251
PROCESS_INFORMATION* ProcessInformation;
253
/* Data and process termination events for which to wait. */
254
PHANDLE ProcessEvents;
255
int ProcessEventsLength;
257
/* Real working directory of our own process. */
258
DWORD RealWorkingDirectoryLength;
259
char* RealWorkingDirectory;
262
/*--------------------------------------------------------------------------*/
263
kwsysProcess* kwsysProcess_New()
267
/* Process control structure. */
270
/* Path to Win9x forwarding executable. */
273
/* Windows version number data. */
276
/* Allocate a process control structure. */
277
cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
280
/* Could not allocate memory for the control structure. */
283
ZeroMemory(cp, sizeof(*cp));
285
/* Share stdin with the parent process by default. */
286
cp->PipeSharedSTDIN = 1;
288
/* Set initial status. */
289
cp->State = kwsysProcess_State_Starting;
291
/* Choose a method of running the child based on version of
293
ZeroMemory(&osv, sizeof(osv));
294
osv.dwOSVersionInfoSize = sizeof(osv);
296
if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
298
/* This is Win9x. We need the console forwarding executable to
299
work-around a Windows 9x bug. */
300
char fwdName[_MAX_FNAME+1] = "";
301
char tempDir[_MAX_PATH+1] = "";
303
/* We will try putting the executable in the system temp
304
directory. Note that the returned path already has a trailing
306
DWORD length = GetTempPath(_MAX_PATH+1, tempDir);
308
/* Construct the executable name from the process id and kwsysProcess
309
instance. This should be unique. */
310
sprintf(fwdName, KWSYS_NAMESPACE_STRING "pew9xfwd_%u_%p.exe",
311
GetCurrentProcessId(), cp);
313
/* If we have a temp directory, use it. */
314
if(length > 0 && length <= _MAX_PATH)
316
/* Allocate a buffer to hold the forwarding executable path. */
317
size_t tdlen = strlen(tempDir);
318
win9x = (char*)malloc(tdlen + strlen(fwdName) + 2);
321
kwsysProcess_Delete(cp);
325
/* Construct the full path to the forwarding executable. */
326
sprintf(win9x, "%s%s", tempDir, fwdName);
329
/* If we found a place to put the forwarding executable, try to
333
if(!kwsysEncodedWriteArrayProcessFwd9x(win9x))
335
/* Failed to create forwarding executable. Give up. */
337
kwsysProcess_Delete(cp);
341
/* Get a handle to the file that will delete it when closed. */
342
cp->Win9xHandle = CreateFile(win9x, GENERIC_READ, FILE_SHARE_READ, 0,
343
OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
344
if(cp->Win9xHandle == INVALID_HANDLE_VALUE)
346
/* We were not able to get a read handle for the forwarding
347
executable. It will not be deleted properly. Give up. */
350
kwsysProcess_Delete(cp);
356
/* Failed to find a place to put forwarding executable. */
357
kwsysProcess_Delete(cp);
362
/* Save the path to the forwarding executable. */
365
/* Initially no thread owns the mutex. Initialize semaphore to 1. */
366
if(!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0)))
368
kwsysProcess_Delete(cp);
372
/* Initially no data are available. Initialize semaphore to 0. */
373
if(!(cp->Full = CreateSemaphore(0, 0, 1, 0)))
375
kwsysProcess_Delete(cp);
381
SECURITY_ATTRIBUTES sa;
382
ZeroMemory(&sa, sizeof(sa));
383
sa.nLength = sizeof(sa);
384
sa.bInheritHandle = TRUE;
386
/* Create an event to tell the forwarding executable to resume the
388
if(!(cp->Win9xResumeEvent = CreateEvent(&sa, TRUE, 0, 0)))
390
kwsysProcess_Delete(cp);
394
/* Create an event to tell the forwarding executable to kill the
396
if(!(cp->Win9xKillEvent = CreateEvent(&sa, TRUE, 0, 0)))
398
kwsysProcess_Delete(cp);
403
/* Create the thread to read each pipe. */
404
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
408
/* Assign the thread its index. */
409
cp->Pipe[i].Index = i;
411
/* Give the thread a pointer back to the kwsysProcess instance. */
412
cp->Pipe[i].Process = cp;
414
/* The pipe is not yet ready to read. Initialize semaphore to 0. */
415
if(!(cp->Pipe[i].Ready = CreateSemaphore(0, 0, 1, 0)))
417
kwsysProcess_Delete(cp);
421
/* The pipe is not yet reset. Initialize semaphore to 0. */
422
if(!(cp->Pipe[i].Reset = CreateSemaphore(0, 0, 1, 0)))
424
kwsysProcess_Delete(cp);
428
/* The thread's buffer is initially empty. Initialize semaphore to 1. */
429
if(!(cp->Pipe[i].Empty = CreateSemaphore(0, 1, 1, 0)))
431
kwsysProcess_Delete(cp);
435
/* Create the thread. It will block immediately. The thread will
436
not make deeply nested calls, so we need only a small
438
if(!(cp->Pipe[i].Thread = CreateThread(0, 1024, kwsysProcessPipeThread,
439
&cp->Pipe[i], 0, &dummy)))
441
kwsysProcess_Delete(cp);
449
/*--------------------------------------------------------------------------*/
450
void kwsysProcess_Delete(kwsysProcess* cp)
454
/* Make sure we have an instance. */
460
/* If the process is executing, wait for it to finish. */
461
if(cp->State == kwsysProcess_State_Executing)
463
kwsysProcess_WaitForExit(cp, 0);
466
/* We are deleting the kwsysProcess instance. */
469
/* Terminate each of the threads. */
470
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
472
if(cp->Pipe[i].Thread)
474
/* Signal the thread we are ready for it. It will terminate
475
immediately since Deleting is set. */
476
ReleaseSemaphore(cp->Pipe[i].Ready, 1, 0);
478
/* Wait for the thread to exit. */
479
WaitForSingleObject(cp->Pipe[i].Thread, INFINITE);
481
/* Close the handle to the thread. */
482
kwsysProcessCleanupHandle(&cp->Pipe[i].Thread);
485
/* Cleanup the pipe's semaphores. */
486
kwsysProcessCleanupHandle(&cp->Pipe[i].Ready);
487
kwsysProcessCleanupHandle(&cp->Pipe[i].Empty);
490
/* Close the shared semaphores. */
491
kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
492
kwsysProcessCleanupHandle(&cp->Full);
494
/* Close the Win9x resume and kill event handles. */
497
kwsysProcessCleanupHandle(&cp->Win9xResumeEvent);
498
kwsysProcessCleanupHandle(&cp->Win9xKillEvent);
502
kwsysProcess_SetCommand(cp, 0);
503
kwsysProcess_SetWorkingDirectory(cp, 0);
504
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
505
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
506
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
507
if(cp->CommandExitCodes)
509
free(cp->CommandExitCodes);
513
/* Close our handle to the forwarding executable file. This will
514
cause it to be deleted. */
515
kwsysProcessCleanupHandle(&cp->Win9xHandle);
520
/*--------------------------------------------------------------------------*/
521
int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
528
for(i=0; i < cp->NumberOfCommands; ++i)
530
free(cp->Commands[i]);
532
cp->NumberOfCommands = 0;
540
return kwsysProcess_AddCommand(cp, command);
545
/*--------------------------------------------------------------------------*/
546
int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
548
int newNumberOfCommands;
551
/* Make sure we have a command to add. */
557
/* Allocate a new array for command pointers. */
558
newNumberOfCommands = cp->NumberOfCommands + 1;
559
if(!(newCommands = (char**)malloc(sizeof(char*) * newNumberOfCommands)))
565
/* Copy any existing commands into the new array. */
568
for(i=0; i < cp->NumberOfCommands; ++i)
570
newCommands[i] = cp->Commands[i];
574
/* We need to construct a single string representing the command
575
and its arguments. We will surround each argument containing
576
spaces with double-quotes. Inside a double-quoted argument, we
577
need to escape double-quotes and all backslashes before them.
578
We also need to escape backslashes at the end of an argument
579
because they come before the closing double-quote for the
583
char const* const* arg;
585
/* First determine the length of the final string. */
586
for(arg = command; *arg; ++arg)
588
/* Keep track of how many backslashes have been encountered in a
589
row in this argument. */
594
/* Scan the string for spaces. If there are no spaces, we can
595
pass the argument verbatim. */
598
if(*c == ' ' || *c == '\t')
605
/* Add the length of the argument, plus 1 for the space
606
separating the arguments. */
607
length += (int)strlen(*arg) + 1;
611
/* Add 2 for double quotes since spaces are present. */
614
/* Scan the string to find characters that need escaping. */
619
/* Found a backslash. It may need to be escaped later. */
624
/* Found a double-quote. We need to escape it and all
625
immediately preceding backslashes. */
626
length += backslashes + 1;
631
/* Found another character. This eliminates the possibility
632
that any immediately preceding backslashes will be
638
/* We need to escape all ending backslashes. */
639
length += backslashes;
643
/* Allocate enough space for the command. We do not need an extra
644
byte for the terminating null because we allocated a space for
645
the first argument that we will not use. */
646
newCommands[cp->NumberOfCommands] = (char*)malloc(length);
647
if(!newCommands[cp->NumberOfCommands])
654
/* Construct the command line in the allocated buffer. */
655
cmd = newCommands[cp->NumberOfCommands];
656
for(arg = command; *arg; ++arg)
658
/* Keep track of how many backslashes have been encountered in a
659
row in an argument. */
664
/* Scan the string for spaces. If there are no spaces, we can
665
pass the argument verbatim. */
668
if(*c == ' ' || *c == '\t')
675
/* Add the separating space if this is not the first argument. */
683
/* Add the opening double-quote for this argument. */
686
/* Add the characters of the argument, possibly escaping them. */
691
/* Found a backslash. It may need to be escaped later. */
697
/* Add enough backslashes to escape any that preceded the
699
while(backslashes > 0)
705
/* Add the backslash to escape the double-quote. */
708
/* Add the double-quote itself. */
713
/* We encountered a normal character. This eliminates any
714
escaping needed for preceding backslashes. Add the
721
/* Add enough backslashes to escape any trailing ones. */
722
while(backslashes > 0)
728
/* Add the closing double-quote for this argument. */
733
/* No spaces. Add the argument verbatim. */
741
/* Add the terminating null character to the command line. */
745
/* Save the new array of commands. */
747
cp->Commands = newCommands;
748
cp->NumberOfCommands = newNumberOfCommands;
752
/*--------------------------------------------------------------------------*/
753
void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
759
cp->Timeout = timeout;
766
/*--------------------------------------------------------------------------*/
767
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
773
if(cp->WorkingDirectory)
775
free(cp->WorkingDirectory);
776
cp->WorkingDirectory = 0;
780
/* We must convert the working directory to a full path. */
781
DWORD length = GetFullPathName(dir, 0, 0, 0);
784
cp->WorkingDirectory = (char*)malloc(length);
785
if(!cp->WorkingDirectory)
789
if(!GetFullPathName(dir, length, cp->WorkingDirectory, 0))
791
free(cp->WorkingDirectory);
792
cp->WorkingDirectory = 0;
800
/*--------------------------------------------------------------------------*/
801
int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
810
case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break;
811
case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break;
812
case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break;
822
*pfile = malloc(strlen(file)+1);
827
strcpy(*pfile, file);
830
/* If we are redirecting the pipe, do not share it. */
833
kwsysProcess_SetPipeShared(cp, pipe, 0);
839
/*--------------------------------------------------------------------------*/
840
void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
849
case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break;
850
case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break;
851
case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break;
855
/* If we are sharing the pipe, do not redirect it to a file. */
858
kwsysProcess_SetPipeFile(cp, pipe, 0);
862
/*--------------------------------------------------------------------------*/
863
int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
872
case kwsysProcess_Option_HideWindow: return cp->HideWindow;
877
/*--------------------------------------------------------------------------*/
878
void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
887
case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
892
/*--------------------------------------------------------------------------*/
893
int kwsysProcess_GetState(kwsysProcess* cp)
895
return cp? cp->State : kwsysProcess_State_Error;
898
/*--------------------------------------------------------------------------*/
899
int kwsysProcess_GetExitException(kwsysProcess* cp)
901
return cp? cp->ExitException : kwsysProcess_Exception_Other;
904
/*--------------------------------------------------------------------------*/
905
int kwsysProcess_GetExitValue(kwsysProcess* cp)
907
return cp? cp->ExitValue : -1;
910
/*--------------------------------------------------------------------------*/
911
int kwsysProcess_GetExitCode(kwsysProcess* cp)
913
return cp? cp->ExitCode : 0;
916
/*--------------------------------------------------------------------------*/
917
const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
921
return "Process management structure could not be allocated";
923
else if(cp->State == kwsysProcess_State_Error)
925
return cp->ErrorMessage;
930
/*--------------------------------------------------------------------------*/
931
const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
935
return "GetExceptionString called with NULL process management structure";
937
else if(cp->State == kwsysProcess_State_Exception)
939
return cp->ExitExceptionString;
941
return "No exception";
944
/*--------------------------------------------------------------------------*/
945
void kwsysProcess_Execute(kwsysProcess* cp)
949
/* Child startup control data. */
950
kwsysProcessCreateInformation si;
952
/* Do not execute a second time. */
953
if(!cp || cp->State == kwsysProcess_State_Executing)
958
/* Initialize the control structure for a new process. */
959
if(!kwsysProcessInitialize(cp))
961
strcpy(cp->ErrorMessage, "Out of memory");
962
cp->State = kwsysProcess_State_Error;
966
/* Save the real working directory of this process and change to
967
the working directory for the child processes. This is needed
968
to make pipe file paths evaluate correctly. */
969
if(cp->WorkingDirectory)
971
if(!GetCurrentDirectory(cp->RealWorkingDirectoryLength,
972
cp->RealWorkingDirectory))
974
kwsysProcessCleanup(cp, 1);
977
SetCurrentDirectory(cp->WorkingDirectory);
980
/* Reset the Win9x resume and kill events. */
983
if(!ResetEvent(cp->Win9xResumeEvent))
985
kwsysProcessCleanup(cp, 1);
988
if(!ResetEvent(cp->Win9xKillEvent))
990
kwsysProcessCleanup(cp, 1);
995
/* Initialize startup info data. */
996
ZeroMemory(&si, sizeof(si));
997
si.StartupInfo.cb = sizeof(si.StartupInfo);
999
/* Decide whether a child window should be shown. */
1000
si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
1001
si.StartupInfo.wShowWindow =
1002
(unsigned short)(cp->HideWindow?SW_HIDE:SW_SHOWDEFAULT);
1004
/* Connect the child's output pipes to the threads. */
1005
si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
1007
/* Create stderr pipe to be shared by all processes in the pipeline.
1008
Neither end is directly inherited. */
1009
if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
1010
&cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0))
1012
kwsysProcessCleanup(cp, 1);
1016
/* Create an inherited duplicate of the write end, but do not
1017
close the non-inherited version. We need to keep it open
1018
to use in waking up the pipe threads. */
1019
if(!DuplicateHandle(GetCurrentProcess(), cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
1020
GetCurrentProcess(), &si.StartupInfo.hStdError,
1021
0, TRUE, DUPLICATE_SAME_ACCESS))
1023
kwsysProcessCleanup(cp, 1);
1024
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
1028
/* Replace the stderr pipe with a file if requested. In this case
1029
the pipe thread will still run but never report data. */
1030
if(cp->PipeFileSTDERR)
1032
if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError,
1033
cp->PipeFileSTDERR))
1035
kwsysProcessCleanup(cp, 1);
1036
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
1041
/* Replace the stderr pipe with the parent process's if requested.
1042
In this case the pipe thread will still run but never report
1044
if(cp->PipeSharedSTDERR)
1046
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
1047
si.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1050
/* Create the pipeline of processes. */
1053
for(i=0; i < cp->NumberOfCommands; ++i)
1055
if(kwsysProcessCreate(cp, i, &si, &readEnd))
1057
cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess;
1061
kwsysProcessCleanup(cp, 1);
1063
/* Release resources that may have been allocated for this
1064
process before an error occurred. */
1065
kwsysProcessCleanupHandle(&readEnd);
1066
if(si.StartupInfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE))
1068
kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput);
1070
if(si.StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
1072
kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
1074
if(si.StartupInfo.hStdOutput != GetStdHandle(STD_ERROR_HANDLE))
1076
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
1078
kwsysProcessCleanupHandle(&si.ErrorPipeRead);
1079
kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
1084
/* Save a handle to the output pipe for the last process. */
1085
cp->Pipe[KWSYSPE_PIPE_STDOUT].Read = readEnd;
1088
/* Close the inherited handles to the stderr pipe shared by all
1089
processes in the pipeline. */
1090
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
1092
/* Restore the working directory. */
1093
if(cp->RealWorkingDirectory)
1095
SetCurrentDirectory(cp->RealWorkingDirectory);
1096
free(cp->RealWorkingDirectory);
1097
cp->RealWorkingDirectory = 0;
1100
/* The timeout period starts now. */
1101
cp->StartTime = kwsysProcessTimeGetCurrent();
1102
cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
1104
/* All processes in the pipeline have been started in suspended
1105
mode. Resume them all now. */
1108
SetEvent(cp->Win9xResumeEvent);
1112
for(i=0; i < cp->NumberOfCommands; ++i)
1114
ResumeThread(cp->ProcessInformation[i].hThread);
1118
/* ---- It is no longer safe to call kwsysProcessCleanup. ----- */
1119
/* Tell the pipe threads that a process has started. */
1120
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1122
ReleaseSemaphore(cp->Pipe[i].Ready, 1, 0);
1125
/* We don't care about the children's main threads. */
1126
for(i=0; i < cp->NumberOfCommands; ++i)
1128
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
1131
/* No pipe has reported data. */
1132
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1133
cp->PipesLeft = KWSYSPE_PIPE_COUNT;
1135
/* The process has now started. */
1136
cp->State = kwsysProcess_State_Executing;
1139
/*--------------------------------------------------------------------------*/
1141
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
1142
double* userTimeout)
1144
kwsysProcessTime userStartTime;
1145
kwsysProcessTime timeoutLength;
1146
kwsysProcessTime timeoutTime;
1151
int pipeId = kwsysProcess_Pipe_None;
1154
/* Make sure we are executing a process. */
1155
if(!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
1158
return kwsysProcess_Pipe_None;
1161
/* Record the time at which user timeout period starts. */
1162
userStartTime = kwsysProcessTimeGetCurrent();
1164
/* Calculate the time at which a timeout will expire, and whether it
1165
is the user or process timeout. */
1166
user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
1168
/* Loop until we have a reason to return. */
1169
while(!done && cp->PipesLeft > 0)
1171
/* If we previously got data from a thread, let it know we are
1172
done with the data. */
1173
if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
1175
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
1176
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1179
/* Setup a timeout if required. */
1180
if(kwsysProcessGetTimeoutLeft(&timeoutTime, &timeoutLength))
1182
/* Timeout has already expired. */
1186
if(timeoutTime.QuadPart < 0)
1192
timeout = kwsysProcessTimeToDWORD(timeoutLength);
1195
/* Wait for a pipe's thread to signal or a process to terminate. */
1196
w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents,
1198
if(w == WAIT_TIMEOUT)
1200
/* Timeout has expired. */
1204
else if(w == WAIT_OBJECT_0)
1206
/* Save the index of the reporting thread and release the mutex.
1207
The thread will block until we signal its Empty mutex. */
1208
cp->CurrentIndex = cp->SharedIndex;
1209
ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
1211
/* Data are available or a pipe closed. */
1212
if(cp->Pipe[cp->CurrentIndex].Closed)
1214
/* The pipe closed. */
1217
else if(data && length)
1219
/* Report this data. */
1220
*data = cp->Pipe[cp->CurrentIndex].DataBuffer;
1221
*length = cp->Pipe[cp->CurrentIndex].DataLength;
1222
switch(cp->CurrentIndex)
1224
case KWSYSPE_PIPE_STDOUT:
1225
pipeId = kwsysProcess_Pipe_STDOUT; break;
1226
case KWSYSPE_PIPE_STDERR:
1227
pipeId = kwsysProcess_Pipe_STDERR; break;
1234
/* A process has terminated. */
1235
kwsysProcessDestroy(cp, w-WAIT_OBJECT_0);
1239
/* Update the user timeout. */
1242
kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
1243
kwsysProcessTime difference = kwsysProcessTimeSubtract(userEndTime,
1245
double d = kwsysProcessTimeToDouble(difference);
1247
if(*userTimeout < 0)
1253
/* Check what happened. */
1256
/* Data are ready on a pipe. */
1261
/* A timeout has expired. */
1264
/* The user timeout has expired. It has no time left. */
1265
return kwsysProcess_Pipe_Timeout;
1269
/* The process timeout has expired. Kill the child now. */
1270
kwsysProcess_Kill(cp);
1271
cp->TimeoutExpired = 1;
1273
return kwsysProcess_Pipe_None;
1278
/* The children have terminated and no more data are available. */
1279
return kwsysProcess_Pipe_None;
1283
/*--------------------------------------------------------------------------*/
1284
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
1289
/* Make sure we are executing a process. */
1290
if(!cp || cp->State != kwsysProcess_State_Executing)
1295
/* Wait for the process to terminate. Ignore all data. */
1296
while((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0)
1298
if(pipe == kwsysProcess_Pipe_Timeout)
1300
/* The user timeout has expired. */
1305
/* When the last pipe closes in WaitForData, the loop terminates
1306
without releaseing the pipe's thread. Release it now. */
1307
if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
1309
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
1310
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1313
/* Wait for all pipe threads to reset. */
1314
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1316
WaitForSingleObject(cp->Pipe[i].Reset, INFINITE);
1319
/* ---- It is now safe again to call kwsysProcessCleanup. ----- */
1320
/* Close all the pipes. */
1321
kwsysProcessCleanup(cp, 0);
1323
/* Determine the outcome. */
1326
/* We killed the child. */
1327
cp->State = kwsysProcess_State_Killed;
1329
else if(cp->TimeoutExpired)
1331
/* The timeout expired. */
1332
cp->State = kwsysProcess_State_Expired;
1336
/* The children exited. Report the outcome of the last process. */
1337
cp->ExitCode = cp->CommandExitCodes[cp->NumberOfCommands-1];
1338
if((cp->ExitCode & 0xF0000000) == 0xC0000000)
1340
/* Child terminated due to exceptional behavior. */
1341
cp->State = kwsysProcess_State_Exception;
1343
kwsysProcessSetExitException(cp, cp->ExitCode);
1347
/* Child exited without exception. */
1348
cp->State = kwsysProcess_State_Exited;
1349
cp->ExitException = kwsysProcess_Exception_None;
1350
cp->ExitValue = cp->ExitCode;
1357
/*--------------------------------------------------------------------------*/
1358
void kwsysProcess_Kill(kwsysProcess* cp)
1362
/* Make sure we are executing a process. */
1363
if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
1364
cp->Killed || cp->Terminated)
1369
/* If we are killing a process that just reported data, release
1370
the pipe's thread. */
1371
if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
1373
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
1374
cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1377
/* Wake up all the pipe threads with dummy data. */
1378
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1381
WriteFile(cp->Pipe[i].Write, "", 1, &dummy, 0);
1384
/* Tell pipe threads to reset until we run another process. */
1385
while(cp->PipesLeft > 0)
1387
WaitForSingleObject(cp->Full, INFINITE);
1388
cp->CurrentIndex = cp->SharedIndex;
1389
ReleaseSemaphore(cp->SharedIndexMutex, 1, 0);
1390
cp->Pipe[cp->CurrentIndex].Closed = 1;
1391
ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
1395
/* Kill the children. */
1399
/* Windows 9x. Tell the forwarding executable to kill the child. */
1400
SetEvent(cp->Win9xKillEvent);
1404
/* Not Windows 9x. Just terminate the children. */
1405
for(i=0; i < cp->NumberOfCommands; ++i)
1407
kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
1411
/* We are killing the children and ignoring all data. Do not wait
1412
for them to exit. */
1415
/*--------------------------------------------------------------------------*/
1418
Function executed for each pipe's thread. Argument is a pointer to
1419
the kwsysProcessPipeData instance for this thread.
1421
DWORD WINAPI kwsysProcessPipeThread(LPVOID ptd)
1423
kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
1424
kwsysProcess* cp = td->Process;
1426
/* Wait for a process to be ready. */
1427
while((WaitForSingleObject(td->Ready, INFINITE), !cp->Deleting))
1429
/* Read output from the process for this thread's pipe. */
1430
kwsysProcessPipeThreadReadPipe(cp, td);
1432
/* We were signalled to exit with our buffer empty. Reset the
1433
mutex for a new process. */
1434
ReleaseSemaphore(td->Empty, 1, 0);
1436
/* Signal the main thread we have reset for a new process. */
1437
ReleaseSemaphore(td->Reset, 1, 0);
1442
/*--------------------------------------------------------------------------*/
1445
Function called in each pipe's thread to handle data for one
1446
execution of a subprocess.
1448
void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td)
1450
/* Wait for space in the thread's buffer. */
1451
while((WaitForSingleObject(td->Empty, INFINITE), !td->Closed))
1453
/* Read data from the pipe. This may block until data are available. */
1454
if(!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE,
1455
&td->DataLength, 0))
1457
if(GetLastError() != ERROR_BROKEN_PIPE)
1459
/* UNEXPECTED failure to read the pipe. */
1462
/* The pipe closed. There are no more data to read. */
1466
/* Wait for our turn to be handled by the main thread. */
1467
WaitForSingleObject(cp->SharedIndexMutex, INFINITE);
1469
/* Tell the main thread we have something to report. */
1470
cp->SharedIndex = td->Index;
1471
ReleaseSemaphore(cp->Full, 1, 0);
1475
/*--------------------------------------------------------------------------*/
1476
/* Initialize a process control structure for kwsysProcess_Execute. */
1477
int kwsysProcessInitialize(kwsysProcess* cp)
1479
/* Reset internal status flags. */
1480
cp->TimeoutExpired = 0;
1483
cp->ExitException = kwsysProcess_Exception_None;
1487
/* Reset error data. */
1488
cp->ErrorMessage[0] = 0;
1489
strcpy(cp->ExitExceptionString, "No exception");
1491
/* Allocate process information for each process. */
1492
cp->ProcessInformation =
1493
(PROCESS_INFORMATION*)malloc(sizeof(PROCESS_INFORMATION) *
1494
cp->NumberOfCommands);
1495
if(!cp->ProcessInformation)
1499
ZeroMemory(cp->ProcessInformation,
1500
sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
1501
if(cp->CommandExitCodes)
1503
free(cp->CommandExitCodes);
1505
cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD)*cp->NumberOfCommands);
1506
if(!cp->CommandExitCodes)
1510
ZeroMemory(cp->CommandExitCodes, sizeof(DWORD)*cp->NumberOfCommands);
1512
/* Allocate event wait array. The first event is cp->Full, the rest
1513
are the process termination events. */
1514
cp->ProcessEvents = (PHANDLE)malloc(sizeof(HANDLE)*(cp->NumberOfCommands+1));
1515
if(!cp->ProcessEvents)
1519
ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands+1));
1520
cp->ProcessEvents[0] = cp->Full;
1521
cp->ProcessEventsLength = cp->NumberOfCommands+1;
1523
/* Allocate space to save the real working directory of this process. */
1524
if(cp->WorkingDirectory)
1526
cp->RealWorkingDirectoryLength = GetCurrentDirectory(0, 0);
1527
if(cp->RealWorkingDirectoryLength > 0)
1529
cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength);
1530
if(!cp->RealWorkingDirectory)
1540
/*--------------------------------------------------------------------------*/
1541
int kwsysProcessCreate(kwsysProcess* cp, int index,
1542
kwsysProcessCreateInformation* si,
1545
/* Setup the process's stdin. */
1548
/* Create an inherited duplicate of the read end from the output
1549
pipe of the previous process. This also closes the
1550
non-inherited version. */
1551
if(!DuplicateHandle(GetCurrentProcess(), *readEnd,
1552
GetCurrentProcess(), readEnd,
1553
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
1554
DUPLICATE_SAME_ACCESS)))
1558
si->StartupInfo.hStdInput = *readEnd;
1560
/* This function is done with this handle. */
1563
else if(cp->PipeFileSTDIN)
1565
/* Create a handle to read a file for stdin. */
1566
HANDLE fin = CreateFile(cp->PipeFileSTDIN, GENERIC_READ,
1567
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
1568
if(fin == INVALID_HANDLE_VALUE)
1572
/* Create an inherited duplicate of the handle. This also closes
1573
the non-inherited version. */
1574
if(!DuplicateHandle(GetCurrentProcess(), fin,
1575
GetCurrentProcess(), &fin,
1576
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
1577
DUPLICATE_SAME_ACCESS)))
1581
si->StartupInfo.hStdInput = fin;
1583
else if(cp->PipeSharedSTDIN)
1585
si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1589
si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE;
1592
/* Setup the process's stdout. */
1594
DWORD maybeClose = DUPLICATE_CLOSE_SOURCE;
1597
/* Create the output pipe for this process. Neither end is directly
1599
if(!CreatePipe(readEnd, &writeEnd, 0, 0))
1604
/* Create an inherited duplicate of the write end. Close the
1605
non-inherited version unless this is the last process. Save the
1606
non-inherited write end of the last process. */
1607
if(index == cp->NumberOfCommands-1)
1609
cp->Pipe[KWSYSPE_PIPE_STDOUT].Write = writeEnd;
1612
if(!DuplicateHandle(GetCurrentProcess(), writeEnd,
1613
GetCurrentProcess(), &writeEnd,
1614
0, TRUE, (maybeClose | DUPLICATE_SAME_ACCESS)))
1618
si->StartupInfo.hStdOutput = writeEnd;
1621
/* Replace the stdout pipe with a file if requested. In this case
1622
the pipe thread will still run but never report data. */
1623
if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT)
1625
if(!kwsysProcessSetupOutputPipeFile(&si->StartupInfo.hStdOutput,
1626
cp->PipeFileSTDOUT))
1632
/* Replace the stdout pipe with the parent process's if requested.
1633
In this case the pipe thread will still run but never report
1635
if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT)
1637
kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
1638
si->StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1641
/* Create the child process. */
1647
/* Create an error reporting pipe for the forwarding executable.
1648
Neither end is directly inherited. */
1649
if(!CreatePipe(&si->ErrorPipeRead, &si->ErrorPipeWrite, 0, 0))
1654
/* Create an inherited duplicate of the write end. This also closes
1655
the non-inherited version. */
1656
if(!DuplicateHandle(GetCurrentProcess(), si->ErrorPipeWrite,
1657
GetCurrentProcess(), &si->ErrorPipeWrite,
1658
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
1659
DUPLICATE_SAME_ACCESS)))
1664
/* The forwarding executable is given a handle to the error pipe
1665
and resume and kill events. */
1666
realCommand = malloc(strlen(cp->Win9x)+strlen(cp->Commands[index])+100);
1671
sprintf(realCommand, "%s %p %p %p %d %s", cp->Win9x,
1672
si->ErrorPipeWrite, cp->Win9xResumeEvent, cp->Win9xKillEvent,
1673
cp->HideWindow, cp->Commands[index]);
1677
realCommand = cp->Commands[index];
1680
/* Create the child in a suspended state so we can wait until all
1681
children have been created before running any one. */
1682
r = CreateProcess(0, realCommand, 0, 0, TRUE,
1683
cp->Win9x? 0 : CREATE_SUSPENDED, 0, 0,
1684
&si->StartupInfo, &cp->ProcessInformation[index]);
1691
/* Close the error pipe write end so we can detect when the
1692
forwarding executable closes it. */
1693
kwsysProcessCleanupHandle(&si->ErrorPipeWrite);
1696
/* Wait for the forwarding executable to report an error or
1697
close the error pipe to report success. */
1700
while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0)
1702
if(ReadFile(si->ErrorPipeRead, cp->ErrorMessage+total,
1703
KWSYSPE_PIPE_BUFFER_SIZE-total, &n, 0))
1712
if(total > 0 || GetLastError() != ERROR_BROKEN_PIPE)
1714
/* The forwarding executable could not run the process, or
1715
there was an error reading from its error pipe. Preserve
1716
the last error while cleaning up the forwarding executable
1717
so the cleanup our caller does reports the proper error. */
1718
DWORD error = GetLastError();
1719
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread);
1720
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
1721
SetLastError(error);
1725
kwsysProcessCleanupHandle(&si->ErrorPipeRead);
1734
/* Successfully created this child process. */
1737
/* Close our handle to the input pipe for the current process. */
1738
kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
1741
if(si->StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
1743
/* The parent process does not need the inhertied pipe write end. */
1744
kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
1750
/*--------------------------------------------------------------------------*/
1751
void kwsysProcessDestroy(kwsysProcess* cp, int event)
1756
/* Find the process index for the termination event. */
1757
for(index=0; index < cp->NumberOfCommands; ++index)
1759
if(cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event])
1765
/* Check the exit code of the process. */
1766
GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
1767
&cp->CommandExitCodes[index]);
1769
/* Close the process handle for the terminated process. */
1770
kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess);
1772
/* Remove the process from the available events. */
1773
cp->ProcessEventsLength -= 1;
1774
for(i=event; i < cp->ProcessEventsLength; ++i)
1776
cp->ProcessEvents[i] = cp->ProcessEvents[i+1];
1779
/* Check if all processes have terminated. */
1780
if(cp->ProcessEventsLength == 1)
1784
/* Close our copies of the pipe write handles so the pipe threads
1785
can detect end-of-data. */
1786
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1788
kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
1793
/*--------------------------------------------------------------------------*/
1794
int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
1802
/* Close the existing inherited handle. */
1803
kwsysProcessCleanupHandle(phandle);
1805
/* Create a handle to write a file for the pipe. */
1806
fout = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, 0,
1807
CREATE_ALWAYS, 0, 0);
1808
if(fout == INVALID_HANDLE_VALUE)
1813
/* Create an inherited duplicate of the handle. This also closes
1814
the non-inherited version. */
1815
if(!DuplicateHandle(GetCurrentProcess(), fout,
1816
GetCurrentProcess(), &fout,
1817
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
1818
DUPLICATE_SAME_ACCESS)))
1823
/* Assign the replacement handle. */
1828
/*--------------------------------------------------------------------------*/
1830
/* Close the given handle if it is open. Reset its value to 0. */
1831
void kwsysProcessCleanupHandle(PHANDLE h)
1840
/*--------------------------------------------------------------------------*/
1842
/* Close all handles created by kwsysProcess_Execute. */
1843
void kwsysProcessCleanup(kwsysProcess* cp, int error)
1847
/* If this is an error case, report the error. */
1850
/* Construct an error message if one has not been provided already. */
1851
if(cp->ErrorMessage[0] == 0)
1853
/* Format the error message. */
1854
DWORD original = GetLastError();
1855
DWORD length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
1856
FORMAT_MESSAGE_IGNORE_INSERTS, 0, original,
1857
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1858
cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, 0);
1861
/* FormatMessage failed. Use a default message. */
1862
_snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE,
1863
"Process execution failed with error 0x%X. "
1864
"FormatMessage failed with error 0x%X",
1865
original, GetLastError());
1869
/* Remove trailing period and newline, if any. */
1870
kwsysProcessCleanErrorMessage(cp);
1872
/* Set the error state. */
1873
cp->State = kwsysProcess_State_Error;
1875
/* Cleanup any processes already started in a suspended state. */
1876
if(cp->ProcessInformation)
1880
SetEvent(cp->Win9xKillEvent);
1884
for(i=0; i < cp->NumberOfCommands; ++i)
1886
if(cp->ProcessInformation[i].hProcess)
1888
TerminateProcess(cp->ProcessInformation[i].hProcess, 255);
1889
WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE);
1893
for(i=0; i < cp->NumberOfCommands; ++i)
1895
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
1896
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
1900
/* Restore the working directory. */
1901
if(cp->RealWorkingDirectory)
1903
SetCurrentDirectory(cp->RealWorkingDirectory);
1908
if(cp->ProcessInformation)
1910
free(cp->ProcessInformation);
1911
cp->ProcessInformation = 0;
1913
if(cp->ProcessEvents)
1915
free(cp->ProcessEvents);
1916
cp->ProcessEvents = 0;
1918
if(cp->RealWorkingDirectory)
1920
free(cp->RealWorkingDirectory);
1921
cp->RealWorkingDirectory = 0;
1924
/* Close each pipe. */
1925
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1927
kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
1928
kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
1932
/*--------------------------------------------------------------------------*/
1933
void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
1935
/* Remove trailing period and newline, if any. */
1936
int length = strlen(cp->ErrorMessage);
1937
if(cp->ErrorMessage[length-1] == '\n')
1939
cp->ErrorMessage[length-1] = 0;
1941
if(length > 0 && cp->ErrorMessage[length-1] == '\r')
1943
cp->ErrorMessage[length-1] = 0;
1947
if(length > 0 && cp->ErrorMessage[length-1] == '.')
1949
cp->ErrorMessage[length-1] = 0;
1953
/*--------------------------------------------------------------------------*/
1954
/* Get the time at which either the process or user timeout will
1955
expire. Returns 1 if the user timeout is first, and 0 otherwise. */
1956
int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
1957
kwsysProcessTime* timeoutTime)
1959
/* The first time this is called, we need to calculate the time at
1960
which the child will timeout. */
1961
if(cp->Timeout && cp->TimeoutTime.QuadPart < 0)
1963
kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout);
1964
cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length);
1967
/* Start with process timeout. */
1968
*timeoutTime = cp->TimeoutTime;
1970
/* Check if the user timeout is earlier. */
1973
kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
1974
kwsysProcessTime userTimeoutLength = kwsysProcessTimeFromDouble(*userTimeout);
1975
kwsysProcessTime userTimeoutTime = kwsysProcessTimeAdd(currentTime,
1977
if(kwsysProcessTimeLess(userTimeoutTime, *timeoutTime))
1979
*timeoutTime = userTimeoutTime;
1986
/*--------------------------------------------------------------------------*/
1987
/* Get the length of time before the given timeout time arrives.
1988
Returns 1 if the time has already arrived, and 0 otherwise. */
1989
int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
1990
kwsysProcessTime* timeoutLength)
1992
if(timeoutTime->QuadPart < 0)
1994
/* No timeout time has been requested. */
1999
/* Calculate the remaining time. */
2000
kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
2001
*timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime);
2002
if(timeoutLength->QuadPart < 0)
2004
/* Timeout has already expired. */
2009
/* There is some time left. */
2015
/*--------------------------------------------------------------------------*/
2016
kwsysProcessTime kwsysProcessTimeGetCurrent()
2018
kwsysProcessTime current;
2020
GetSystemTimeAsFileTime(&ft);
2021
current.LowPart = ft.dwLowDateTime;
2022
current.HighPart = ft.dwHighDateTime;
2026
/*--------------------------------------------------------------------------*/
2027
DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t)
2029
return (DWORD)(t.QuadPart * 0.0001);
2032
/*--------------------------------------------------------------------------*/
2033
double kwsysProcessTimeToDouble(kwsysProcessTime t)
2035
return t.QuadPart * 0.0000001;
2038
/*--------------------------------------------------------------------------*/
2039
kwsysProcessTime kwsysProcessTimeFromDouble(double d)
2042
t.QuadPart = (LONGLONG)(d*10000000);
2046
/*--------------------------------------------------------------------------*/
2047
int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
2049
return in1.QuadPart < in2.QuadPart;
2052
/*--------------------------------------------------------------------------*/
2053
kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2)
2055
kwsysProcessTime out;
2056
out.QuadPart = in1.QuadPart + in2.QuadPart;
2060
/*--------------------------------------------------------------------------*/
2061
kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2)
2063
kwsysProcessTime out;
2064
out.QuadPart = in1.QuadPart - in2.QuadPart;
2068
/*--------------------------------------------------------------------------*/
2069
#define KWSYSPE_CASE(type, str) \
2070
cp->ExitException = kwsysProcess_Exception_##type; \
2071
strcpy(cp->ExitExceptionString, str)
2072
static void kwsysProcessSetExitException(kwsysProcess* cp, int code)
2076
case STATUS_CONTROL_C_EXIT:
2077
KWSYSPE_CASE(Interrupt, "User interrupt"); break;
2079
case STATUS_FLOAT_DENORMAL_OPERAND:
2080
KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)"); break;
2081
case STATUS_FLOAT_DIVIDE_BY_ZERO:
2082
KWSYSPE_CASE(Numerical, "Divide-by-zero"); break;
2083
case STATUS_FLOAT_INEXACT_RESULT:
2084
KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)"); break;
2085
case STATUS_FLOAT_INVALID_OPERATION:
2086
KWSYSPE_CASE(Numerical, "Invalid floating-point operation"); break;
2087
case STATUS_FLOAT_OVERFLOW:
2088
KWSYSPE_CASE(Numerical, "Floating-point overflow"); break;
2089
case STATUS_FLOAT_STACK_CHECK:
2090
KWSYSPE_CASE(Numerical, "Floating-point stack check failed"); break;
2091
case STATUS_FLOAT_UNDERFLOW:
2092
KWSYSPE_CASE(Numerical, "Floating-point underflow"); break;
2093
#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
2094
case STATUS_FLOAT_MULTIPLE_FAULTS:
2095
KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)"); break;
2097
#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
2098
case STATUS_FLOAT_MULTIPLE_TRAPS:
2099
KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); break;
2101
case STATUS_INTEGER_DIVIDE_BY_ZERO:
2102
KWSYSPE_CASE(Numerical, "Integer divide-by-zero"); break;
2103
case STATUS_INTEGER_OVERFLOW:
2104
KWSYSPE_CASE(Numerical, "Integer overflow"); break;
2106
case STATUS_DATATYPE_MISALIGNMENT:
2107
KWSYSPE_CASE(Fault, "Datatype misalignment"); break;
2108
case STATUS_ACCESS_VIOLATION:
2109
KWSYSPE_CASE(Fault, "Access violation"); break;
2110
case STATUS_IN_PAGE_ERROR:
2111
KWSYSPE_CASE(Fault, "In-page error"); break;
2112
case STATUS_INVALID_HANDLE:
2113
KWSYSPE_CASE(Fault, "Invalid hanlde"); break;
2114
case STATUS_NONCONTINUABLE_EXCEPTION:
2115
KWSYSPE_CASE(Fault, "Noncontinuable exception"); break;
2116
case STATUS_INVALID_DISPOSITION:
2117
KWSYSPE_CASE(Fault, "Invalid disposition"); break;
2118
case STATUS_ARRAY_BOUNDS_EXCEEDED:
2119
KWSYSPE_CASE(Fault, "Array bounds exceeded"); break;
2120
case STATUS_STACK_OVERFLOW:
2121
KWSYSPE_CASE(Fault, "Stack overflow"); break;
2123
case STATUS_ILLEGAL_INSTRUCTION:
2124
KWSYSPE_CASE(Illegal, "Illegal instruction"); break;
2125
case STATUS_PRIVILEGED_INSTRUCTION:
2126
KWSYSPE_CASE(Illegal, "Privileged instruction"); break;
2128
case STATUS_NO_MEMORY:
2130
cp->ExitException = kwsysProcess_Exception_Other;
2131
sprintf(cp->ExitExceptionString, "Exit code 0x%x\n", code);
2137
typedef struct kwsysProcess_List_s kwsysProcess_List;
2138
static kwsysProcess_List* kwsysProcess_List_New();
2139
static void kwsysProcess_List_Delete(kwsysProcess_List* self);
2140
static int kwsysProcess_List_Update(kwsysProcess_List* self);
2141
static int kwsysProcess_List_NextProcess(kwsysProcess_List* self);
2142
static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self);
2143
static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self);
2145
/*--------------------------------------------------------------------------*/
2146
/* Windows NT 4 API definitions. */
2147
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
2148
typedef LONG NTSTATUS;
2149
typedef LONG KPRIORITY;
2150
typedef struct _UNICODE_STRING UNICODE_STRING;
2151
struct _UNICODE_STRING
2154
USHORT MaximumLength;
2158
/* The process information structure. Declare only enough to get
2159
process identifiers. The rest may be ignored because we use the
2160
NextEntryDelta to move through an array of instances. */
2161
typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION;
2162
typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION;
2163
struct _SYSTEM_PROCESS_INFORMATION
2165
ULONG NextEntryDelta;
2168
LARGE_INTEGER CreateTime;
2169
LARGE_INTEGER UserTime;
2170
LARGE_INTEGER KernelTime;
2171
UNICODE_STRING ProcessName;
2172
KPRIORITY BasePriority;
2174
ULONG InheritedFromProcessId;
2177
/*--------------------------------------------------------------------------*/
2178
/* Toolhelp32 API definitions. */
2179
#define TH32CS_SNAPPROCESS 0x00000002
2180
typedef struct tagPROCESSENTRY32 PROCESSENTRY32;
2181
typedef PROCESSENTRY32* LPPROCESSENTRY32;
2182
struct tagPROCESSENTRY32
2186
DWORD th32ProcessID;
2187
DWORD th32DefaultHeapID;
2190
DWORD th32ParentProcessID;
2191
LONG pcPriClassBase;
2193
char szExeFile[MAX_PATH];
2196
/*--------------------------------------------------------------------------*/
2197
/* Windows API function types. */
2198
typedef HANDLE (WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD);
2199
typedef BOOL (WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32);
2200
typedef BOOL (WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32);
2201
typedef NTSTATUS (WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID,
2205
/*--------------------------------------------------------------------------*/
2206
static int kwsysProcess_List__New_NT4(kwsysProcess_List* self);
2207
static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self);
2208
static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self);
2209
static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self);
2210
static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self);
2211
static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self);
2212
static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self);
2213
static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self);
2214
static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self);
2215
static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self);
2216
static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self);
2217
static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self);
2219
struct kwsysProcess_List_s
2221
/* Implementation switches at runtime based on version of Windows. */
2224
/* Implementation functions and data for NT 4. */
2225
ZwQuerySystemInformationType P_ZwQuerySystemInformation;
2228
PSYSTEM_PROCESS_INFORMATION CurrentInfo;
2230
/* Implementation functions and data for other Windows versions. */
2231
CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot;
2232
Process32FirstType P_Process32First;
2233
Process32NextType P_Process32Next;
2235
PROCESSENTRY32 CurrentEntry;
2238
/*--------------------------------------------------------------------------*/
2239
static kwsysProcess_List* kwsysProcess_List_New()
2242
kwsysProcess_List* self;
2244
/* Allocate and initialize the list object. */
2245
if(!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List))))
2249
memset(self, 0, sizeof(*self));
2251
/* Select an implementation. */
2252
ZeroMemory(&osv, sizeof(osv));
2253
osv.dwOSVersionInfoSize = sizeof(osv);
2255
self->NT4 = (osv.dwPlatformId == VER_PLATFORM_WIN32_NT &&
2256
osv.dwMajorVersion < 5)? 1:0;
2258
/* Initialize the selected implementation. */
2260
kwsysProcess_List__New_NT4(self) :
2261
kwsysProcess_List__New_Snapshot(self)))
2263
kwsysProcess_List_Delete(self);
2267
/* Update to the current set of processes. */
2268
if(!kwsysProcess_List_Update(self))
2270
kwsysProcess_List_Delete(self);
2276
/*--------------------------------------------------------------------------*/
2277
static void kwsysProcess_List_Delete(kwsysProcess_List* self)
2283
kwsysProcess_List__Delete_NT4(self);
2287
kwsysProcess_List__Delete_Snapshot(self);
2293
/*--------------------------------------------------------------------------*/
2294
static int kwsysProcess_List_Update(kwsysProcess_List* self)
2296
return self? (self->NT4?
2297
kwsysProcess_List__Update_NT4(self) :
2298
kwsysProcess_List__Update_Snapshot(self)) : 0;
2301
/*--------------------------------------------------------------------------*/
2302
static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self)
2304
return self? (self->NT4?
2305
kwsysProcess_List__GetProcessId_NT4(self) :
2306
kwsysProcess_List__GetProcessId_Snapshot(self)) : -1;
2310
/*--------------------------------------------------------------------------*/
2311
static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self)
2313
return self? (self->NT4?
2314
kwsysProcess_List__GetParentId_NT4(self) :
2315
kwsysProcess_List__GetParentId_Snapshot(self)) : -1;
2319
/*--------------------------------------------------------------------------*/
2320
static int kwsysProcess_List_NextProcess(kwsysProcess_List* self)
2322
return (self? (self->NT4?
2323
kwsysProcess_List__Next_NT4(self) :
2324
kwsysProcess_List__Next_Snapshot(self)) : 0);
2327
/*--------------------------------------------------------------------------*/
2328
static int kwsysProcess_List__New_NT4(kwsysProcess_List* self)
2330
HANDLE hNT = GetModuleHandle("ntdll.dll");
2333
/* Get pointers to the needed API functions. */
2334
self->P_ZwQuerySystemInformation =
2335
((ZwQuerySystemInformationType)
2336
GetProcAddress(hNT, "ZwQuerySystemInformation"));
2339
if(!self->P_ZwQuerySystemInformation)
2344
/* Allocate an initial process information buffer. */
2345
self->BufferSize = 32768;
2346
self->Buffer = (char*)malloc(self->BufferSize);
2347
return self->Buffer? 1:0;
2350
/*--------------------------------------------------------------------------*/
2351
static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self)
2353
/* Free the process information buffer. */
2360
/*--------------------------------------------------------------------------*/
2361
static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self)
2363
self->CurrentInfo = 0;
2366
/* Query number 5 is for system process list. */
2368
self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0);
2369
if(status == STATUS_INFO_LENGTH_MISMATCH)
2371
/* The query requires a bigger buffer. */
2372
int newBufferSize = self->BufferSize * 2;
2373
char* newBuffer = (char*)malloc(newBufferSize);
2377
self->Buffer = newBuffer;
2378
self->BufferSize = newBufferSize;
2385
else if(status >= 0)
2387
/* The query succeeded. Initialize traversal of the process list. */
2388
self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer;
2393
/* The query failed. */
2399
/*--------------------------------------------------------------------------*/
2400
static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
2402
if(self->CurrentInfo)
2404
if(self->CurrentInfo->NextEntryDelta > 0)
2406
self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)
2407
((char*)self->CurrentInfo +
2408
self->CurrentInfo->NextEntryDelta));
2411
self->CurrentInfo = 0;
2416
/*--------------------------------------------------------------------------*/
2417
static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self)
2419
return self->CurrentInfo? self->CurrentInfo->ProcessId : -1;
2422
/*--------------------------------------------------------------------------*/
2423
static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self)
2425
return self->CurrentInfo? self->CurrentInfo->InheritedFromProcessId : -1;
2428
/*--------------------------------------------------------------------------*/
2429
static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self)
2431
HANDLE hKernel = GetModuleHandle("kernel32.dll");
2434
self->P_CreateToolhelp32Snapshot =
2435
((CreateToolhelp32SnapshotType)
2436
GetProcAddress(hKernel, "CreateToolhelp32Snapshot"));
2437
self->P_Process32First =
2438
((Process32FirstType)
2439
GetProcAddress(hKernel, "Process32First"));
2440
self->P_Process32Next =
2441
((Process32NextType)
2442
GetProcAddress(hKernel, "Process32Next"));
2443
CloseHandle(hKernel);
2445
return (self->P_CreateToolhelp32Snapshot &&
2446
self->P_Process32First &&
2447
self->P_Process32Next)? 1:0;
2450
/*--------------------------------------------------------------------------*/
2451
static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self)
2455
CloseHandle(self->Snapshot);
2459
/*--------------------------------------------------------------------------*/
2460
static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self)
2464
CloseHandle(self->Snapshot);
2466
if(!(self->Snapshot =
2467
self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)))
2471
ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry));
2472
self->CurrentEntry.dwSize = sizeof(self->CurrentEntry);
2473
if(!self->P_Process32First(self->Snapshot, &self->CurrentEntry))
2475
CloseHandle(self->Snapshot);
2482
/*--------------------------------------------------------------------------*/
2483
static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self)
2487
if(self->P_Process32Next(self->Snapshot, &self->CurrentEntry))
2491
CloseHandle(self->Snapshot);
2497
/*--------------------------------------------------------------------------*/
2498
static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self)
2500
return self->Snapshot? self->CurrentEntry.th32ProcessID : -1;
2503
/*--------------------------------------------------------------------------*/
2504
static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self)
2506
return self->Snapshot? self->CurrentEntry.th32ParentProcessID : -1;
2509
/*--------------------------------------------------------------------------*/
2510
static void kwsysProcessKill(DWORD pid)
2512
HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
2515
TerminateProcess(h, 255);
2516
WaitForSingleObject(h, INFINITE);
2520
/*--------------------------------------------------------------------------*/
2521
static void kwsysProcessKillTree(int pid)
2523
kwsysProcess_List* plist = kwsysProcess_List_New();
2524
kwsysProcessKill(pid);
2529
if(kwsysProcess_List_GetCurrentParentId(plist) == pid)
2531
int ppid = kwsysProcess_List_GetCurrentProcessId(plist);
2532
kwsysProcessKillTree(ppid);
2534
} while(kwsysProcess_List_NextProcess(plist));
2535
kwsysProcess_List_Delete(plist);