~ubuntu-branches/ubuntu/jaunty/cmake/jaunty-security

« back to all changes in this revision

Viewing changes to Source/kwsys/ProcessWin32.c

  • Committer: Bazaar Package Importer
  • Author(s): A. Maitland Bottoms
  • Date: 2005-03-02 09:22:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050302092244-y6o9j8wr27vqcqvx
Tags: 2.0.5-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*=========================================================================
 
2
 
 
3
  Program:   KWSys - Kitware System Library
 
4
  Module:    $RCSfile: ProcessWin32.c,v $
 
5
 
 
6
  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
 
7
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
 
8
 
 
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.
 
12
 
 
13
=========================================================================*/
 
14
#define KWSYS_IN_PROCESS_C
 
15
#include "kwsysPrivate.h"
 
16
#include KWSYS_HEADER(Process.h)
 
17
 
 
18
/*
 
19
 
 
20
Implementation for Windows
 
21
 
 
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.
 
25
 
 
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.
 
30
 
 
31
For more information, please check Microsoft Knowledge Base Articles
 
32
Q190351 and Q150956.
 
33
 
 
34
*/
 
35
 
 
36
#ifdef _MSC_VER
 
37
#pragma warning (push, 1)
 
38
#endif
 
39
#include <windows.h> /* Windows API */
 
40
#include <string.h>  /* strlen, strdup */
 
41
#include <stdio.h>   /* sprintf */
 
42
#include <io.h>      /* _unlink */
 
43
 
 
44
#ifndef _MAX_FNAME
 
45
#define _MAX_FNAME 4096
 
46
#endif
 
47
#ifndef _MAX_PATH
 
48
#define _MAX_PATH 4096
 
49
#endif
 
50
 
 
51
#ifdef _MSC_VER
 
52
#pragma warning (pop)
 
53
#pragma warning (disable: 4514)
 
54
#pragma warning (disable: 4706)
 
55
#endif
 
56
 
 
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
 
61
 
 
62
/* The maximum amount to read from a pipe at a time.  */
 
63
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
 
64
 
 
65
#define kwsysEncodedWriteArrayProcessFwd9x kwsys_ns(EncodedWriteArrayProcessFwd9x)
 
66
 
 
67
typedef LARGE_INTEGER kwsysProcessTime;
 
68
 
 
69
typedef struct kwsysProcessCreateInformation_s
 
70
{
 
71
  /* Windows child startup control data.  */
 
72
  STARTUPINFO StartupInfo;
 
73
 
 
74
  /* Special error reporting pipe for Win9x forwarding executable.  */
 
75
  HANDLE ErrorPipeRead;
 
76
  HANDLE ErrorPipeWrite;
 
77
} kwsysProcessCreateInformation;
 
78
 
 
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,
 
86
                              PHANDLE readEnd);
 
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);
 
106
 
 
107
/*--------------------------------------------------------------------------*/
 
108
/* A structure containing data for each pipe's thread.  */
 
109
struct kwsysProcessPipeData_s
 
110
{
 
111
  /* ------------- Data managed per instance of kwsysProcess ------------- */
 
112
 
 
113
  /* Handle for the thread for this pipe.  */
 
114
  HANDLE Thread;
 
115
 
 
116
  /* Semaphore indicating a process and pipe are available.  */
 
117
  HANDLE Ready;
 
118
 
 
119
  /* Semaphore indicating when this thread's buffer is empty.  */
 
120
  HANDLE Empty;
 
121
 
 
122
  /* Semaphore indicating a pipe thread has reset for another process.  */
 
123
  HANDLE Reset;
 
124
 
 
125
  /* Index of this pipe.  */
 
126
  int Index;
 
127
 
 
128
  /* The kwsysProcess instance owning this pipe.  */
 
129
  kwsysProcess* Process;
 
130
 
 
131
  /* ------------- Data managed per call to Execute ------------- */
 
132
 
 
133
  /* Buffer for data read in this pipe's thread.  */
 
134
  char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
 
135
 
 
136
  /* The length of the data stored in the buffer.  */
 
137
  DWORD DataLength;
 
138
 
 
139
  /* Whether the pipe has been closed.  */
 
140
  int Closed;
 
141
 
 
142
  /* Handle for the read end of this pipe. */
 
143
  HANDLE Read;
 
144
 
 
145
  /* Handle for the write end of this pipe. */
 
146
  HANDLE Write;
 
147
};
 
148
 
 
149
/*--------------------------------------------------------------------------*/
 
150
/* Structure containing data used to implement the child's execution.  */
 
151
struct kwsysProcess_s
 
152
{
 
153
  /* ------------- Data managed per instance of kwsysProcess ------------- */
 
154
 
 
155
  /* The status of the process structure.  */
 
156
  int State;
 
157
 
 
158
  /* The command lines to execute.  */
 
159
  char** Commands;
 
160
  int NumberOfCommands;
 
161
 
 
162
  /* The exit code of each command.  */
 
163
  DWORD* CommandExitCodes;
 
164
 
 
165
  /* The working directory for the child process.  */
 
166
  char* WorkingDirectory;
 
167
 
 
168
  /* Whether to hide the child process's window.  */
 
169
  int HideWindow;
 
170
 
 
171
  /* On Win9x platforms, the path to the forwarding executable.  */
 
172
  char* Win9x;
 
173
 
 
174
  /* On Win9x platforms, the resume event for the forwarding executable.  */
 
175
  HANDLE Win9xResumeEvent;
 
176
 
 
177
  /* On Win9x platforms, the kill event for the forwarding executable.  */
 
178
  HANDLE Win9xKillEvent;
 
179
 
 
180
  /* Mutex to protect the shared index used by threads to report data.  */
 
181
  HANDLE SharedIndexMutex;
 
182
 
 
183
  /* Semaphore used by threads to signal data ready.  */
 
184
  HANDLE Full;
 
185
 
 
186
  /* Whether we are currently deleting this kwsysProcess instance.  */
 
187
  int Deleting;
 
188
 
 
189
  /* Data specific to each pipe and its thread.  */
 
190
  kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
 
191
 
 
192
  /* Name of files to which stdin and stdout pipes are attached.  */
 
193
  char* PipeFileSTDIN;
 
194
  char* PipeFileSTDOUT;
 
195
  char* PipeFileSTDERR;
 
196
 
 
197
  /* Whether each pipe is shared with the parent process.  */
 
198
  int PipeSharedSTDIN;
 
199
  int PipeSharedSTDOUT;
 
200
  int PipeSharedSTDERR;
 
201
 
 
202
  /* Handle to automatically delete the Win9x forwarding executable.  */
 
203
  HANDLE Win9xHandle;
 
204
 
 
205
  /* ------------- Data managed per call to Execute ------------- */
 
206
 
 
207
  /* The exceptional behavior that terminated the process, if any.  */
 
208
  int ExitException;
 
209
 
 
210
  /* The process exit code.  */
 
211
  DWORD ExitCode;
 
212
 
 
213
  /* The process return code, if any.  */
 
214
  int ExitValue;
 
215
 
 
216
  /* Index of last pipe to report data, if any.  */
 
217
  int CurrentIndex;
 
218
 
 
219
  /* Index shared by threads to report data.  */
 
220
  int SharedIndex;
 
221
 
 
222
  /* The timeout length.  */
 
223
  double Timeout;
 
224
 
 
225
  /* Time at which the child started.  */
 
226
  kwsysProcessTime StartTime;
 
227
 
 
228
  /* Time at which the child will timeout.  Negative for no timeout.  */
 
229
  kwsysProcessTime TimeoutTime;
 
230
 
 
231
  /* Flag for whether the process was killed.  */
 
232
  int Killed;
 
233
 
 
234
  /* Flag for whether the timeout expired.  */
 
235
  int TimeoutExpired;
 
236
 
 
237
  /* Flag for whether the process has terminated.  */
 
238
  int Terminated;
 
239
 
 
240
  /* The number of pipes still open during execution and while waiting
 
241
     for pipes to close after process termination.  */
 
242
  int PipesLeft;
 
243
 
 
244
  /* Buffer for error messages (possibly from Win9x child).  */
 
245
  char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
 
246
 
 
247
  /* Description for the ExitException.  */
 
248
  char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1];
 
249
 
 
250
  /* Windows process information data.  */
 
251
  PROCESS_INFORMATION* ProcessInformation;
 
252
 
 
253
  /* Data and process termination events for which to wait.  */
 
254
  PHANDLE ProcessEvents;
 
255
  int ProcessEventsLength;
 
256
 
 
257
  /* Real working directory of our own process.  */
 
258
  DWORD RealWorkingDirectoryLength;
 
259
  char* RealWorkingDirectory;
 
260
};
 
261
 
 
262
/*--------------------------------------------------------------------------*/
 
263
kwsysProcess* kwsysProcess_New()
 
264
{
 
265
  int i;
 
266
 
 
267
  /* Process control structure.  */
 
268
  kwsysProcess* cp;
 
269
 
 
270
  /* Path to Win9x forwarding executable.  */
 
271
  char* win9x = 0;
 
272
 
 
273
  /* Windows version number data.  */
 
274
  OSVERSIONINFO osv;
 
275
 
 
276
  /* Allocate a process control structure.  */
 
277
  cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
 
278
  if(!cp)
 
279
    {
 
280
    /* Could not allocate memory for the control structure.  */
 
281
    return 0;
 
282
    }
 
283
  ZeroMemory(cp, sizeof(*cp));
 
284
 
 
285
  /* Share stdin with the parent process by default.  */
 
286
  cp->PipeSharedSTDIN = 1;
 
287
 
 
288
  /* Set initial status.  */
 
289
  cp->State = kwsysProcess_State_Starting;
 
290
 
 
291
  /* Choose a method of running the child based on version of
 
292
     windows.  */
 
293
  ZeroMemory(&osv, sizeof(osv));
 
294
  osv.dwOSVersionInfoSize = sizeof(osv);
 
295
  GetVersionEx(&osv);
 
296
  if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
 
297
    {
 
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] = "";
 
302
 
 
303
    /* We will try putting the executable in the system temp
 
304
       directory.  Note that the returned path already has a trailing
 
305
       slash.  */
 
306
    DWORD length = GetTempPath(_MAX_PATH+1, tempDir);
 
307
 
 
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);
 
