[Tizen_6_build] Fixed 32-bit arm build with gcc 9
[platform/upstream/boost-jam.git] / execnt.c
1 /*
2  * Copyright 1993, 1995 Christopher Seiwald.
3  *
4  * This file is part of Jam - see jam.c for Copyright information.
5  */
6
7 /*  This file is ALSO:
8  *  Copyright 2001-2004 David Abrahams.
9  *  Copyright 2007 Rene Rivera.
10  *  Distributed under the Boost Software License, Version 1.0.
11  *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
12  */
13
14 #include "jam.h"
15 #include "lists.h"
16 #include "execcmd.h"
17 #include "pathsys.h"
18 #include "string.h"
19 #include "output.h"
20 #include <errno.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <time.h>
24 #include <math.h>
25
26 #ifdef USE_EXECNT
27
28 #define WIN32_LEAN_AND_MEAN
29 #include <windows.h>
30 #include <process.h>
31 #include <tlhelp32.h>
32
33 /*
34  * execnt.c - execute a shell command on Windows NT
35  *
36  * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
37  * The default is:
38  *
39  *  /bin/sh -c %        [ on UNIX/AmigaOS ]
40  *  cmd.exe /c %        [ on Windows NT ]
41  *
42  * Each word must be an individual element in a jam variable value.
43  *
44  * In $(JAMSHELL), % expands to the command string and ! expands to
45  * the slot number (starting at 1) for multiprocess (-j) invocations.
46  * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
47  * argument.
48  *
49  * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
50  *
51  * External routines:
52  *  exec_cmd() - launch an async command execution.
53  *  exec_wait() - wait and drive at most one execution completion.
54  *
55  * Internal routines:
56  *  onintr() - bump intr to note command interruption.
57  *
58  * 04/08/94 (seiwald) - Coherent/386 support added.
59  * 05/04/94 (seiwald) - async multiprocess interface
60  * 01/22/95 (seiwald) - $(JAMSHELL) support
61  * 06/02/97 (gsar)    - full async multiprocess support for Win32
62  */
63
64 /* get the maximum command line length according to the OS */
65 int maxline();
66
67 /* delete and argv list */
68 static void free_argv(char**);
69 /* Convert a command string into arguments for spawnvp. */
70 static char** string_to_args(const char*);
71 /* bump intr to note command interruption */
72 static void onintr(int);
73 /* If the command is suitable for execution via spawnvp */
74 long can_spawn(char*);
75 /* Add two 64-bit unsigned numbers, h1l1 and h2l2 */
76 static FILETIME add_64(
77     unsigned long h1, unsigned long l1,
78     unsigned long h2, unsigned long l2);
79 static FILETIME add_FILETIME(FILETIME t1, FILETIME t2);
80 static FILETIME negate_FILETIME(FILETIME t);
81 /* Convert a FILETIME to a number of seconds */
82 static double filetime_seconds(FILETIME t);
83 /* record the timing info for the process */
84 static void record_times(HANDLE, timing_info*);
85 /* calc the current running time of an *active* process */
86 static double running_time(HANDLE);
87 /* */
88 DWORD get_process_id(HANDLE);
89 /* terminate the given process, after terminating all its children */
90 static void kill_process_tree(DWORD, HANDLE);
91 /* waits for a command to complete or for the given timeout, whichever is first */
92 static int try_wait(int timeoutMillis);
93 /* reads any pending output for running commands */
94 static void read_output();
95 /* checks if a command ran out of time, and kills it */
96 static int try_kill_one();
97 /* */
98 static double creation_time(HANDLE);
99 /* Recursive check if first process is parent (directly or indirectly) of
100 the second one. */
101 static int is_parent_child(DWORD, DWORD);
102 /* */
103 static void close_alert(HANDLE);
104 /* close any alerts hanging around */
105 static void close_alerts();
106
107 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
108
109 static int intr = 0;
110 static int cmdsrunning = 0;
111 static void (* istat)( int );
112
113
114 /* The list of commands we run. */
115 static struct
116 {
117     string action;   /* buffer to hold action */
118     string target;   /* buffer to hold target */
119     string command;  /* buffer to hold command being invoked */
120
121     /* Temporary batch file used to execute the action when needed. */
122     char * tempfile_bat;
123
124     /* Pipes for communicating with the child process. Parent reads from (0),
125      * child writes to (1).
126      */
127     HANDLE pipe_out[ 2 ];
128     HANDLE pipe_err[ 2 ];
129
130     string              buffer_out;   /* buffer to hold stdout, if any */
131     string              buffer_err;   /* buffer to hold stderr, if any */
132
133     PROCESS_INFORMATION pi;           /* running process information */
134     DWORD               exit_code;    /* executed command's exit code */
135     int                 exit_reason;  /* reason why a command completed */
136
137     /* Function called when the command completes. */
138     void (* func)( void * closure, int status, timing_info *, char *, char * );
139
140     /* Opaque data passed back to the 'func' callback called when the command
141      * completes.
142      */
143     void * closure;
144 }
145 cmdtab[ MAXJOBS ] = { { 0 } };
146
147
148 /*
149  * Execution unit tests.
150  */
151
152 void execnt_unit_test()
153 {
154 #if !defined( NDEBUG )
155     /* vc6 preprocessor is broken, so assert with these strings gets confused.
156      * Use a table instead.
157      */
158     typedef struct test { char * command; int result; } test;
159     test tests[] = {
160         { "x", 0 },
161         { "x\n ", 0 },
162         { "x\ny", 1 },
163         { "x\n\n y", 1 },
164         { "echo x > foo.bar", 1 },
165         { "echo x < foo.bar", 1 },
166         { "echo x \">\" foo.bar", 0 },
167         { "echo x \"<\" foo.bar", 0 },
168         { "echo x \\\">\\\" foo.bar", 1 },
169         { "echo x \\\"<\\\" foo.bar", 1 } };
170     int i;
171     for ( i = 0; i < sizeof( tests ) / sizeof( *tests ); ++i )
172         assert( !can_spawn( tests[ i ].command ) == tests[ i ].result );
173
174     {
175         char * long_command = BJAM_MALLOC_ATOMIC( MAXLINE + 10 );
176         assert( long_command != 0 );
177         memset( long_command, 'x', MAXLINE + 9 );
178         long_command[ MAXLINE + 9 ] = 0;
179         assert( can_spawn( long_command ) == MAXLINE + 9 );
180         BJAM_FREE( long_command );
181     }
182
183     {
184         /* Work around vc6 bug; it doesn't like escaped string
185          * literals inside assert
186          */
187         char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
188         char const expected[] = "-c -I\"Foobar\"";
189
190         assert( !strcmp( argv[ 0 ], "g++" ) );
191         assert( !strcmp( argv[ 1 ], expected ) );
192         free_argv( argv );
193     }
194 #endif
195 }
196
197
198 /*
199  * exec_cmd() - launch an async command execution.
200  */
201
202 void exec_cmd
203 (
204     char * command,
205     void (* func)( void * closure, int status, timing_info *, char * invoked_command, char * command_output ),
206     void * closure,
207     LIST * shell,
208     char * action,
209     char * target
210 )
211 {
212     int      slot;
213     int      raw_cmd = 0 ;
214     char   * argv_static[ MAXARGC + 1 ];  /* +1 for NULL */
215     char * * argv = argv_static;
216     char   * p;
217     char   * command_orig = command;
218
219     /* Check to see if we need to hack around the line-length limitation. Look
220      * for a JAMSHELL setting of "%", indicating that the command should be
221      * invoked directly.
222      */
223     if ( shell && !strcmp( shell->string, "%" ) && !list_next( shell ) )
224     {
225         raw_cmd = 1;
226         shell = 0;
227     }
228
229     /* Find a slot in the running commands table for this one. */
230     for ( slot = 0; slot < MAXJOBS; ++slot )
231         if ( !cmdtab[ slot ].pi.hProcess )
232             break;
233     if ( slot == MAXJOBS )
234     {
235         printf( "no slots for child!\n" );
236         exit( EXITBAD );
237     }
238
239     /* Compute the name of a temp batch file, for possible use. */
240     if ( !cmdtab[ slot ].tempfile_bat )
241     {
242         char const * tempdir = path_tmpdir();
243         DWORD procID = GetCurrentProcessId();
244
245         /* SVA - allocate 64 bytes extra just to be safe. */
246         cmdtab[ slot ].tempfile_bat = BJAM_MALLOC_ATOMIC( strlen( tempdir ) + 64 );
247
248         sprintf( cmdtab[ slot ].tempfile_bat, "%s\\jam%d-%02d.bat",
249             tempdir, procID, slot );
250     }
251
252     /* Trim leading, -ending- white space */
253     while ( *( command + 1 ) && isspace( *command ) )
254         ++command;
255
256     /* Write to .BAT file unless the line would be too long and it meets the
257      * other spawnability criteria.
258      */
259     if ( raw_cmd && ( can_spawn( command ) >= MAXLINE ) )
260     {
261         if ( DEBUG_EXECCMD )
262             printf("Executing raw command directly\n");
263     }
264     else
265     {
266         FILE * f = 0;
267         int tries = 0;
268         raw_cmd = 0;
269
270         /* Write command to bat file. For some reason this open can fail
271          * intermitently. But doing some retries works. Most likely this is due
272          * to a previously existing file of the same name that happens to be
273          * opened by an active virus scanner. Pointed out and fixed by Bronek
274          * Kozicki.
275          */
276         for ( ; !f && ( tries < 4 ); ++tries )
277         {
278             f = fopen( cmdtab[ slot ].tempfile_bat, "w" );
279             if ( !f && ( tries < 4 ) ) Sleep( 250 );
280         }
281         if ( !f )
282         {
283             printf( "failed to write command file!\n" );
284             exit( EXITBAD );
285         }
286         fputs( command, f );
287         fclose( f );
288
289         command = cmdtab[ slot ].tempfile_bat;
290
291         if ( DEBUG_EXECCMD )
292         {
293             if ( shell )
294                 printf( "using user-specified shell: %s", shell->string );
295             else
296                 printf( "Executing through .bat file\n" );
297         }
298     }
299
300     /* Formulate argv; If shell was defined, be prepared for % and ! subs.
301      * Otherwise, use stock cmd.exe.
302      */
303     if ( shell )
304     {
305         int i;
306         char jobno[ 4 ];
307         int gotpercent = 0;
308
309         sprintf( jobno, "%d", slot + 1 );
310
311         for ( i = 0; shell && ( i < MAXARGC ); ++i, shell = list_next( shell ) )
312         {
313             switch ( shell->string[ 0 ] )
314             {
315                 case '%': argv[ i ] = command; ++gotpercent; break;
316                 case '!': argv[ i ] = jobno; break;
317                 default : argv[ i ] = shell->string;
318             }
319             if ( DEBUG_EXECCMD )
320                 printf( "argv[%d] = '%s'\n", i, argv[ i ] );
321         }
322
323         if ( !gotpercent )
324             argv[ i++ ] = command;
325
326         argv[ i ] = 0;
327     }
328     else if ( raw_cmd )
329     {
330         argv = string_to_args( command );
331     }
332     else
333     {
334         argv[ 0 ] = "cmd.exe";
335         argv[ 1 ] = "/Q/C";  /* anything more is non-portable */
336         argv[ 2 ] = command;
337         argv[ 3 ] = 0;
338     }
339
340     /* Catch interrupts whenever commands are running. */
341     if ( !cmdsrunning++ )
342         istat = signal( SIGINT, onintr );
343
344     /* Start the command. */
345     {
346         SECURITY_ATTRIBUTES sa
347             = { sizeof( SECURITY_ATTRIBUTES ), 0, 0 };
348         SECURITY_DESCRIPTOR sd;
349         STARTUPINFO si
350             = { sizeof( STARTUPINFO ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
351         string cmd;
352
353         /* Init the security data. */
354         InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION );
355         SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE );
356         sa.lpSecurityDescriptor = &sd;
357         sa.bInheritHandle = TRUE;
358
359         /* Create the stdout, which is also the merged out + err, pipe. */
360         if ( !CreatePipe( &cmdtab[ slot ].pipe_out[ 0 ],
361             &cmdtab[ slot ].pipe_out[ 1 ], &sa, 0 ) )
362         {
363             perror( "CreatePipe" );
364             exit( EXITBAD );
365         }
366
367         /* Create the stdout, which is also the merged out+err, pipe. */
368         if ( globs.pipe_action == 2 )
369         {
370             if ( !CreatePipe( &cmdtab[ slot ].pipe_err[ 0 ],
371                 &cmdtab[ slot ].pipe_err[ 1 ], &sa, 0 ) )
372             {
373                 perror( "CreatePipe" );
374                 exit( EXITBAD );
375             }
376         }
377
378         /* Set handle inheritance off for the pipe ends the parent reads from. */
379         SetHandleInformation( cmdtab[ slot ].pipe_out[ 0 ], HANDLE_FLAG_INHERIT, 0 );
380         if ( globs.pipe_action == 2 )
381             SetHandleInformation( cmdtab[ slot ].pipe_err[ 0 ], HANDLE_FLAG_INHERIT, 0 );
382
383         /* Hide the child window, if any. */
384         si.dwFlags |= STARTF_USESHOWWINDOW;
385         si.wShowWindow = SW_HIDE;
386
387         /* Set the child outputs to the pipes. */
388         si.dwFlags |= STARTF_USESTDHANDLES;
389         si.hStdOutput = cmdtab[ slot ].pipe_out[ 1 ];
390         if ( globs.pipe_action == 2 )
391         {
392             /* Pipe stderr to the action error output. */
393             si.hStdError = cmdtab[ slot ].pipe_err[ 1 ];
394         }
395         else if ( globs.pipe_action == 1 )
396         {
397             /* Pipe stderr to the console error output. */
398             si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
399         }
400         else
401         {
402             /* Pipe stderr to the action merged output. */
403             si.hStdError = cmdtab[ slot ].pipe_out[ 1 ];
404         }
405
406         /* Let the child inherit stdin, as some commands assume it's available. */
407         si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
408
409         /* Save the operation for exec_wait() to find. */
410         cmdtab[ slot ].func = func;
411         cmdtab[ slot ].closure = closure;
412         if ( action && target )
413         {
414             string_copy( &cmdtab[ slot ].action, action );
415             string_copy( &cmdtab[ slot ].target, target );
416         }
417         else
418         {
419             string_free( &cmdtab[ slot ].action );
420             string_new ( &cmdtab[ slot ].action );
421             string_free( &cmdtab[ slot ].target );
422             string_new ( &cmdtab[ slot ].target );
423         }
424         string_copy( &cmdtab[ slot ].command, command_orig );
425
426         /* Put together the command we run. */
427         {
428             char * * argp = argv;
429             string_new( &cmd );
430             string_copy( &cmd, *(argp++) );
431             while ( *argp )
432             {
433                 string_push_back( &cmd, ' ' );
434                 string_append( &cmd, *(argp++) );
435             }
436         }
437
438         /* Create output buffers. */
439         string_new( &cmdtab[ slot ].buffer_out );
440         string_new( &cmdtab[ slot ].buffer_err );
441
442         /* Run the command by creating a sub-process for it. */
443         if (
444             ! CreateProcess(
445                 NULL                    ,  /* application name               */
446                 cmd.value               ,  /* command line                   */
447                 NULL                    ,  /* process attributes             */
448                 NULL                    ,  /* thread attributes              */
449                 TRUE                    ,  /* inherit handles                */
450                 CREATE_NEW_PROCESS_GROUP,  /* create flags                   */
451                 NULL                    ,  /* env vars, null inherits env    */
452                 NULL                    ,  /* current dir, null is our       */
453                                            /* current dir                    */
454                 &si                     ,  /* startup info                   */
455                 &cmdtab[ slot ].pi         /* child process info, if created */
456                 )
457             )
458         {
459             perror( "CreateProcess" );
460             exit( EXITBAD );
461         }
462
463         /* Clean up temporary stuff. */
464         string_free( &cmd );
465     }
466
467     /* Wait until we are under the limit of concurrent commands. Do not trust
468      * globs.jobs alone.
469      */
470     while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) )
471         if ( !exec_wait() )
472             break;
473
474     if ( argv != argv_static )
475         free_argv( argv );
476 }
477
478
479 /*
480  * exec_wait()
481  *  * wait and drive at most one execution completion.
482  *  * waits for one command to complete, while processing the i/o for all
483  *    ongoing commands.
484  *
485  *   Returns 0 if called when there were no more commands being executed or 1
486  * otherwise.
487  */
488
489 int exec_wait()
490 {
491     int i = -1;
492
493     /* Handle naive make1() which does not know if cmds are running. */
494     if ( !cmdsrunning )
495         return 0;
496
497     /* Wait for a command to complete, while snarfing up any output. */
498     do
499     {
500         /* Check for a complete command, briefly. */
501         i = try_wait(500);
502         /* Read in the output of all running commands. */
503         read_output();
504         /* Close out pending debug style dialogs. */
505         close_alerts();
506         /* Check if a command ran out of time. */
507         if ( i < 0 ) i = try_kill_one();
508     }
509     while ( i < 0 );
510
511     /* We have a command... process it. */
512     --cmdsrunning;
513     {
514         timing_info time;
515         int rstat;
516
517         /* The time data for the command. */
518         record_times( cmdtab[ i ].pi.hProcess, &time );
519
520         /* Clear the temp file. */
521         if ( cmdtab[ i ].tempfile_bat )
522         {
523             unlink( cmdtab[ i ].tempfile_bat );
524             BJAM_FREE( cmdtab[ i ].tempfile_bat );
525             cmdtab[ i ].tempfile_bat = NULL;
526         }
527
528         /* Find out the process exit code. */
529         GetExitCodeProcess( cmdtab[ i ].pi.hProcess, &cmdtab[ i ].exit_code );
530
531         /* The dispossition of the command. */
532         if ( intr )
533             rstat = EXEC_CMD_INTR;
534         else if ( cmdtab[ i ].exit_code != 0 )
535             rstat = EXEC_CMD_FAIL;
536         else
537             rstat = EXEC_CMD_OK;
538
539         /* Output the action block. */
540         out_action(
541             cmdtab[ i ].action.size     > 0 ? cmdtab[ i ].action.value     : 0,
542             cmdtab[ i ].target.size     > 0 ? cmdtab[ i ].target.value     : 0,
543             cmdtab[ i ].command.size    > 0 ? cmdtab[ i ].command.value    : 0,
544             cmdtab[ i ].buffer_out.size > 0 ? cmdtab[ i ].buffer_out.value : 0,
545             cmdtab[ i ].buffer_err.size > 0 ? cmdtab[ i ].buffer_err.value : 0,
546             cmdtab[ i ].exit_reason );
547
548         /* Call the callback, may call back to jam rule land. Assume -p0 in
549          * effect so only pass buffer containing merged output.
550          */
551         (*cmdtab[ i ].func)(
552             cmdtab[ i ].closure,
553             rstat,
554             &time,
555             cmdtab[ i ].command.value,
556             cmdtab[ i ].buffer_out.value );
557
558         /* Clean up the command data, process, etc. */
559         string_free( &cmdtab[ i ].action  ); string_new( &cmdtab[ i ].action  );
560         string_free( &cmdtab[ i ].target  ); string_new( &cmdtab[ i ].target  );
561         string_free( &cmdtab[ i ].command ); string_new( &cmdtab[ i ].command );
562         if ( cmdtab[ i ].pi.hProcess   ) { CloseHandle( cmdtab[ i ].pi.hProcess   ); cmdtab[ i ].pi.hProcess   = 0; }
563         if ( cmdtab[ i ].pi.hThread    ) { CloseHandle( cmdtab[ i ].pi.hThread    ); cmdtab[ i ].pi.hThread    = 0; }
564         if ( cmdtab[ i ].pipe_out[ 0 ] ) { CloseHandle( cmdtab[ i ].pipe_out[ 0 ] ); cmdtab[ i ].pipe_out[ 0 ] = 0; }
565         if ( cmdtab[ i ].pipe_out[ 1 ] ) { CloseHandle( cmdtab[ i ].pipe_out[ 1 ] ); cmdtab[ i ].pipe_out[ 1 ] = 0; }
566         if ( cmdtab[ i ].pipe_err[ 0 ] ) { CloseHandle( cmdtab[ i ].pipe_err[ 0 ] ); cmdtab[ i ].pipe_err[ 0 ] = 0; }
567         if ( cmdtab[ i ].pipe_err[ 1 ] ) { CloseHandle( cmdtab[ i ].pipe_err[ 1 ] ); cmdtab[ i ].pipe_err[ 1 ] = 0; }
568         string_free( &cmdtab[ i ].buffer_out ); string_new( &cmdtab[ i ].buffer_out );
569         string_free( &cmdtab[ i ].buffer_err ); string_new( &cmdtab[ i ].buffer_err );
570         cmdtab[ i ].exit_code = 0;
571         cmdtab[ i ].exit_reason = EXIT_OK;
572     }
573
574     return 1;
575 }
576
577
578 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
579
580 static void free_argv( char * * args )
581 {
582     BJAM_FREE( args[ 0 ] );
583     BJAM_FREE( args );
584 }
585
586
587 /*
588  * For more details on Windows cmd.exe shell command-line length limitations see
589  * the following MSDN article:
590  *     http://support.microsoft.com/default.aspx?scid=kb;en-us;830473
591  */
592
593 int maxline()
594 {
595     OSVERSIONINFO os_info;
596     os_info.dwOSVersionInfoSize = sizeof( os_info );
597     GetVersionEx( &os_info );
598
599     if ( os_info.dwMajorVersion >= 5 ) return 8191; /* XP >     */
600     if ( os_info.dwMajorVersion == 4 ) return 2047; /* NT 4.x   */
601     return 996;                                     /* NT 3.5.1 */
602 }
603
604
605 /*
606  * Convert a command string into arguments for spawnvp(). The original code,
607  * inherited from ftjam, tried to break up every argument on the command-line,
608  * dealing with quotes, but that is really a waste of time on Win32, at least.
609  * It turns out that all you need to do is get the raw path to the executable in
610  * the first argument to spawnvp(), and you can pass all the rest of the
611  * command-line arguments to spawnvp() in one, un-processed string.
612  *
613  * New strategy: break the string in at most one place.
614  */
615
616 static char * * string_to_args( char const * string )
617 {
618     int            src_len;
619     int            in_quote;
620     char         * line;
621     char   const * src;
622     char         * dst;
623     char *       * argv;
624
625     /* Drop leading and trailing whitespace if any. */
626     while ( isspace( *string ) )
627         ++string;
628
629     src_len = strlen( string );
630     while ( ( src_len > 0 ) && isspace( string[ src_len - 1 ] ) )
631         --src_len;
632
633     /* Copy the input string into a buffer we can modify. */
634     line = (char *)BJAM_MALLOC_ATOMIC( src_len + 1 );
635     if ( !line )
636         return 0;
637
638     /* Allocate the argv array.
639      *   element 0: stores the path to the executable
640      *   element 1: stores the command-line arguments to the executable
641      *   element 2: NULL terminator
642      */
643     argv = (char * *)BJAM_MALLOC( 3 * sizeof( char * ) );
644     if ( !argv )
645     {
646         BJAM_FREE( line );
647         return 0;
648     }
649
650     /* Strip quotes from the first command-line argument and find where it ends.
651      * Quotes are illegal in Win32 pathnames, so we do not need to worry about
652      * preserving escaped quotes here. Spaces can not be escaped in Win32, only
653      * enclosed in quotes, so removing backslash escapes is also a non-issue.
654      */
655     in_quote = 0;
656     for ( src = string, dst = line ; *src; ++src )
657     {
658         if ( *src == '"' )
659             in_quote = !in_quote;
660         else if ( !in_quote && isspace( *src ) )
661             break;
662         else
663             *dst++ = *src;
664     }
665     *dst++ = 0;
666     argv[ 0 ] = line;
667
668     /* Skip whitespace in src. */
669     while ( isspace( *src ) )
670         ++src;
671
672     argv[ 1 ] = dst;
673
674     /* Copy the rest of the arguments verbatim. */
675     src_len -= src - string;
676
677     /* Use strncat() because it appends a trailing nul. */
678     *dst = 0;
679     strncat( dst, src, src_len );
680
681     argv[ 2 ] = 0;
682
683     return argv;
684 }
685
686
687 static void onintr( int disp )
688 {
689     ++intr;
690     printf( "...interrupted\n" );
691 }
692
693
694 /*
695  * can_spawn() - If the command is suitable for execution via spawnvp(), return
696  * a number >= the number of characters it would occupy on the command-line.
697  * Otherwise, return zero.
698  */
699
700 long can_spawn( char * command )
701 {
702     char * p;
703     char inquote = 0;
704
705     /* Move to the first non-whitespace. */
706     command += strspn( command, " \t" );
707
708     p = command;
709
710     /* Look for newlines and unquoted i/o redirection. */
711     do
712     {
713         p += strcspn( p, "'\n\"<>|" );
714
715         switch ( *p )
716         {
717         case '\n':
718             /* Skip over any following spaces. */
719             while ( isspace( *p ) )
720                 ++p;
721             /* Must use a .bat file if there is anything significant following
722              * the newline.
723              */
724             if ( *p )
725                 return 0;
726             break;
727
728         case '"':
729         case '\'':
730             if ( ( p > command ) && ( p[ -1 ] != '\\' ) )
731             {
732                 if ( inquote == *p )
733                     inquote = 0;
734                 else if ( inquote == 0 )
735                     inquote = *p;
736             }
737             ++p;
738             break;
739
740         case '<':
741         case '>':
742         case '|':
743             if ( !inquote )
744                 return 0;
745             ++p;
746             break;
747         }
748     }
749     while ( *p );
750
751     /* Return the number of characters the command will occupy. */
752     return p - command;
753 }
754
755
756 /* 64-bit arithmetic helpers. */
757
758 /* Compute the carry bit from the addition of two 32-bit unsigned numbers. */
759 #define add_carry_bit( a, b ) ( (((a) | (b)) >> 31) & (~((a) + (b)) >> 31) & 0x1 )
760
761 /* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1 and h2l2. */
762 #define add_64_hi( h1, l1, h2, l2 ) ((h1) + (h2) + add_carry_bit(l1, l2))
763
764
765 /*
766  * Add two 64-bit unsigned numbers, h1l1 and h2l2.
767  */
768
769 static FILETIME add_64
770 (
771     unsigned long h1, unsigned long l1,
772     unsigned long h2, unsigned long l2
773 )
774 {
775     FILETIME result;
776     result.dwLowDateTime = l1 + l2;
777     result.dwHighDateTime = add_64_hi( h1, l1, h2, l2 );
778     return result;
779 }
780
781
782 static FILETIME add_FILETIME( FILETIME t1, FILETIME t2 )
783 {
784     return add_64( t1.dwHighDateTime, t1.dwLowDateTime, t2.dwHighDateTime,
785         t2.dwLowDateTime );
786 }
787
788
789 static FILETIME negate_FILETIME( FILETIME t )
790 {
791     /* 2s complement negation */
792     return add_64( ~t.dwHighDateTime, ~t.dwLowDateTime, 0, 1 );
793 }
794
795
796 /*
797  * Convert a FILETIME to a number of seconds.
798  */
799
800 static double filetime_seconds( FILETIME t )
801 {
802     return t.dwHighDateTime * ( (double)( 1UL << 31 ) * 2.0 * 1.0e-7 ) + t.dwLowDateTime * 1.0e-7;
803 }
804
805
806 /*
807  * What should be a simple conversion, turns out to be horribly complicated by
808  * the defficiencies of MSVC and the Win32 API.
809  */
810
811 static time_t filetime_dt( FILETIME t_utc )
812 {
813     static int calc_time_diff = 1;
814     static double time_diff;
815     if ( calc_time_diff )
816     {
817         struct tm t0_;
818         FILETIME f0_local;
819         FILETIME f0_;
820         SYSTEMTIME s0_;
821         GetSystemTime( &s0_ );
822         t0_.tm_year = s0_.wYear-1900;
823         t0_.tm_mon = s0_.wMonth-1;
824         t0_.tm_wday = s0_.wDayOfWeek;
825         t0_.tm_mday = s0_.wDay;
826         t0_.tm_hour = s0_.wHour;
827         t0_.tm_min = s0_.wMinute;
828         t0_.tm_sec = s0_.wSecond;
829         t0_.tm_isdst = 0;
830         SystemTimeToFileTime( &s0_, &f0_local );
831         LocalFileTimeToFileTime( &f0_local, &f0_ );
832         time_diff = filetime_seconds( f0_ ) - (double)mktime( &t0_ );
833         calc_time_diff = 0;
834     }
835     return ceil( filetime_seconds( t_utc ) - time_diff );
836 }
837
838
839 static void record_times( HANDLE process, timing_info * time )
840 {
841     FILETIME creation;
842     FILETIME exit;
843     FILETIME kernel;
844     FILETIME user;
845     if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
846     {
847         time->system = filetime_seconds( kernel   );
848         time->user   = filetime_seconds( user     );
849         time->start  = filetime_dt     ( creation );
850         time->end    = filetime_dt     ( exit     );
851     }
852 }
853
854
855 #define IO_BUFFER_SIZE ( 16 * 1024 )
856
857 static char ioBuffer[ IO_BUFFER_SIZE + 1 ];
858
859
860 static void read_pipe
861 (
862     HANDLE   in,  /* the pipe to read from */
863     string * out
864 )
865 {
866     DWORD bytesInBuffer = 0;
867     DWORD bytesAvailable = 0;
868
869     do
870     {
871         /* check if we have any data to read */
872         if ( !PeekNamedPipe( in, ioBuffer, IO_BUFFER_SIZE, &bytesInBuffer, &bytesAvailable, NULL ) )
873             bytesAvailable = 0;
874
875         /* read in the available data */
876         if ( bytesAvailable > 0 )
877         {
878             /* we only read in the available bytes, to avoid blocking */
879             if ( ReadFile( in, ioBuffer,
880                 bytesAvailable <= IO_BUFFER_SIZE ? bytesAvailable : IO_BUFFER_SIZE,
881                 &bytesInBuffer, NULL ) )
882             {
883                 if ( bytesInBuffer > 0 )
884                 {
885                     /* Clean up some illegal chars. */
886                     int i;
887                     for ( i = 0; i < bytesInBuffer; ++i )
888                     {
889                         if ( ( (unsigned char)ioBuffer[ i ] < 1 ) )
890                             ioBuffer[ i ] = '?';
891                     }
892                     /* Null, terminate. */
893                     ioBuffer[ bytesInBuffer ] = '\0';
894                     /* Append to the output. */
895                     string_append( out, ioBuffer );
896                     /* Subtract what we read in. */
897                     bytesAvailable -= bytesInBuffer;
898                 }
899                 else
900                 {
901                     /* Likely read a error, bail out. */
902                     bytesAvailable = 0;
903                 }
904             }
905             else
906             {
907                 /* Definitely read a error, bail out. */
908                 bytesAvailable = 0;
909             }
910         }
911     }
912     while ( bytesAvailable > 0 );
913 }
914
915
916 static void read_output()
917 {
918     int i;
919     for ( i = 0; i < globs.jobs && i < MAXJOBS; ++i )
920     {
921         /* Read stdout data. */
922         if ( cmdtab[ i ].pipe_out[ 0 ] )
923             read_pipe( cmdtab[ i ].pipe_out[ 0 ], & cmdtab[ i ].buffer_out );
924         /* Read stderr data. */
925         if ( cmdtab[ i ].pipe_err[ 0 ] )
926             read_pipe( cmdtab[ i ].pipe_err[ 0 ], & cmdtab[ i ].buffer_err );
927     }
928 }
929
930
931 /*
932  * Waits for a single child process command to complete, or the timeout,
933  * whichever comes first. Returns the index of the completed command in the
934  * cmdtab array, or -1.
935  */
936
937 static int try_wait( int timeoutMillis )
938 {
939     int i;
940     int num_active;
941     int wait_api_result;
942     HANDLE active_handles[ MAXJOBS ];
943     int active_procs[ MAXJOBS ];
944
945     /* Prepare a list of all active processes to wait for. */
946     for ( num_active = 0, i = 0; i < globs.jobs; ++i )
947     {
948         if ( cmdtab[ i ].pi.hProcess )
949         {
950             active_handles[ num_active ] = cmdtab[ i ].pi.hProcess;
951             active_procs[ num_active ] = i;
952             ++num_active;
953         }
954     }
955
956     /* Wait for a child to complete, or for our timeout window to expire. */
957     wait_api_result = WaitForMultipleObjects( num_active, active_handles,
958         FALSE, timeoutMillis );
959     if ( ( WAIT_OBJECT_0 <= wait_api_result ) &&
960         ( wait_api_result < WAIT_OBJECT_0 + num_active ) )
961     {
962         /* Rerminated process detected - return its index. */
963         return active_procs[ wait_api_result - WAIT_OBJECT_0 ];
964     }
965
966     /* Timeout. */
967     return -1;
968 }
969
970
971 static int try_kill_one()
972 {
973     /* Only need to check if a timeout was specified with the -l option. */
974     if ( globs.timeout > 0 )
975     {
976         int i;
977         for ( i = 0; i < globs.jobs; ++i )
978         {
979             double t = running_time( cmdtab[ i ].pi.hProcess );
980             if ( t > (double)globs.timeout )
981             {
982                 /* The job may have left an alert dialog around, try and get rid
983                  * of it before killing
984                  */
985                 close_alert( cmdtab[ i ].pi.hProcess );
986                 /* We have a "runaway" job, kill it. */
987                 kill_process_tree( 0, cmdtab[ i ].pi.hProcess );
988                 /* And return it marked as a timeout. */
989                 cmdtab[ i ].exit_reason = EXIT_TIMEOUT;
990                 return i;
991             }
992         }
993     }
994     return -1;
995 }
996
997
998 static void close_alerts()
999 {
1000     /* We only attempt this every 5 seconds, or so, because it is not a cheap
1001      * operation, and we will catch the alerts eventually. This check uses
1002      * floats as some compilers define CLOCKS_PER_SEC as a float or double.
1003      */
1004     if ( ( (float)clock() / (float)( CLOCKS_PER_SEC * 5 ) ) < ( 1.0 / 5.0 ) )
1005     {
1006         int i;
1007         for ( i = 0; i < globs.jobs; ++i )
1008             close_alert( cmdtab[ i ].pi.hProcess );
1009     }
1010 }
1011
1012
1013 /*
1014  * Calc the current running time of an *active* process.
1015  */
1016
1017 static double running_time( HANDLE process )
1018 {
1019     FILETIME creation;
1020     FILETIME exit;
1021     FILETIME kernel;
1022     FILETIME user;
1023     FILETIME current;
1024     if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
1025     {
1026         /* Compute the elapsed time. */
1027         GetSystemTimeAsFileTime( &current );
1028         return filetime_seconds( add_FILETIME( current,
1029             negate_FILETIME( creation ) ) );
1030     }
1031     return 0.0;
1032 }
1033
1034
1035 /* It is just stupidly silly that one has to do this. */
1036 typedef struct PROCESS_BASIC_INFORMATION__
1037 {
1038     LONG  ExitStatus;
1039     PVOID PebBaseAddress;
1040     ULONG AffinityMask;
1041     LONG  BasePriority;
1042     ULONG UniqueProcessId;
1043     ULONG InheritedFromUniqueProcessId;
1044 } PROCESS_BASIC_INFORMATION_;
1045 typedef LONG (__stdcall * NtQueryInformationProcess__)(
1046     HANDLE ProcessHandle,
1047     LONG ProcessInformationClass,
1048     PVOID ProcessInformation,
1049     ULONG ProcessInformationLength,
1050     PULONG ReturnLength);
1051 static NtQueryInformationProcess__ NtQueryInformationProcess_ = NULL;
1052 static HMODULE NTDLL_ = NULL;
1053 DWORD get_process_id( HANDLE process )
1054 {
1055     PROCESS_BASIC_INFORMATION_ pinfo;
1056     if ( !NtQueryInformationProcess_ )
1057     {
1058         if ( ! NTDLL_ )
1059             NTDLL_ = GetModuleHandleA( "ntdll" );
1060         if ( NTDLL_ )
1061             NtQueryInformationProcess_
1062                 = (NtQueryInformationProcess__)GetProcAddress( NTDLL_, "NtQueryInformationProcess" );
1063     }
1064     if ( NtQueryInformationProcess_ )
1065     {
1066         LONG r = (*NtQueryInformationProcess_)( process,
1067             /* ProcessBasicInformation == */ 0, &pinfo,
1068             sizeof( PROCESS_BASIC_INFORMATION_ ), NULL );
1069         return pinfo.UniqueProcessId;
1070     }
1071     return 0;
1072 }
1073
1074
1075 /*
1076  * Not really optimal, or efficient, but it is easier this way, and it is not
1077  * like we are going to be killing thousands, or even tens of processes.
1078  */
1079
1080 static void kill_process_tree( DWORD pid, HANDLE process )
1081 {
1082     HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
1083     if ( !pid )
1084         pid = get_process_id( process );
1085     process_snapshot_h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
1086
1087     if ( INVALID_HANDLE_VALUE != process_snapshot_h )
1088     {
1089         BOOL ok = TRUE;
1090         PROCESSENTRY32 pinfo;
1091         pinfo.dwSize = sizeof( PROCESSENTRY32 );
1092         for (
1093             ok = Process32First( process_snapshot_h, &pinfo );
1094             ok == TRUE;
1095             ok = Process32Next( process_snapshot_h, &pinfo ) )
1096         {
1097             if ( pinfo.th32ParentProcessID == pid )
1098             {
1099                 /* Found a child, recurse to kill it and anything else below it.
1100                  */
1101                 HANDLE ph = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
1102                     pinfo.th32ProcessID );
1103                 if ( NULL != ph )
1104                 {
1105                     kill_process_tree( pinfo.th32ProcessID, ph );
1106                     CloseHandle( ph );
1107                 }
1108             }
1109         }
1110         CloseHandle( process_snapshot_h );
1111     }
1112     /* Now that the children are all dead, kill the root. */
1113     TerminateProcess( process, -2 );
1114 }
1115
1116
1117 static double creation_time( HANDLE process )
1118 {
1119     FILETIME creation;
1120     FILETIME exit;
1121     FILETIME kernel;
1122     FILETIME user;
1123     FILETIME current;
1124     return GetProcessTimes( process, &creation, &exit, &kernel, &user )
1125         ? filetime_seconds( creation )
1126         : 0.0;
1127 }
1128
1129
1130 /*
1131  * Recursive check if first process is parent (directly or indirectly) of the
1132  * second one. Both processes are passed as process ids, not handles. Special
1133  * return value 2 means that the second process is smss.exe and its parent
1134  * process is System (first argument is ignored).
1135  */
1136
1137 static int is_parent_child( DWORD parent, DWORD child )
1138 {
1139     HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
1140
1141     if ( !child )
1142         return 0;
1143     if ( parent == child )
1144         return 1;
1145
1146     process_snapshot_h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
1147     if ( INVALID_HANDLE_VALUE != process_snapshot_h )
1148     {
1149         BOOL ok = TRUE;
1150         PROCESSENTRY32 pinfo;
1151         pinfo.dwSize = sizeof( PROCESSENTRY32 );
1152         for (
1153             ok = Process32First( process_snapshot_h, &pinfo );
1154             ok == TRUE;
1155             ok = Process32Next( process_snapshot_h, &pinfo ) )
1156         {
1157             if ( pinfo.th32ProcessID == child )
1158             {
1159                 /* Unfortunately, process ids are not really unique. There might
1160                  * be spurious "parent and child" relationship match between two
1161                  * non-related processes if real parent process of a given
1162                  * process has exited (while child process kept running as an
1163                  * "orphan") and the process id of such parent process has been
1164                  * reused by internals of the operating system when creating
1165                  * another process.
1166                  *
1167                  * Thus additional check is needed - process creation time. This
1168                  * check may fail (i.e. return 0) for system processes due to
1169                  * insufficient privileges, and that is OK.
1170                  */
1171                 double tchild = 0.0;
1172                 double tparent = 0.0;
1173                 HANDLE hchild = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pinfo.th32ProcessID );
1174                 CloseHandle( process_snapshot_h );
1175
1176                 /* csrss.exe may display message box like following:
1177                  *   xyz.exe - Unable To Locate Component
1178                  *   This application has failed to start because
1179                  *   boost_foo-bar.dll was not found. Re-installing the
1180                  *   application may fix the problem
1181                  * This actually happens when starting test process that depends
1182                  * on a dynamic library which failed to build. We want to
1183                  * automatically close these message boxes even though csrss.exe
1184                  * is not our child process. We may depend on the fact that (in
1185                  * all current versions of Windows) csrss.exe is directly child
1186                  * of the smss.exe process, which in turn is directly child of
1187                  * the System process, which always has process id == 4. This
1188                  * check must be performed before comparison of process creation
1189                  * times.
1190                  */
1191                 if ( !stricmp( pinfo.szExeFile, "csrss.exe" ) &&
1192                     ( is_parent_child( parent, pinfo.th32ParentProcessID ) == 2 ) )
1193                     return 1;
1194                 if ( !stricmp( pinfo.szExeFile, "smss.exe" ) &&
1195                     ( pinfo.th32ParentProcessID == 4 ) )
1196                     return 2;
1197
1198                 if ( hchild )
1199                 {
1200                     HANDLE hparent = OpenProcess( PROCESS_QUERY_INFORMATION,
1201                         FALSE, pinfo.th32ParentProcessID );
1202                     if ( hparent )
1203                     {
1204                         tchild = creation_time( hchild );
1205                         tparent = creation_time( hparent );
1206                         CloseHandle( hparent );
1207                     }
1208                     CloseHandle( hchild );
1209                 }
1210
1211                 /* Return 0 if one of the following is true:
1212                  *  1. we failed to read process creation time
1213                  *  2. child was created before alleged parent
1214                  */
1215                 if ( ( tchild == 0.0 ) || ( tparent == 0.0 ) ||
1216                     ( tchild < tparent ) )
1217                     return 0;
1218
1219                 return is_parent_child( parent, pinfo.th32ParentProcessID ) & 1;
1220             }
1221         }
1222
1223         CloseHandle( process_snapshot_h );
1224     }
1225
1226     return 0;
1227 }
1228
1229 typedef struct PROCESS_HANDLE_ID { HANDLE h; DWORD pid; } PROCESS_HANDLE_ID;
1230
1231
1232 /*
1233  * This function is called by the operating system for each topmost window.
1234  */
1235
1236 BOOL CALLBACK close_alert_window_enum( HWND hwnd, LPARAM lParam )
1237 {
1238     char buf[ 7 ] = { 0 };
1239     PROCESS_HANDLE_ID p = *( (PROCESS_HANDLE_ID *)lParam );
1240     DWORD pid = 0;
1241     DWORD tid = 0;
1242
1243     /* We want to find and close any window that:
1244      *  1. is visible and
1245      *  2. is a dialog and
1246      *  3. is displayed by any of our child processes
1247      */
1248     if ( !IsWindowVisible( hwnd ) )
1249         return TRUE;
1250
1251     if ( !GetClassNameA( hwnd, buf, sizeof( buf ) ) )
1252         return TRUE;  /* Failed to read class name; presume it is not a dialog. */
1253
1254     if ( strcmp( buf, "#32770" ) )
1255         return TRUE;  /* Not a dialog */
1256
1257     /* GetWindowThreadProcessId() returns 0 on error, otherwise thread id of
1258      * window message pump thread.
1259      */
1260     tid = GetWindowThreadProcessId( hwnd, &pid );
1261
1262     if ( tid && is_parent_child( p.pid, pid ) )
1263     {
1264         /* Ask really nice. */
1265         PostMessageA( hwnd, WM_CLOSE, 0, 0 );
1266         /* Now wait and see if it worked. If not, insist. */
1267         if ( WaitForSingleObject( p.h, 200 ) == WAIT_TIMEOUT )
1268         {
1269             PostThreadMessageA( tid, WM_QUIT, 0, 0 );
1270             WaitForSingleObject( p.h, 300 );
1271         }
1272
1273         /* Done, we do not want to check any other window now. */
1274         return FALSE;
1275     }
1276
1277     return TRUE;
1278 }
1279
1280
1281 static void close_alert( HANDLE process )
1282 {
1283     DWORD pid = get_process_id( process );
1284     /* If process already exited or we just can not get its process id, do not
1285      * go any further.
1286      */
1287     if ( pid )
1288     {
1289         PROCESS_HANDLE_ID p;
1290         p.h = process;
1291         p.pid = pid;
1292         EnumWindows( &close_alert_window_enum, (LPARAM)&p );
1293     }
1294 }
1295
1296 #endif /* USE_EXECNT */