312
 
 
313
    /* If we have a temp directory, use it.  */
 
314
    if(length > 0 && length <= _MAX_PATH)
 
315
      {
 
316
      /* Allocate a buffer to hold the forwarding executable path.  */
 
317
      size_t tdlen = strlen(tempDir);
 
318
      win9x = (char*)malloc(tdlen + strlen(fwdName) + 2);
 
319
      if(!win9x)
 
320
        {
 
321
        kwsysProcess_Delete(cp);
 
322
        return 0;
 
323
        }
 
324
 
 
325
      /* Construct the full path to the forwarding executable.  */
 
326
      sprintf(win9x, "%s%s", tempDir, fwdName);
 
327
      }
 
328
 
 
329
    /* If we found a place to put the forwarding executable, try to
 
330
       write it. */
 
331
    if(win9x)
 
332
      {
 
333
      if(!kwsysEncodedWriteArrayProcessFwd9x(win9x))
 
334
        {
 
335
        /* Failed to create forwarding executable.  Give up.  */
 
336
        free(win9x);
 
337
        kwsysProcess_Delete(cp);
 
338
        return 0;
 
339
        }
 
340
 
 
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)
 
345
        {
 
346
        /* We were not able to get a read handle for the forwarding
 
347
           executable.  It will not be deleted properly.  Give up.  */
 
348
        _unlink(win9x);
 
349
        free(win9x);
 
350
        kwsysProcess_Delete(cp);
 
351
        return 0;
 
352
        }
 
353
      }
 
354
    else
 
355
      {
 
356
      /* Failed to find a place to put forwarding executable.  */
 
357
      kwsysProcess_Delete(cp);
 
358
      return 0;
 
359
      }
 
360
    }
 
361
 
 
362
  /* Save the path to the forwarding executable.  */
 
363
  cp->Win9x = win9x;
 
364
 
 
365
  /* Initially no thread owns the mutex.  Initialize semaphore to 1.  */
 
366
  if(!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0)))
 
367
    {
 
368
    kwsysProcess_Delete(cp);
 
369
    return 0;
 
370
    }
 
371
 
 
372
  /* Initially no data are available.  Initialize semaphore to 0.  */
 
373
  if(!(cp->Full = CreateSemaphore(0, 0, 1, 0)))
 
374
    {
 
375
    kwsysProcess_Delete(cp);
 
376
    return 0;
 
377
    }
 
378
 
 
379
  if(cp->Win9x)
 
380
    {
 
381
    SECURITY_ATTRIBUTES sa;
 
382
    ZeroMemory(&sa, sizeof(sa));
 
383
    sa.nLength = sizeof(sa);
 
384
    sa.bInheritHandle = TRUE;
 
385
 
 
386
    /* Create an event to tell the forwarding executable to resume the
 
387
       child.  */
 
388
    if(!(cp->Win9xResumeEvent = CreateEvent(&sa, TRUE, 0, 0)))
 
389
      {
 
390
      kwsysProcess_Delete(cp);
 
391
      return 0;
 
392
      }
 
393
 
 
394
    /* Create an event to tell the forwarding executable to kill the
 
395
       child.  */
 
396
    if(!(cp->Win9xKillEvent = CreateEvent(&sa, TRUE, 0, 0)))
 
397
      {
 
398
      kwsysProcess_Delete(cp);
 
399
      return 0;
 
400
      }
 
401
    }
 
402
 
 
403
  /* Create the thread to read each pipe.  */
 
404
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
 
405
    {
 
406
    DWORD dummy=0;
 
407
 
 
408
    /* Assign the thread its index.  */
 
409
    cp->Pipe[i].Index = i;
 
410
 
 
411
    /* Give the thread a pointer back to the kwsysProcess instance.  */
 
412
    cp->Pipe[i].Process = cp;
 
413
 
 
414
    /* The pipe is not yet ready to read.  Initialize semaphore to 0.  */
 
415
    if(!(cp->Pipe[i].Ready = CreateSemaphore(0, 0, 1, 0)))
 
416
      {
 
417
      kwsysProcess_Delete(cp);
 
418
      return 0;
 
419
      }
 
420
 
 
421
    /* The pipe is not yet reset.  Initialize semaphore to 0.  */
 
422
    if(!(cp->Pipe[i].Reset = CreateSemaphore(0, 0, 1, 0)))
 
423
      {
 
424
      kwsysProcess_Delete(cp);
 
425
      return 0;
 
426
      }
 
427
 
 
428
    /* The thread's buffer is initially empty.  Initialize semaphore to 1.  */
 
429
    if(!(cp->Pipe[i].Empty = CreateSemaphore(0, 1, 1, 0)))
 
430
      {
 
431
      kwsysProcess_Delete(cp);
 
432
      return 0;
 
433
      }
 
434
 
 
435
    /* Create the thread.  It will block immediately.  The thread will
 
436
       not make deeply nested calls, so we need only a small
 
437
       stack.  */
 
438
    if(!(cp->Pipe[i].Thread = CreateThread(0, 1024, kwsysProcessPipeThread,
 
439
                                           &cp->Pipe[i], 0, &dummy)))
 
440
      {
 
441
      kwsysProcess_Delete(cp);
 
442
      return 0;
 
443
      }
 
444
    }
 
445
 
 
446
  return cp;
 
447
}
 
448
 
 
449
/*--------------------------------------------------------------------------*/
 
450
void kwsysProcess_Delete(kwsysProcess* cp)
 
451
{
 
452
  int i;
 
453
 
 
454
  /* Make sure we have an instance.  */
 
455
  if(!cp)
 
456
    {
 
457
    return;
 
458
    }
 
459
 
 
460
  /* If the process is executing, wait for it to finish.  */
 
461
  if(cp->State == kwsysProcess_State_Executing)
 
462
    {
 
463
    kwsysProcess_WaitForExit(cp, 0);
 
464
    }
 
465
 
 
466
  /* We are deleting the kwsysProcess instance.  */
 
467
  cp->Deleting = 1;
 
468
 
 
469
  /* Terminate each of the threads.  */
 
470
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
 
471
    {
 
472
    if(cp->Pipe[i].Thread)
 
473
      {
 
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);
 
477
 
 
478
      /* Wait for the thread to exit.  */
 
479
      WaitForSingleObject(cp->Pipe[i].Thread, INFINITE);
 
480
 
 
481
      /* Close the handle to the thread. */
 
482
      kwsysProcessCleanupHandle(&cp->Pipe[i].Thread);
 
483
      }
 
484
 
 
485
    /* Cleanup the pipe's semaphores.  */
 
486
    kwsysProcessCleanupHandle(&cp->Pipe[i].Ready);
 
487
    kwsysProcessCleanupHandle(&cp->Pipe[i].Empty);
 
488
    }
 
489
 
 
490
  /* Close the shared semaphores.  */
 
491
  kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
 
492
  kwsysProcessCleanupHandle(&cp->Full);
 
493
 
 
494
  /* Close the Win9x resume and kill event handles.  */
 
495
  if(cp->Win9x)
 
496
    {
 
497
    kwsysProcessCleanupHandle(&cp->Win9xResumeEvent);
 
498
    kwsysProcessCleanupHandle(&cp->Win9xKillEvent);
 
499
    }
 
500
 
 
501
  /* Free memory.  */
 
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)
 
508
    {
 
509
    free(cp->CommandExitCodes);
 
510
    }
 
511
  if(cp->Win9x)
 
512
    {
 
513
    /* Close our handle to the forwarding executable file.  This will
 
514
       cause it to be deleted.  */
 
515
    kwsysProcessCleanupHandle(&cp->Win9xHandle);
 
516
    }
 
517
  free(cp);
 
518
}
 
519
 
 
520
/*--------------------------------------------------------------------------*/
 
521
int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
 
522
{
 
523
  int i;
 
524
  if(!cp)
 
525
    {
 
526
    return 0;
 
527
    }
 
528
  for(i=0; i < cp->NumberOfCommands; ++i)
 
529
    {
 
530
    free(cp->Commands[i]);
 
531
    }
 
532
  cp->NumberOfCommands = 0;
 
533
  if(cp->Commands)
 
534
    {
 
535
    free(cp->Commands);
 
536
    cp->Commands = 0;
 
537
    }
 
538
  if(command)
 
539
    {
 
540
    return kwsysProcess_AddCommand(cp, command);
 
541
    }
 
542
  return 1;
 
543
}
 
544
 
 
545
/*--------------------------------------------------------------------------*/
 
546
int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
 
547
{
 
548
  int newNumberOfCommands;
 
549
  char** newCommands;
 
550
 
 
551
  /* Make sure we have a command to add.  */
 
552
  if(!cp || !command)
 
553
    {
 
554
    return 0;
 
555
    }
 
556
 
 
557
  /* Allocate a new array for command pointers.  */
 
558
  newNumberOfCommands = cp->NumberOfCommands + 1;
 
559
  if(!(newCommands = (char**)malloc(sizeof(char*) * newNumberOfCommands)))
 
560
    {
 
561
    /* Out of memory.  */
 
562
    return 0;
 
563
    }
 
564
 
 
565
  /* Copy any existing commands into the new array.  */
 
566
  {
 
567
  int i;
 
568
  for(i=0; i < cp->NumberOfCommands; ++i)
 
569
    {
 
570
    newCommands[i] = cp->Commands[i];
 
571
    }
 
572
  }
 
573
 
 
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
 
580
       argument.  */
 
581
  {
 
582
  char* cmd;
 
583
  char const* const* arg;
 
584
  int length = 0;
 
585
  /* First determine the length of the final string.  */
 
586
  for(arg = command; *arg; ++arg)
 
587
    {
 
588
    /* Keep track of how many backslashes have been encountered in a
 
589
       row in this argument.  */
 
590
    int backslashes = 0;
 
591
    int spaces = 0;
 
592
    const char* c;
 
593
 
 
594
    /* Scan the string for spaces.  If there are no spaces, we can
 
595
         pass the argument verbatim.  */
 
596
    for(c=*arg; *c; ++c)
 
597
      {
 
598
      if(*c == ' ' || *c == '\t')
 
599
        {
 
600
        spaces = 1;
 
601
        break;
 
602
        }
 
603
      }
 
604
 
 
605
    /* Add the length of the argument, plus 1 for the space
 
606
         separating the arguments.  */
 
607
    length += (int)strlen(*arg) + 1;
 
608
 
 
609
    if(spaces)
 
610
      {
 
611
      /* Add 2 for double quotes since spaces are present.  */
 
612
      length += 2;
 
613
 
 
614
        /* Scan the string to find characters that need escaping.  */
 
615
      for(c=*arg; *c; ++c)
 
616
        {
 
617
        if(*c == '\\')
 
618
          {
 
619
          /* Found a backslash.  It may need to be escaped later.  */
 
620
          ++backslashes;
 
621
          }
 
622
        else if(*c == '"')
 
623
          {
 
624
          /* Found a double-quote.  We need to escape it and all
 
625
             immediately preceding backslashes.  */
 
626
          length += backslashes + 1;
 
627
          backslashes = 0;
 
628
          }
 
629
        else
 
630
          {
 
631
          /* Found another character.  This eliminates the possibility
 
632
             that any immediately preceding backslashes will be
 
633
             escaped.  */
 
634
          backslashes = 0;
 
635
          }
 
636
        }
 
637
 
 
638
      /* We need to escape all ending backslashes. */
 
639
      length += backslashes;
 
640
      }
 
641
    }
 
642
 
 
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])
 
648
    {
 
649
    /* Out of memory.  */
 
650
    free(newCommands);
 
651
    return 0;
 
652
    }
 
653
 
 
654
  /* Construct the command line in the allocated buffer.  */
 
655
  cmd = newCommands[cp->NumberOfCommands];
 
656
  for(arg = command; *arg; ++arg)
 
657
    {
 
658
    /* Keep track of how many backslashes have been encountered in a
 
659
       row in an argument.  */
 
660
    int backslashes = 0;
 
661
    int spaces = 0;
 
662
    const char* c;
 
663
 
 
664
    /* Scan the string for spaces.  If there are no spaces, we can
 
665
         pass the argument verbatim.  */
 
666
    for(c=*arg; *c; ++c)
 
667
      {
 
668
      if(*c == ' ' || *c == '\t')
 
669
        {
 
670
        spaces = 1;
 
671
        break;
 
672
        }
 
673
      }
 
674
 
 
675
    /* Add the separating space if this is not the first argument.  */
 
676
    if(arg != command)
 
677
      {
 
678
      *cmd++ = ' ';
 
679
      }
 
680
 
 
681
    if(spaces)
 
682
      {
 
683
      /* Add the opening double-quote for this argument.  */
 
684
      *cmd++ = '"';
 
685
 
 
686
        /* Add the characters of the argument, possibly escaping them.  */
 
687
      for(c=*arg; *c; ++c)
 
688
        {
 
689
        if(*c == '\\')
 
690
          {
 
691
          /* Found a backslash.  It may need to be escaped later.  */
 
692
          ++backslashes;
 
693
          *cmd++ = '\\';
 
694
          }
 
695
        else if(*c == '"')
 
696
          {
 
697
          /* Add enough backslashes to escape any that preceded the
 
698
             double-quote.  */
 
699
          while(backslashes > 0)
 
700
            {
 
701
            --backslashes;
 
702
            *cmd++ = '\\';
 
703
            }
 
704
 
 
705
          /* Add the backslash to escape the double-quote.  */
 
706
          *cmd++ = '\\';
 
707
 
 
708
          /* Add the double-quote itself.  */
 
709
          *cmd++ = '"';
 
710
          }
 
711
        else
 
712
          {
 
713
          /* We encountered a normal character.  This eliminates any
 
714
             escaping needed for preceding backslashes.  Add the
 
715
             character.  */
 
716
          backslashes = 0;
 
717
          *cmd++ = *c;
 
718
          }
 
719
        }
 
720
 
 
721
      /* Add enough backslashes to escape any trailing ones.  */
 
722
      while(backslashes > 0)
 
723
        {
 
724
        --backslashes;
 
725
        *cmd++ = '\\';
 
726
        }
 
727
 
 
728
      /* Add the closing double-quote for this argument.  */
 
729
      *cmd++ = '"';
 
730
      }
 
731
    else
 
732
      {
 
733
      /* No spaces.  Add the argument verbatim.  */
 
734
      for(c=*arg; *c; ++c)
 
735
        {
 
736
        *cmd++ = *c;
 
737
        }
 
738
      }
 
739
    }
 
740
 
 
741
  /* Add the terminating null character to the command line.  */
 
742
  *cmd = 0;
 
743
  }
 
744
 
 
745
  /* Save the new array of commands.  */
 
746
  free(cp->Commands);
 
747
  cp->Commands = newCommands;
 
748
  cp->NumberOfCommands = newNumberOfCommands;
 
749
  return 1;
 
750
}
 
751
 
 
752
/*--------------------------------------------------------------------------*/
 
753
void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
 
754
{
 
755
  if(!cp)
 
756
    {
 
757
    return;
 
758
    }
 
759
  cp->Timeout = timeout;
 
760
  if(cp->Timeout < 0)
 
761
    {
 
762
    cp->Timeout = 0;
 
763
    }
 
764
}
 
765
 
 
766
/*--------------------------------------------------------------------------*/
 
767
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
 
768
{
 
769
  if(!cp)
 
770
    {
 
771
    return 0;
 
772
    }
 
773
  if(cp->WorkingDirectory)
 
774
    {
 
775
    free(cp->WorkingDirectory);
 
776
    cp->WorkingDirectory = 0;
 
777
    }
 
778
  if(dir && dir[0])
 
779
    {
 
780
    /* We must convert the working directory to a full path.  */
 
781
    DWORD length = GetFullPathName(dir, 0, 0, 0);
 
782
    if(length > 0)
 
783
      {
 
784
      cp->WorkingDirectory = (char*)malloc(length);
 
785
      if(!cp->WorkingDirectory)
 
786
        {
 
787
        return 0;
 
788
        }
 
789
      if(!GetFullPathName(dir, length, cp->WorkingDirectory, 0))
 
790
        {
 
791
        free(cp->WorkingDirectory);
 
792
        cp->WorkingDirectory = 0;
 
793
        return 0;
 
794
        }
 
795
      }
 
796
    }
 
797
  return 1;
 
798
}
 
799
 
 
800
/*--------------------------------------------------------------------------*/
 
801
int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
 
802
{
 
803
  char** pfile;
 
804
  if(!cp)
 
805
    {
 
806
    return 0;
 
807
    }
 
808
  switch(pipe)
 
809
    {
 
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;
 
813
    default: return 0;
 
814
    }
 
815
  if(*pfile)
 
816
    {
 
817
    free(*pfile);
 
818
    *pfile = 0;
 
819
    }
 
820
  if(file)
 
821
    {
 
822
    *pfile = malloc(strlen(file)+1);
 
823
    if(!*pfile)
 
824
      {
 
825
      return 0;
 
826
      }
 
827
    strcpy(*pfile, file);
 
828
    }
 
829
 
 
830
  /* If we are redirecting the pipe, do not share it.  */
 
831
  if(*pfile)
 
832
    {
 
833
    kwsysProcess_SetPipeShared(cp, pipe, 0);
 
834
    }
 
835
 
 
836
  return 1;
 
837
}
 
838
 
 
839
/*--------------------------------------------------------------------------*/
 
840
void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared)
 
841
{
 
842
  if(!cp)
 
843
    {
 
844
    return;
 
845
    }
 
846
 
 
847
  switch(pipe)
 
848
    {
 
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;
 
852
    default: return;
 
853
    }
 
854
 
 
855
  /* If we are sharing the pipe, do not redirect it to a file.  */
 
856
  if(shared)
 
857
    {
 
858
    kwsysProcess_SetPipeFile(cp, pipe, 0);
 
859
    }
 
860
}
 
861
 
 
862
/*--------------------------------------------------------------------------*/
 
863
int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
 
864
{
 
865
  if(!cp)
 
866
    {
 
867
    return 0;
 
868
    }
 
869
 
 
870
  switch(optionId)
 
871
    {
 
872
    case kwsysProcess_Option_HideWindow: return cp->HideWindow;
 
873
    default: return 0;
 
874
    }
 
875
}
 
876
 
 
877
/*--------------------------------------------------------------------------*/
 
878
void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
 
879
{
 
880
  if(!cp)
 
881
    {
 
882
    return;
 
883
    }
 
884
 
 
885
  switch(optionId)
 
886
    {
 
887
    case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
 
888
    default: break;
 
889
    }
 
890
}
 
891
 
 
892
/*--------------------------------------------------------------------------*/
 
893
int kwsysProcess_GetState(kwsysProcess* cp)
 
894
{
 
895
  return cp? cp->State : kwsysProcess_State_Error;
 
896
}
 
897
 
 
898
/*--------------------------------------------------------------------------*/
 
899
int kwsysProcess_GetExitException(kwsysProcess* cp)
 
900
{
 
901
  return cp? cp->ExitException : kwsysProcess_Exception_Other;
 
902
}
 
903
 
 
904
/*--------------------------------------------------------------------------*/
 
905
int kwsysProcess_GetExitValue(kwsysProcess* cp)
 
906
{
 
907
  return cp? cp->ExitValue : -1;
 
908
}
 
909
 
 
910
/*--------------------------------------------------------------------------*/
 
911
int kwsysProcess_GetExitCode(kwsysProcess* cp)
 
912
{
 
913
  return cp? cp->ExitCode : 0;
 
914
}
 
915
 
 
916
/*--------------------------------------------------------------------------*/
 
917
const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
 
918
{
 
919
  if(!cp)
 
920
    {
 
921
    return "Process management structure could not be allocated";
 
922
    }
 
923
  else if(cp->State == kwsysProcess_State_Error)
 
924
    {
 
925
    return cp->ErrorMessage;
 
926
    }
 
927
  return "Success";
 
928
}
 
929
 
 
930
/*--------------------------------------------------------------------------*/
 
931
const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
 
932
{
 
933
  if(!cp)
 
934
    {
 
935
    return "GetExceptionString called with NULL process management structure";
 
936
    }
 
937
  else if(cp->State == kwsysProcess_State_Exception)
 
938
    {
 
939
    return cp->ExitExceptionString;
 
940
    }
 
941
  return "No exception";
 
942
}
 
943
 
 
944
/*--------------------------------------------------------------------------*/
 
945
void kwsysProcess_Execute(kwsysProcess* cp)
 
946
{
 
947
  int i;
 
948
 
 
949
  /* Child startup control data.  */
 
950
  kwsysProcessCreateInformation si;
 
951
 
 
952
  /* Do not execute a second time.  */
 
953
  if(!cp || cp->State == kwsysProcess_State_Executing)
 
954
    {
 
955
    return;
 
956
    }
 
957
 
 
958
  /* Initialize the control structure for a new process.  */
 
959
  if(!kwsysProcessInitialize(cp))
 
960
    {
 
961
    strcpy(cp->ErrorMessage, "Out of memory");
 
962
    cp->State = kwsysProcess_State_Error;
 
963
    return;
 
964
    }
 
965
 
 
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)
 
970
    {
 
971
    if(!GetCurrentDirectory(cp->RealWorkingDirectoryLength,
 
972
                            cp->RealWorkingDirectory))
 
973
      {
 
974
      kwsysProcessCleanup(cp, 1);
 
975
      return;
 
976
      }
 
977
    SetCurrentDirectory(cp->WorkingDirectory);
 
978
    }
 
979
 
 
980
  /* Reset the Win9x resume and kill events.  */
 
981
  if(cp->Win9x)
 
982
    {
 
983
    if(!ResetEvent(cp->Win9xResumeEvent))
 
984
      {
 
985
      kwsysProcessCleanup(cp, 1);
 
986
      return;
 
987
      }
 
988
    if(!ResetEvent(cp->Win9xKillEvent))
 
989
      {
 
990
      kwsysProcessCleanup(cp, 1);
 
991
      return;
 
992
      }
 
993
    }
 
994
 
 
995
  /* Initialize startup info data.  */
 
996
  ZeroMemory(&si, sizeof(si));
 
997
  si.StartupInfo.cb = sizeof(si.StartupInfo);
 
998
 
 
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);
 
1003
 
 
1004
  /* Connect the child's output pipes to the threads.  */
 
1005
  si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
 
1006
 
 
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))
 
1011
    {
 
1012
    kwsysProcessCleanup(cp, 1);
 
1013
    return;
 
1014
    }
 
1015
 
 
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))
 
1022
    {
 
1023
    kwsysProcessCleanup(cp, 1);
 
1024
    kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
 
1025
    return;
 
1026
    }
 
1027
 
 
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)
 
1031
    {
 
1032
    if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError,
 
1033
                                        cp->PipeFileSTDERR))
 
1034
      {
 
1035
      kwsysProcessCleanup(cp, 1);
 
1036
      kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
 
1037
      return;
 
1038
      }
 
1039
    }
 
1040
 
 
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
 
1043
     data.  */
 
1044
  if(cp->PipeSharedSTDERR)
 
1045
    {
 
1046
    kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
 
1047
    si.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 
1048
    }
 
1049
 
 
1050
  /* Create the pipeline of processes.  */
 
1051
  {
 
1052
  HANDLE readEnd = 0;
 
1053
  for(i=0; i < cp->NumberOfCommands; ++i)
 
1054
    {
 
1055
    if(kwsysProcessCreate(cp, i, &si, &readEnd))
 
1056
      {
 
1057
      cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess;
 
1058
      }
 
1059
    else
 
1060
      {
 
1061
      kwsysProcessCleanup(cp, 1);
 
1062
 
 
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))
 
1067
        {
 
1068
        kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput);
 
1069
        }
 
1070
      if(si.StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
 
1071
        {
 
1072
        kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
 
1073
        }
 
1074
      if(si.StartupInfo.hStdOutput != GetStdHandle(STD_ERROR_HANDLE))
 
1075
        {
 
1076
        kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
 
1077
        }
 
1078
      kwsysProcessCleanupHandle(&si.ErrorPipeRead);
 
1079
      kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
 
1080
      return;
 
1081
      }
 
1082
    }
 
1083
 
 
1084
  /* Save a handle to the output pipe for the last process.  */
 
1085
  cp->Pipe[KWSYSPE_PIPE_STDOUT].Read = readEnd;
 
1086
  }
 
1087
 
 
1088
  /* Close the inherited handles to the stderr pipe shared by all
 
1089
     processes in the pipeline.  */
 
1090
  kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
 
1091
 
 
1092
  /* Restore the working directory.  */
 
1093
  if(cp->RealWorkingDirectory)
 
1094
    {
 
1095
    SetCurrentDirectory(cp->RealWorkingDirectory);
 
1096
    free(cp->RealWorkingDirectory);
 
1097
    cp->RealWorkingDirectory = 0;
 
1098
    }
 
1099
 
 
1100
  /* The timeout period starts now.  */
 
1101
  cp->StartTime = kwsysProcessTimeGetCurrent();
 
1102
  cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
 
1103
 
 
1104
  /* All processes in the pipeline have been started in suspended
 
1105
     mode.  Resume them all now.  */
 
1106
  if(cp->Win9x)
 
1107
    {
 
1108
    SetEvent(cp->Win9xResumeEvent);
 
1109
    }
 
1110
  else
 
1111
    {
 
1112
    for(i=0; i < cp->NumberOfCommands; ++i)
 
1113
      {
 
1114
      ResumeThread(cp->ProcessInformation[i].hThread);
 
1115
      }
 
1116
    }
 
1117
 
 
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)
 
1121
    {
 
1122
    ReleaseSemaphore(cp->Pipe[i].Ready, 1, 0);
 
1123
    }
 
1124
 
 
1125
  /* We don't care about the children's main threads.  */
 
1126
  for(i=0; i < cp->NumberOfCommands; ++i)
 
1127
    {
 
1128
    kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
 
1129
    }
 
1130
 
 
1131
  /* No pipe has reported data.  */
 
1132
  cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
 
1133
  cp->PipesLeft = KWSYSPE_PIPE_COUNT;
 
1134
 
 
1135
  /* The process has now started.  */
 
1136
  cp->State = kwsysProcess_State_Executing;
 
1137
}
 
1138
 
 
1139
/*--------------------------------------------------------------------------*/
 
1140
 
 
1141
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
 
1142
                             double* userTimeout)
 
1143
{
 
1144
  kwsysProcessTime userStartTime;
 
1145
  kwsysProcessTime timeoutLength;
 
1146
  kwsysProcessTime timeoutTime;
 
1147
  DWORD timeout;
 
1148
  int user;
 
1149
  int done = 0;
 
1150
  int expired = 0;
 
1151
  int pipeId = kwsysProcess_Pipe_None;
 
1152
  DWORD w;
 
1153
 
 
1154
  /* Make sure we are executing a process.  */
 
1155
  if(!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
 
1156
     cp->TimeoutExpired)
 
1157
    {
 
1158
    return kwsysProcess_Pipe_None;
 
1159
    }
 
1160
 
 
1161
  /* Record the time at which user timeout period starts.  */
 
1162
  userStartTime = kwsysProcessTimeGetCurrent();
 
1163
 
 
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);
 
1167
 
 
1168
  /* Loop until we have a reason to return.  */
 
1169
  while(!done && cp->PipesLeft > 0)
 
1170
    {
 
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)
 
1174
      {
 
1175
      ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
 
1176
      cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
 
1177
      }
 
1178
 
 
1179
    /* Setup a timeout if required.  */
 
1180
    if(kwsysProcessGetTimeoutLeft(&timeoutTime, &timeoutLength))
 
1181
      {
 
1182
      /* Timeout has already expired.  */
 
1183
      expired = 1;
 
1184
      break;
 
1185
      }
 
1186
    if(timeoutTime.QuadPart < 0)
 
1187
      {
 
1188
      timeout = INFINITE;
 
1189
      }
 
1190
    else
 
1191
      {
 
1192
      timeout = kwsysProcessTimeToDWORD(timeoutLength);
 
1193
      }
 
1194
 
 
1195
    /* Wait for a pipe's thread to signal or a process to terminate.  */
 
1196
    w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents,
 
1197
                               0, timeout);
 
1198
    if(w == WAIT_TIMEOUT)
 
1199
      {
 
1200
      /* Timeout has expired.  */
 
1201
      expired = 1;
 
1202
      done = 1;
 
1203
      }
 
1204
    else if(w == WAIT_OBJECT_0)
 
1205
      {
 
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);
 
1210
 
 
1211
      /* Data are available or a pipe closed.  */
 
1212
      if(cp->Pipe[cp->CurrentIndex].Closed)
 
1213
        {
 
1214
        /* The pipe closed.  */
 
1215
        --cp->PipesLeft;
 
1216
        }
 
1217
      else if(data && length)
 
1218
        {
 
1219
        /* Report this data.  */
 
1220
        *data = cp->Pipe[cp->CurrentIndex].DataBuffer;
 
1221
        *length = cp->Pipe[cp->CurrentIndex].DataLength;
 
1222
        switch(cp->CurrentIndex)
 
1223
          {
 
1224
          case KWSYSPE_PIPE_STDOUT:
 
1225
            pipeId = kwsysProcess_Pipe_STDOUT; break;
 
1226
          case KWSYSPE_PIPE_STDERR:
 
1227
            pipeId = kwsysProcess_Pipe_STDERR; break;
 
1228
          }
 
1229
        done = 1;
 
1230
        }
 
1231
      }
 
1232
    else
 
1233
      {
 
1234
      /* A process has terminated.  */
 
1235
      kwsysProcessDestroy(cp, w-WAIT_OBJECT_0);
 
1236
      }
 
1237
    }
 
1238
 
 
1239
  /* Update the user timeout.  */
 
1240
  if(userTimeout)
 
1241
    {
 
1242
    kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent();
 
1243
    kwsysProcessTime difference = kwsysProcessTimeSubtract(userEndTime,
 
1244
                                                           userStartTime);
 
1245
    double d = kwsysProcessTimeToDouble(difference);
 
1246
    *userTimeout -= d;
 
1247
    if(*userTimeout < 0)
 
1248
      {
 
1249
      *userTimeout = 0;
 
1250
      }
 
1251
    }
 
1252
 
 
1253
  /* Check what happened.  */
 
1254
  if(pipeId)
 
1255
    {
 
1256
    /* Data are ready on a pipe.  */
 
1257
    return pipeId;
 
1258
    }
 
1259
  else if(expired)
 
1260
    {
 
1261
    /* A timeout has expired.  */
 
1262
    if(user)
 
1263
      {
 
1264
      /* The user timeout has expired.  It has no time left.  */
 
1265
      return kwsysProcess_Pipe_Timeout;
 
1266
      }
 
1267
    else
 
1268
      {
 
1269
      /* The process timeout has expired.  Kill the child now.  */
 
1270
      kwsysProcess_Kill(cp);
 
1271
      cp->TimeoutExpired = 1;
 
1272
      cp->Killed = 0;
 
1273
      return kwsysProcess_Pipe_None;
 
1274
      }
 
1275
    }
 
1276
  else
 
1277
    {
 
1278
    /* The children have terminated and no more data are available.  */
 
1279
    return kwsysProcess_Pipe_None;
 
1280
    }
 
1281
}
 
1282
 
 
1283
/*--------------------------------------------------------------------------*/
 
1284
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
 
1285
{
 
1286
  int i;
 
1287
  int pipe;
 
1288
 
 
1289
  /* Make sure we are executing a process.  */
 
1290
  if(!cp || cp->State != kwsysProcess_State_Executing)
 
1291
    {
 
1292
    return 1;
 
1293
    }
 
1294
 
 
1295
  /* Wait for the process to terminate.  Ignore all data.  */
 
1296
  while((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0)
 
1297
    {
 
1298
    if(pipe == kwsysProcess_Pipe_Timeout)
 
1299
      {
 
1300
      /* The user timeout has expired.  */
 
1301
      return 0;
 
1302
      }
 
1303
    }
 
1304
 
 
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)
 
1308
    {
 
1309
    ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
 
1310
    cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
 
1311
    }
 
1312
 
 
1313
  /* Wait for all pipe threads to reset.  */
 
1314
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
 
1315
    {
 
1316
    WaitForSingleObject(cp->Pipe[i].Reset, INFINITE);
 
1317
    }
 
1318
 
 
1319
  /* ---- It is now safe again to call kwsysProcessCleanup. ----- */
 
1320
  /* Close all the pipes.  */
 
1321
  kwsysProcessCleanup(cp, 0);
 
1322
 
 
1323
  /* Determine the outcome.  */
 
1324
  if(cp->Killed)
 
1325
    {
 
1326
    /* We killed the child.  */
 
1327
    cp->State = kwsysProcess_State_Killed;
 
1328
    }
 
1329
  else if(cp->TimeoutExpired)
 
1330
    {
 
1331
    /* The timeout expired.  */
 
1332
    cp->State = kwsysProcess_State_Expired;
 
1333
    }
 
1334
  else
 
1335
    {
 
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)
 
1339
      {
 
1340
      /* Child terminated due to exceptional behavior.  */
 
1341
      cp->State = kwsysProcess_State_Exception;
 
1342
      cp->ExitValue = 1;
 
1343
      kwsysProcessSetExitException(cp, cp->ExitCode);
 
1344
      }
 
1345
    else
 
1346
      {
 
1347
      /* Child exited without exception.  */
 
1348
      cp->State = kwsysProcess_State_Exited;
 
1349
      cp->ExitException = kwsysProcess_Exception_None;
 
1350
      cp->ExitValue = cp->ExitCode;
 
1351
      }
 
1352
    }
 
1353
 
 
1354
  return 1;
 
1355
}
 
1356
 
 
1357
/*--------------------------------------------------------------------------*/
 
1358
void kwsysProcess_Kill(kwsysProcess* cp)
 
1359
{
 
1360
  int i;
 
1361
 
 
1362
  /* Make sure we are executing a process.  */
 
1363
  if(!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired ||
 
1364
     cp->Killed || cp->Terminated)
 
1365
    {
 
1366
    return;
 
1367
    }
 
1368
 
 
1369
  /* If we are killing a process that just reported data, release
 
1370
     the pipe's thread.  */
 
1371
  if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
 
1372
    {
 
1373
    ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Empty, 1, 0);
 
1374
    cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
 
1375
    }
 
1376
 
 
1377
  /* Wake up all the pipe threads with dummy data.  */
 
1378
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
 
1379
    {
 
1380
    DWORD dummy;
 
1381
    WriteFile(cp->Pipe[i].Write, "", 1, &dummy, 0);
 
1382
    }
 
1383
 
 
1384
  /* Tell pipe threads to reset until we run another process.  */
 
1385
  while(cp->PipesLeft > 0)
 
1386
    {
 
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);
 
1392
    --cp->PipesLeft;
 
1393
    }
 
1394
 
 
1395
  /* Kill the children.  */
 
1396
  cp->Killed = 1;
 
1397
  if(cp->Win9x)
 
1398
    {
 
1399
    /* Windows 9x.  Tell the forwarding executable to kill the child.  */
 
1400
    SetEvent(cp->Win9xKillEvent);
 
1401
    }
 
1402
  else
 
1403
    {
 
1404
    /* Not Windows 9x.  Just terminate the children.  */
 
1405
    for(i=0; i < cp->NumberOfCommands; ++i)
 
1406
      {
 
1407
      kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId);
 
1408
      }
 
1409
    }
 
1410
 
 
1411
  /* We are killing the children and ignoring all data.  Do not wait
 
1412
     for them to exit.  */
 
1413
}
 
1414
 
 
1415
/*--------------------------------------------------------------------------*/
 
1416
 
 
1417
/*
 
1418
  Function executed for each pipe's thread.  Argument is a pointer to
 
1419
  the kwsysProcessPipeData instance for this thread.
 
1420
*/
 
1421
DWORD WINAPI kwsysProcessPipeThread(LPVOID ptd)
 
1422
{
 
1423
  kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd;
 
1424
  kwsysProcess* cp = td->Process;
 
1425
 
 
1426
  /* Wait for a process to be ready.  */
 
1427
  while((WaitForSingleObject(td->Ready, INFINITE), !cp->Deleting))
 
1428
    {
 
1429
    /* Read output from the process for this thread's pipe.  */
 
1430
    kwsysProcessPipeThreadReadPipe(cp, td);
 
1431
 
 
1432
    /* We were signalled to exit with our buffer empty.  Reset the
 
1433
       mutex for a new process.  */
 
1434
    ReleaseSemaphore(td->Empty, 1, 0);
 
1435
 
 
1436
    /* Signal the main thread we have reset for a new process.  */
 
1437
    ReleaseSemaphore(td->Reset, 1, 0);
 
1438
    }
 
1439
  return 0;
 
1440
}
 
1441
 
 
1442
/*--------------------------------------------------------------------------*/
 
1443
 
 
1444
/*
 
1445
  Function called in each pipe's thread to handle data for one
 
1446
  execution of a subprocess.
 
1447
*/
 
1448
void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td)
 
1449
{
 
1450
  /* Wait for space in the thread's buffer. */
 
1451
  while((WaitForSingleObject(td->Empty, INFINITE), !td->Closed))
 
1452
    {
 
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))
 
1456
      {
 
1457
      if(GetLastError() != ERROR_BROKEN_PIPE)
 
1458
        {
 
1459
        /* UNEXPECTED failure to read the pipe.  */
 
1460
        }
 
1461
 
 
1462
      /* The pipe closed.  There are no more data to read.  */
 
1463
      td->Closed = 1;
 
1464
      }
 
1465
 
 
1466
    /* Wait for our turn to be handled by the main thread.  */
 
1467
    WaitForSingleObject(cp->SharedIndexMutex, INFINITE);
 
1468
 
 
1469
    /* Tell the main thread we have something to report.  */
 
1470
    cp->SharedIndex = td->Index;
 
1471
    ReleaseSemaphore(cp->Full, 1, 0);
 
1472
    }
 
1473
}
 
1474
 
 
1475
/*--------------------------------------------------------------------------*/
 
1476
/* Initialize a process control structure for kwsysProcess_Execute.  */
 
1477
int kwsysProcessInitialize(kwsysProcess* cp)
 
1478
{
 
1479
  /* Reset internal status flags.  */
 
1480
  cp->TimeoutExpired = 0;
 
1481
  cp->Terminated = 0;
 
1482
  cp->Killed = 0;
 
1483
  cp->ExitException = kwsysProcess_Exception_None;
 
1484
  cp->ExitCode = 1;
 
1485
  cp->ExitValue = 1;
 
1486
 
 
1487
  /* Reset error data.  */
 
1488
  cp->ErrorMessage[0] = 0;
 
1489
  strcpy(cp->ExitExceptionString, "No exception");
 
1490
 
 
1491
  /* Allocate process information for each process.  */
 
1492
  cp->ProcessInformation =
 
1493
    (PROCESS_INFORMATION*)malloc(sizeof(PROCESS_INFORMATION) *
 
1494
                                 cp->NumberOfCommands);
 
1495
  if(!cp->ProcessInformation)
 
1496
    {
 
1497
    return 0;
 
1498
    }
 
1499
  ZeroMemory(cp->ProcessInformation,
 
1500
             sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands);
 
1501
  if(cp->CommandExitCodes)
 
1502
    {
 
1503
    free(cp->CommandExitCodes);
 
1504
    }
 
1505
  cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD)*cp->NumberOfCommands);
 
1506
  if(!cp->CommandExitCodes)
 
1507
    {
 
1508
    return 0;
 
1509
    }
 
1510
  ZeroMemory(cp->CommandExitCodes, sizeof(DWORD)*cp->NumberOfCommands);
 
1511
 
 
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)
 
1516
    {
 
1517
    return 0;
 
1518
    }
 
1519
  ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands+1));
 
1520
  cp->ProcessEvents[0] = cp->Full;
 
1521
  cp->ProcessEventsLength = cp->NumberOfCommands+1;
 
1522
 
 
1523
  /* Allocate space to save the real working directory of this process.  */
 
1524
  if(cp->WorkingDirectory)
 
1525
    {
 
1526
    cp->RealWorkingDirectoryLength = GetCurrentDirectory(0, 0);
 
1527
    if(cp->RealWorkingDirectoryLength > 0)
 
1528
      {
 
1529
      cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength);
 
1530
      if(!cp->RealWorkingDirectory)
 
1531
        {
 
1532
        return 0;
 
1533
        }
 
1534
      }
 
1535
    }
 
1536
 
 
1537
  return 1;
 
1538
}
 
1539
 
 
1540
/*--------------------------------------------------------------------------*/
 
1541
int kwsysProcessCreate(kwsysProcess* cp, int index,
 
1542
                       kwsysProcessCreateInformation* si,
 
1543
                       PHANDLE readEnd)
 
1544
{
 
1545
  /* Setup the process's stdin.  */
 
1546
  if(*readEnd)
 
1547
    {
 
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)))
 
1555
      {
 
1556
      return 0;
 
1557
      }
 
1558
    si->StartupInfo.hStdInput = *readEnd;
 
1559
 
 
1560
    /* This function is done with this handle.  */
 
1561
    *readEnd = 0;
 
1562
    }
 
1563
  else if(cp->PipeFileSTDIN)
 
1564
    {
 
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)
 
1569
      {
 
1570
      return 0;
 
1571
      }
 
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)))
 
1578
      {
 
1579
      return 0;
 
1580
      }
 
1581
    si->StartupInfo.hStdInput = fin;
 
1582
    }
 
1583
  else if(cp->PipeSharedSTDIN)
 
1584
    {
 
1585
    si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
 
1586
    }
 
1587
  else
 
1588
    {
 
1589
    si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE;
 
1590
    }
 
1591
 
 
1592
  /* Setup the process's stdout.  */
 
1593
  {
 
1594
  DWORD maybeClose = DUPLICATE_CLOSE_SOURCE;
 
1595
  HANDLE writeEnd;
 
1596
 
 
1597
  /* Create the output pipe for this process.  Neither end is directly
 
1598
     inherited.  */
 
1599
  if(!CreatePipe(readEnd, &writeEnd, 0, 0))
 
1600
    {
 
1601
    return 0;
 
1602
    }
 
1603
 
 
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)
 
1608
    {
 
1609
    cp->Pipe[KWSYSPE_PIPE_STDOUT].Write = writeEnd;
 
1610
    maybeClose = 0;
 
1611
    }
 
1612
  if(!DuplicateHandle(GetCurrentProcess(), writeEnd,
 
1613
                      GetCurrentProcess(), &writeEnd,
 
1614
                      0, TRUE, (maybeClose | DUPLICATE_SAME_ACCESS)))
 
1615
    {
 
1616
    return 0;
 
1617
    }
 
1618
  si->StartupInfo.hStdOutput = writeEnd;
 
1619
  }
 
1620
 
 
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)
 
1624
    {
 
1625
    if(!kwsysProcessSetupOutputPipeFile(&si->StartupInfo.hStdOutput,
 
1626
                                        cp->PipeFileSTDOUT))
 
1627
      {
 
1628
      return 0;
 
1629
      }
 
1630
    }
 
1631
 
 
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
 
1634
     data.  */
 
1635
  if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT)
 
1636
    {
 
1637
    kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
 
1638
    si->StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 
1639
    }
 
1640
 
 
1641
  /* Create the child process.  */
 
1642
  {
 
1643
  BOOL r;
 
1644
  char* realCommand;
 
1645
  if(cp->Win9x)
 
1646
    {
 
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))
 
1650
      {
 
1651
      return 0;
 
1652
      }
 
1653
 
 
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)))
 
1660
      {
 
1661
      return 0;
 
1662
      }
 
1663
 
 
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);
 
1667
    if(!realCommand)
 
1668
      {
 
1669
      return 0;
 
1670
      }
 
1671
    sprintf(realCommand, "%s %p %p %p %d %s", cp->Win9x,
 
1672
            si->ErrorPipeWrite, cp->Win9xResumeEvent, cp->Win9xKillEvent,
 
1673
            cp->HideWindow, cp->Commands[index]);
 
1674
    }
 
1675
  else
 
1676
    {
 
1677
    realCommand = cp->Commands[index];
 
1678
    }
 
1679
 
 
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]);
 
1685
 
 
1686
  if(cp->Win9x)
 
1687
    {
 
1688
    /* Free memory.  */
 
1689
    free(realCommand);
 
1690
 
 
1691
    /* Close the error pipe write end so we can detect when the
 
1692
       forwarding executable closes it.  */
 
1693
    kwsysProcessCleanupHandle(&si->ErrorPipeWrite);
 
1694
    if(r)
 
1695
      {
 
1696
      /* Wait for the forwarding executable to report an error or
 
1697
         close the error pipe to report success.  */
 
1698
      DWORD total = 0;
 
1699
      DWORD n = 1;
 
1700
      while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0)
 
1701
        {
 
1702
        if(ReadFile(si->ErrorPipeRead, cp->ErrorMessage+total,
 
1703
                    KWSYSPE_PIPE_BUFFER_SIZE-total, &n, 0))
 
1704
          {
 
1705
          total += n;
 
1706
          }
 
1707
        else
 
1708
          {
 
1709
          n = 0;
 
1710
          }
 
1711
        }
 
1712
      if(total > 0 || GetLastError() != ERROR_BROKEN_PIPE)
 
1713
        {
 
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);
 
1722
        return 0;
 
1723
        }
 
1724
      }
 
1725
    kwsysProcessCleanupHandle(&si->ErrorPipeRead);
 
1726
    }
 
1727
 
 
1728
  if(!r)
 
1729
    {
 
1730
    return 0;
 
1731
    }
 
1732
  }
 
1733
 
 
1734
  /* Successfully created this child process.  */
 
1735
  if(index > 0)
 
1736
    {
 
1737
    /* Close our handle to the input pipe for the current process.  */
 
1738
    kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
 
1739
    }
 
1740
 
 
1741
  if(si->StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
 
1742
    {
 
1743
    /* The parent process does not need the inhertied pipe write end.  */
 
1744
    kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
 
1745
    }
 
1746
 
 
1747
  return 1;
 
1748
}
 
1749
 
 
1750
/*--------------------------------------------------------------------------*/
 
1751
void kwsysProcessDestroy(kwsysProcess* cp, int event)
 
1752
{
 
1753
  int i;
 
1754
  int index;
 
1755
 
 
1756
  /* Find the process index for the termination event.  */
 
1757
  for(index=0; index < cp->NumberOfCommands; ++index)
 
1758
    {
 
1759
    if(cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event])
 
1760
      {
 
1761
      break;
 
1762
      }
 
1763
    }
 
1764
 
 
1765
  /* Check the exit code of the process.  */
 
1766
  GetExitCodeProcess(cp->ProcessInformation[index].hProcess,
 
1767
                     &cp->CommandExitCodes[index]);
 
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
    {
 
1776
    cp->ProcessEvents[i] = cp->ProcessEvents[i+1];
 
1777
    }
 
1778
 
 
1779
  /* Check if all processes have terminated.  */
 
1780
  if(cp->ProcessEventsLength == 1)
 
1781
    {
 
1782
    cp->Terminated = 1;
 
1783
 
 
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)
 
1787
      {
 
1788
      kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
 
1789
      }
 
1790
    }
 
1791
}
 
1792
 
 
1793
/*--------------------------------------------------------------------------*/
 
1794
int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
 
1795
{
 
1796
  HANDLE fout;
 
1797
  if(!name)
 
1798
    {
 
1799
    return 1;
 
1800
    }
 
1801
 
 
1802
  /* Close the existing inherited handle.  */
 
1803
  kwsysProcessCleanupHandle(phandle);
 
1804
    
 
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)
 
1809
    {
 
1810
    return 0;
 
1811
    }
 
1812
 
 
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)))
 
1819
    {
 
1820
    return 0;
 
1821
    }
 
1822
 
 
1823
  /* Assign the replacement handle.  */
 
1824
  *phandle = fout;
 
1825
  return 1;
 
1826
}
 
1827
 
 
1828
/*--------------------------------------------------------------------------*/
 
1829
 
 
1830
/* Close the given handle if it is open.  Reset its value to 0.  */
 
1831
void kwsysProcessCleanupHandle(PHANDLE h)
 
1832
{
 
1833
  if(h && *h)
 
1834
    {
 
1835
    CloseHandle(*h);
 
1836
    *h = 0;
 
1837
    }
 
1838
}
 
1839
 
 
1840
/*--------------------------------------------------------------------------*/
 
1841
 
 
1842
/* Close all handles created by kwsysProcess_Execute.  */
 
1843
void kwsysProcessCleanup(kwsysProcess* cp, int error)
 
1844
{
 
1845
  int i;
 
1846
 
 
1847
  /* If this is an error case, report the error.  */
 
1848
  if(error)
 
1849
    {
 
1850
    /* Construct an error message if one has not been provided already.  */
 
1851
    if(cp->ErrorMessage[0] == 0)
 
1852
      {
 
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);
 
1859
      if(length < 1)
 
1860
        {
 
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());
 
1866
        }
 
1867
      }
 
1868
 
 
1869
    /* Remove trailing period and newline, if any.  */
 
1870
    kwsysProcessCleanErrorMessage(cp);
 
1871
 
 
1872
    /* Set the error state.  */
 
1873
    cp->State = kwsysProcess_State_Error;
 
1874
 
 
1875
    /* Cleanup any processes already started in a suspended state.  */
 
1876
    if(cp->ProcessInformation)
 
1877
      {
 
1878
      if(cp->Win9x)
 
1879
        {
 
1880
        SetEvent(cp->Win9xKillEvent);
 
1881
        }
 
1882
      else
 
1883
        {
 
1884
        for(i=0; i < cp->NumberOfCommands; ++i)
 
1885
          {
 
1886
          if(cp->ProcessInformation[i].hProcess)
 
1887
            {
 
1888
            TerminateProcess(cp->ProcessInformation[i].hProcess, 255);
 
1889
            WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE);
 
1890
            }
 
1891
          }
 
1892
        }
 
1893
      for(i=0; i < cp->NumberOfCommands; ++i)
 
1894
        {
 
1895
        kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
 
1896
        kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
 
1897
        }
 
1898
      }
 
1899
 
 
1900
    /* Restore the working directory.  */
 
1901
    if(cp->RealWorkingDirectory)
 
1902
      {
 
1903
      SetCurrentDirectory(cp->RealWorkingDirectory);
 
1904
      }
 
1905
    }
 
1906
 
 
1907
  /* Free memory.  */
 
1908
  if(cp->ProcessInformation)
 
1909
    {
 
1910
    free(cp->ProcessInformation);
 
1911
    cp->ProcessInformation = 0;
 
1912
    }
 
1913
  if(cp->ProcessEvents)
 
1914
    {
 
1915
    free(cp->ProcessEvents);
 
1916
    cp->ProcessEvents = 0;
 
1917
    }
 
1918
  if(cp->RealWorkingDirectory)
 
1919
    {
 
1920
    free(cp->RealWorkingDirectory);
 
1921
    cp->RealWorkingDirectory = 0;
 
1922
    }
 
1923
 
 
1924
  /* Close each pipe.  */
 
1925
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
 
1926
    {
 
1927
    kwsysProcessCleanupHandle(&cp->Pipe[i].Write);
 
1928
    kwsysProcessCleanupHandle(&cp->Pipe[i].Read);
 
1929
    }
 
1930
}
 
1931
 
 
1932
/*--------------------------------------------------------------------------*/
 
1933
void kwsysProcessCleanErrorMessage(kwsysProcess* cp)
 
1934
{
 
1935
  /* Remove trailing period and newline, if any.  */
 
1936
  int length = strlen(cp->ErrorMessage);
 
1937
  if(cp->ErrorMessage[length-1] == '\n')
 
1938
    {
 
1939
    cp->ErrorMessage[length-1] = 0;
 
1940
    --length;
 
1941
    if(length > 0 && cp->ErrorMessage[length-1] == '\r')
 
1942
      {
 
1943
      cp->ErrorMessage[length-1] = 0;
 
1944
      --length;
 
1945
      }
 
1946
    }
 
1947
  if(length > 0 && cp->ErrorMessage[length-1] == '.')
 
1948
    {
 
1949
    cp->ErrorMessage[length-1] = 0;
 
1950
    }
 
1951
}
 
1952
 
 
1953
/*--------------------------------------------------------------------------*/
 
1954
/* Get the time at which either the process or user timeout will
 
1955
   expire.  Returns 1 if the user timeout is first, and 0 otherwise.  */
 
1956
int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
 
1957
                               kwsysProcessTime* timeoutTime)
 
1958
{
 
1959
  /* The first time this is called, we need to calculate the time at
 
1960
     which the child will timeout.  */
 
1961
  if(cp->Timeout && cp->TimeoutTime.QuadPart < 0)
 
1962
    {
 
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
    {
 
1973
    kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
 
1974
    kwsysProcessTime userTimeoutLength = kwsysProcessTimeFromDouble(*userTimeout);
 
1975
    kwsysProcessTime userTimeoutTime = kwsysProcessTimeAdd(currentTime,
 
1976
                                                           userTimeoutLength);
 
1977
    if(kwsysProcessTimeLess(userTimeoutTime, *timeoutTime))
 
1978
      {
 
1979
      *timeoutTime = userTimeoutTime;
 
1980
      return 1;
 
1981
      }
 
1982
    }
 
1983
  return 0;
 
1984
}
 
1985
 
 
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)
 
1991
{
 
1992
  if(timeoutTime->QuadPart < 0)
 
1993
    {
 
1994
    /* No timeout time has been requested.  */
 
1995
    return 0;
 
1996
    }
 
1997
  else
 
1998
    {
 
1999
    /* Calculate the remaining time.  */
 
2000
    kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent();
 
2001
    *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime);
 
2002
    if(timeoutLength->QuadPart < 0)
 
2003
      {
 
2004
      /* Timeout has already expired.  */
 
2005
      return 1;
 
2006
      }
 
2007
    else
 
2008
      {
 
2009
      /* There is some time left.  */
 
2010
      return 0;
 
2011
      }
 
2012
    }
 
2013
}
 
2014
 
 
2015
/*--------------------------------------------------------------------------*/
 
2016
kwsysProcessTime kwsysProcessTimeGetCurrent()
 
2017
{
 
2018
  kwsysProcessTime current;
 
2019
  FILETIME ft;
 
2020
  GetSystemTimeAsFileTime(&ft);
 
2021
  current.LowPart = ft.dwLowDateTime;
 
2022
  current.HighPart = ft.dwHighDateTime;
 
2023
  return current;
 
2024
}
 
2025
 
 
2026
/*--------------------------------------------------------------------------*/
 
2027
DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t)
 
2028
{
 
2029
  return (DWORD)(t.QuadPart * 0.0001);
 
2030
}
 
2031
 
 
2032
/*--------------------------------------------------------------------------*/
 
2033
double kwsysProcessTimeToDouble(kwsysProcessTime t)
 
2034
{
 
2035
  return t.QuadPart * 0.0000001;
 
2036
}
 
2037
 
 
2038
/*--------------------------------------------------------------------------*/
 
2039
kwsysProcessTime kwsysProcessTimeFromDouble(double d)
 
2040
{
 
2041
  kwsysProcessTime t;
 
2042
  t.QuadPart = (LONGLONG)(d*10000000);
 
2043
  return t;
 
2044
}
 
2045
 
 
2046
/*--------------------------------------------------------------------------*/
 
2047
int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2)
 
2048
{
 
2049
  return in1.QuadPart < in2.QuadPart;
 
2050
}
 
2051
 
 
2052
/*--------------------------------------------------------------------------*/
 
2053
kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, kwsysProcessTime in2)
 
2054
{
 
2055
  kwsysProcessTime out;
 
2056
  out.QuadPart = in1.QuadPart + in2.QuadPart;
 
2057
  return out;
 
2058
}
 
2059
 
 
2060
/*--------------------------------------------------------------------------*/
 
2061
kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProcessTime in2)
 
2062
{
 
2063
  kwsysProcessTime out;
 
2064
  out.QuadPart = in1.QuadPart - in2.QuadPart;
 
2065
  return out;
 
2066
}
 
2067
 
 
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)
 
2073
{
 
2074
  switch (code)
 
2075
    {
 
2076
    case STATUS_CONTROL_C_EXIT:
 
2077
      KWSYSPE_CASE(Interrupt, "User interrupt"); break;
 
2078
 
 
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;
 
2096
#endif
 
2097
#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
 
2098
    case STATUS_FLOAT_MULTIPLE_TRAPS:
 
2099
      KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); break;
 
2100
#endif
 
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;
 
2105
 
 
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;
 
2122
 
 
2123
    case STATUS_ILLEGAL_INSTRUCTION:
 
2124
      KWSYSPE_CASE(Illegal, "Illegal instruction"); break;
 
2125
    case STATUS_PRIVILEGED_INSTRUCTION:
 
2126
      KWSYSPE_CASE(Illegal, "Privileged instruction"); break;
 
2127
 
 
2128
    case STATUS_NO_MEMORY:
 
2129
    default:
 
2130
      cp->ExitException = kwsysProcess_Exception_Other;
 
2131
      sprintf(cp->ExitExceptionString, "Exit code 0x%x\n", code);
 
2132
      break;
 
2133
    }
 
2134
}
 
2135
#undef KWSYSPE_CASE
 
2136
 
 
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);
 
2144
 
 
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
 
2152
{
 
2153
  USHORT Length;
 
2154
  USHORT MaximumLength;
 
2155
  PWSTR Buffer;
 
2156
};
 
2157
 
 
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
 
2164
{
 
2165
  ULONG          NextEntryDelta;
 
2166
  ULONG          ThreadCount;
 
2167
  ULONG          Reserved1[6];
 
2168
  LARGE_INTEGER  CreateTime;
 
2169
  LARGE_INTEGER  UserTime;
 
2170
  LARGE_INTEGER  KernelTime;
 
2171
  UNICODE_STRING ProcessName;
 
2172
  KPRIORITY      BasePriority;
 
2173
  ULONG          ProcessId;
 
2174
  ULONG          InheritedFromProcessId;
 
2175
};
 
2176
 
 
2177
/*--------------------------------------------------------------------------*/
 
2178
/* Toolhelp32 API definitions.  */
 
2179
#define TH32CS_SNAPPROCESS  0x00000002
 
2180
typedef struct tagPROCESSENTRY32 PROCESSENTRY32;
 
2181
typedef PROCESSENTRY32* LPPROCESSENTRY32;
 
2182
struct tagPROCESSENTRY32
 
2183
{
 
2184
  DWORD dwSize;
 
2185
  DWORD cntUsage;
 
2186
  DWORD th32ProcessID;
 
2187
  DWORD th32DefaultHeapID;
 
2188
  DWORD th32ModuleID;
 
2189
  DWORD cntThreads;
 
2190
  DWORD th32ParentProcessID;
 
2191
  LONG  pcPriClassBase;
 
2192
  DWORD dwFlags;
 
2193
  char szExeFile[MAX_PATH];
 
2194
};
 
2195
 
 
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,
 
2202
                                                        ULONG, PULONG);
 
2203
 
 
2204
 
 
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);
 
2218
 
 
2219
struct kwsysProcess_List_s
 
2220
{
 
2221
  /* Implementation switches at runtime based on version of Windows.  */
 
2222
  int NT4;
 
2223
 
 
2224
  /* Implementation functions and data for NT 4.  */
 
2225
  ZwQuerySystemInformationType P_ZwQuerySystemInformation;
 
2226
  char* Buffer;
 
2227
  int BufferSize;
 
2228
  PSYSTEM_PROCESS_INFORMATION CurrentInfo;
 
2229
 
 
2230
  /* Implementation functions and data for other Windows versions.  */
 
2231
  CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot;
 
2232
  Process32FirstType P_Process32First;
 
2233
  Process32NextType P_Process32Next;
 
2234
  HANDLE Snapshot;
 
2235
  PROCESSENTRY32 CurrentEntry;
 
2236
};
 
2237
 
 
2238
/*--------------------------------------------------------------------------*/
 
2239
static kwsysProcess_List* kwsysProcess_List_New()
 
2240
{
 
2241
  OSVERSIONINFO osv;
 
2242
  kwsysProcess_List* self;
 
2243
 
 
2244
  /* Allocate and initialize the list object.  */
 
2245
  if(!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List))))
 
2246
    {
 
2247
    return 0;
 
2248
    }
 
2249
  memset(self, 0, sizeof(*self));
 
2250
 
 
2251
  /* Select an implementation.  */
 
2252
  ZeroMemory(&osv, sizeof(osv));
 
2253
  osv.dwOSVersionInfoSize = sizeof(osv);
 
2254
  GetVersionEx(&osv);
 
2255
  self->NT4 = (osv.dwPlatformId == VER_PLATFORM_WIN32_NT &&
 
2256
               osv.dwMajorVersion < 5)? 1:0;
 
2257
 
 
2258
  /* Initialize the selected implementation.  */
 
2259
  if(!(self->NT4?
 
2260
       kwsysProcess_List__New_NT4(self) :
 
2261
       kwsysProcess_List__New_Snapshot(self)))
 
2262
    {
 
2263
    kwsysProcess_List_Delete(self);
 
2264
    return 0;
 
2265
    }
 
2266
 
 
2267
  /* Update to the current set of processes.  */
 
2268
  if(!kwsysProcess_List_Update(self))
 
2269
    {
 
2270
    kwsysProcess_List_Delete(self);
 
2271
    return 0;
 
2272
    }
 
2273
  return self;
 
2274
}
 
2275
 
 
2276
/*--------------------------------------------------------------------------*/
 
2277
static void kwsysProcess_List_Delete(kwsysProcess_List* self)
 
2278
{
 
2279
  if(self)
 
2280
    {
 
2281
    if(self->NT4)
 
2282
      {
 
2283
      kwsysProcess_List__Delete_NT4(self);
 
2284
      }
 
2285
    else
 
2286
      {
 
2287
      kwsysProcess_List__Delete_Snapshot(self);
 
2288
      }
 
2289
    free(self);
 
2290
    }
 
2291
}
 
2292
 
 
2293
/*--------------------------------------------------------------------------*/
 
2294
static int kwsysProcess_List_Update(kwsysProcess_List* self)
 
2295
{
 
2296
  return self? (self->NT4?
 
2297
                kwsysProcess_List__Update_NT4(self) :
 
2298
                kwsysProcess_List__Update_Snapshot(self)) : 0;
 
2299
}
 
2300
 
 
2301
/*--------------------------------------------------------------------------*/
 
2302
static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self)
 
2303
{
 
2304
  return self? (self->NT4?
 
2305
                kwsysProcess_List__GetProcessId_NT4(self) :
 
2306
                kwsysProcess_List__GetProcessId_Snapshot(self)) : -1;
 
2307
 
 
2308
}
 
2309
 
 
2310
/*--------------------------------------------------------------------------*/
 
2311
static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self)
 
2312
{
 
2313
  return self? (self->NT4?
 
2314
                kwsysProcess_List__GetParentId_NT4(self) :
 
2315
                kwsysProcess_List__GetParentId_Snapshot(self)) : -1;
 
2316
 
 
2317
}
 
2318
 
 
2319
/*--------------------------------------------------------------------------*/
 
2320
static int kwsysProcess_List_NextProcess(kwsysProcess_List* self)
 
2321
{
 
2322
  return (self? (self->NT4?
 
2323
                 kwsysProcess_List__Next_NT4(self) :
 
2324
                 kwsysProcess_List__Next_Snapshot(self)) : 0);
 
2325
}
 
2326
 
 
2327
/*--------------------------------------------------------------------------*/
 
2328
static int kwsysProcess_List__New_NT4(kwsysProcess_List* self)
 
2329
{
 
2330
  HANDLE hNT = GetModuleHandle("ntdll.dll");
 
2331
  if(hNT)
 
2332
    {
 
2333
    /* Get pointers to the needed API functions.  */
 
2334
    self->P_ZwQuerySystemInformation =
 
2335
      ((ZwQuerySystemInformationType)
 
2336
       GetProcAddress(hNT, "ZwQuerySystemInformation"));
 
2337
    CloseHandle(hNT);
 
2338
    }
 
2339
  if(!self->P_ZwQuerySystemInformation)
 
2340
    {
 
2341
    return 0;
 
2342
    }
 
2343
 
 
2344
  /* Allocate an initial process information buffer.  */
 
2345
  self->BufferSize = 32768;
 
2346
  self->Buffer = (char*)malloc(self->BufferSize);
 
2347
  return self->Buffer? 1:0;
 
2348
}
 
2349
 
 
2350
/*--------------------------------------------------------------------------*/
 
2351
static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self)
 
2352
{
 
2353
  /* Free the process information buffer.  */
 
2354
  if(self->Buffer)
 
2355
    {
 
2356
    free(self->Buffer);
 
2357
    }
 
2358
}
 
2359
 
 
2360
/*--------------------------------------------------------------------------*/
 
2361
static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self)
 
2362
{
 
2363
  self->CurrentInfo = 0;
 
2364
  while(1)
 
2365
    {
 
2366
    /* Query number 5 is for system process list.  */
 
2367
    NTSTATUS status =
 
2368
      self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0);
 
2369
    if(status == STATUS_INFO_LENGTH_MISMATCH)
 
2370
      {
 
2371
      /* The query requires a bigger buffer.  */
 
2372
      int newBufferSize = self->BufferSize * 2;
 
2373
      char* newBuffer = (char*)malloc(newBufferSize);
 
2374
      if(newBuffer)
 
2375
        {
 
2376
        free(self->Buffer);
 
2377
        self->Buffer = newBuffer;
 
2378
        self->BufferSize = newBufferSize;
 
2379
        }
 
2380
      else
 
2381
        {
 
2382
        return 0;
 
2383
        }
 
2384
      }
 
2385
    else if(status >= 0)
 
2386
      {
 
2387
      /* The query succeeded.  Initialize traversal of the process list.  */
 
2388
      self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer;
 
2389
      return 1;
 
2390
      }
 
2391
    else
 
2392
      {
 
2393
      /* The query failed.  */
 
2394
      return 0;
 
2395
      }
 
2396
    }
 
2397
}
 
2398
 
 
2399
/*--------------------------------------------------------------------------*/
 
2400
static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self)
 
2401
{
 
2402
  if(self->CurrentInfo)
 
2403
    {
 
2404
    if(self->CurrentInfo->NextEntryDelta > 0)
 
2405
      {
 
2406
      self->CurrentInfo = ((PSYSTEM_PROCESS_INFORMATION)
 
2407
                              ((char*)self->CurrentInfo +
 
2408
                               self->CurrentInfo->NextEntryDelta));
 
2409
      return 1;
 
2410
      }
 
2411
    self->CurrentInfo = 0;
 
2412
    }
 
2413
  return 0;
 
2414
}
 
2415
 
 
2416
/*--------------------------------------------------------------------------*/
 
2417
static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self)
 
2418
{
 
2419
  return self->CurrentInfo? self->CurrentInfo->ProcessId : -1;
 
2420
}
 
2421
 
 
2422
/*--------------------------------------------------------------------------*/
 
2423
static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self)
 
2424
{
 
2425
  return self->CurrentInfo? self->CurrentInfo->InheritedFromProcessId : -1;
 
2426
}
 
2427
 
 
2428
/*--------------------------------------------------------------------------*/
 
2429
static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self)
 
2430
{
 
2431
  HANDLE hKernel = GetModuleHandle("kernel32.dll");
 
2432
  if(hKernel)
 
2433
    {
 
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);
 
2444
    }
 
2445
  return (self->P_CreateToolhelp32Snapshot &&
 
2446
          self->P_Process32First &&
 
2447
          self->P_Process32Next)? 1:0;
 
2448
}
 
2449
 
 
2450
/*--------------------------------------------------------------------------*/
 
2451
static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self)
 
2452
{
 
2453
  if(self->Snapshot)
 
2454
    {
 
2455
    CloseHandle(self->Snapshot);
 
2456
    }
 
2457
}
 
2458
 
 
2459
/*--------------------------------------------------------------------------*/
 
2460
static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self)
 
2461
{
 
2462
  if(self->Snapshot)
 
2463
    {
 
2464
    CloseHandle(self->Snapshot);
 
2465
    }
 
2466
  if(!(self->Snapshot =
 
2467
       self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)))
 
2468
    {
 
2469
    return 0;
 
2470
    }
 
2471
  ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry));
 
2472
  self->CurrentEntry.dwSize = sizeof(self->CurrentEntry);
 
2473
  if(!self->P_Process32First(self->Snapshot, &self->CurrentEntry))
 
2474
    {
 
2475
    CloseHandle(self->Snapshot);
 
2476
    self->Snapshot = 0;
 
2477
    return 0;
 
2478
    }
 
2479
  return 1;
 
2480
}
 
2481
 
 
2482
/*--------------------------------------------------------------------------*/
 
2483
static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self)
 
2484
{
 
2485
  if(self->Snapshot)
 
2486
    {
 
2487
    if(self->P_Process32Next(self->Snapshot, &self->CurrentEntry))
 
2488
      {
 
2489
      return 1;
 
2490
      }
 
2491
    CloseHandle(self->Snapshot);
 
2492
    self->Snapshot = 0;
 
2493
    }
 
2494
  return 0;
 
2495
}
 
2496
 
 
2497
/*--------------------------------------------------------------------------*/
 
2498
static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self)
 
2499
{
 
2500
  return self->Snapshot? self->CurrentEntry.th32ProcessID : -1;
 
2501
}
 
2502
 
 
2503
/*--------------------------------------------------------------------------*/
 
2504
static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self)
 
2505
{
 
2506
  return self->Snapshot? self->CurrentEntry.th32ParentProcessID : -1;
 
2507
}
 
2508
 
 
2509
/*--------------------------------------------------------------------------*/
 
2510
static void kwsysProcessKill(DWORD pid)
 
2511
{
 
2512
  HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid);
 
2513
  if(h)
 
2514
    {
 
2515
    TerminateProcess(h, 255);
 
2516
    WaitForSingleObject(h, INFINITE);
 
2517
    }
 
2518
}
 
2519
 
 
2520
/*--------------------------------------------------------------------------*/
 
2521
static void kwsysProcessKillTree(int pid)
 
2522
{
 
2523
  kwsysProcess_List* plist = kwsysProcess_List_New();
 
2524
  kwsysProcessKill(pid);
 
2525
  if(plist)
 
2526
    {
 
2527
    do
 
2528
      {
 
2529
      if(kwsysProcess_List_GetCurrentParentId(plist) == pid)
 
2530
        {
 
2531
        int ppid = kwsysProcess_List_GetCurrentProcessId(plist);
 
2532
        kwsysProcessKillTree(ppid);
 
2533
        }
 
2534
      } while(kwsysProcess_List_NextProcess(plist));
 
2535
    kwsysProcess_List_Delete(plist);
 
2536
    }
 
2537
}