2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
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 copy at
12 * http://www.boost.org/LICENSE_1_0.txt)
16 * execnt.c - execute a shell command on Windows NT
18 * If $(JAMSHELL) is defined, uses that to formulate the actual command. The
19 * default is: cmd.exe /Q/C
21 * In $(JAMSHELL), % expands to the command string and ! expands to the slot
22 * number (starting at 1) for multiprocess (-j) invocations. If $(JAMSHELL) does
23 * not include a %, it is tacked on as the last argument.
25 * Each $(JAMSHELL) placeholder must be specified as a separate individual
26 * element in a jam variable value.
28 * Do not just set JAMSHELL to cmd.exe - it will not work!
31 * exec_check() - preprocess and validate the command
32 * exec_cmd() - launch an async command execution
33 * exec_wait() - wait for any of the async command processes to terminate
36 * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
54 #define WIN32_LEAN_AND_MEAN
58 #include <versionhelpers.h>
61 /* get the maximum shell command line length according to the OS */
63 /* valid raw command string length */
64 static long raw_command_length( char const * command
);
65 /* add two 64-bit unsigned numbers, h1l1 and h2l2 */
66 static FILETIME
add_64(
67 unsigned long h1
, unsigned long l1
,
68 unsigned long h2
, unsigned long l2
);
70 static FILETIME
add_FILETIME( FILETIME t1
, FILETIME t2
);
72 static FILETIME
negate_FILETIME( FILETIME t
);
73 /* record the timing info for the process */
74 static void record_times( HANDLE
const, timing_info
* const );
75 /* calc the current running time of an *active* process */
76 static double running_time( HANDLE
const );
77 /* terminate the given process, after terminating all its children first */
78 static void kill_process_tree( DWORD
const procesdId
, HANDLE
const );
79 /* waits for a command to complete or time out */
80 static int try_wait( int const timeoutMillis
);
81 /* reads any pending output for running commands */
82 static void read_output();
83 /* checks if a command ran out of time, and kills it */
84 static int try_kill_one();
85 /* is the first process a parent (direct or indirect) to the second one */
86 static int is_parent_child( DWORD
const parent
, DWORD
const child
);
88 static void close_alert( PROCESS_INFORMATION
const * const );
89 /* close any alerts hanging around */
90 static void close_alerts();
91 /* prepare a command file to be executed using an external shell */
92 static char const * prepare_command_file( string
const * command
, int slot
);
93 /* invoke the actual external process using the given command line */
94 static void invoke_cmd( char const * const command
, int const slot
);
95 /* find a free slot in the running commands table */
96 static int get_free_cmdtab_slot();
97 /* put together the final command string we are to run */
98 static void string_new_from_argv( string
* result
, char const * const * argv
);
99 /* frees and renews the given string */
100 static void string_renew( string
* const );
101 /* reports the last failed Windows API related error message */
102 static void reportWindowsError( char const * const apiName
, int slot
);
103 /* closes a Windows HANDLE and resets its variable to 0. */
104 static void closeWinHandle( HANDLE
* const handle
);
105 /* Adds the job index to the list of currently active jobs. */
106 static void register_wait( int job_id
);
108 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
110 /* CreateProcessA() Windows API places a limit of 32768 characters (bytes) on
111 * the allowed command-line length, including a trailing Unicode (2-byte)
112 * nul-terminator character.
114 #define MAX_RAW_COMMAND_LENGTH 32766
116 /* Communication buffers size */
117 #define IO_BUFFER_SIZE ( 64 * 1024 )
119 /* We hold handles for pipes used to communicate with child processes in two
120 * element arrays indexed as follows.
122 #define EXECCMD_PIPE_READ 0
123 #define EXECCMD_PIPE_WRITE 1
125 static int intr_installed
;
128 /* The list of commands we run. */
129 static struct _cmdtab_t
131 /* Temporary command file used to execute the action when needed. */
132 string command_file
[ 1 ];
134 /* Pipes for communicating with the child process. Parent reads from (0),
135 * child writes to (1).
137 HANDLE pipe_out
[ 2 ];
138 HANDLE pipe_err
[ 2 ];
140 string buffer_out
[ 1 ]; /* buffer to hold stdout, if any */
141 string buffer_err
[ 1 ]; /* buffer to hold stderr, if any */
143 PROCESS_INFORMATION pi
; /* running process information */
149 /* Function called when the command completes. */
150 ExecCmdCallback func
;
152 /* Opaque data passed back to the 'func' callback. */
155 static int cmdtab_size
= 0;
157 /* A thread-safe single element queue. Used by the worker threads
158 * to signal the main thread that a process is completed.
168 * Execution unit tests.
171 void execnt_unit_test()
173 #if !defined( NDEBUG )
174 /* vc6 preprocessor is broken, so assert with these strings gets confused.
175 * Use a table instead.
178 typedef struct test
{ const char * command
; int result
; } test
;
188 { " \n\t\t\v\r\r\n \t x \v \t\t\r\n\n\n \n\n\v\t", 8 },
191 { "echo x > foo.bar", -1 },
192 { "echo x < foo.bar", -1 },
193 { "echo x | foo.bar", -1 },
194 { "echo x \">\" foo.bar", 18 },
195 { "echo x '<' foo.bar", 18 },
196 { "echo x \"|\" foo.bar", 18 },
197 { "echo x \\\">\\\" foo.bar", -1 },
198 { "echo x \\\"<\\\" foo.bar", -1 },
199 { "echo x \\\"|\\\" foo.bar", -1 },
200 { "\"echo x > foo.bar\"", 18 },
201 { "echo x \"'\"<' foo.bar", -1 },
202 { "echo x \\\\\"<\\\\\" foo.bar", 22 },
203 { "echo x \\x\\\"<\\\\\" foo.bar", -1 },
206 for ( t
= tests
; t
->command
; ++t
)
207 assert( raw_command_length( t
->command
) == t
->result
);
211 int const length
= maxline() + 9;
212 char * const cmd
= (char *)BJAM_MALLOC_ATOMIC( length
+ 1 );
213 memset( cmd
, 'x', length
);
215 assert( raw_command_length( cmd
) == length
);
222 * exec_init() - global initialization
224 void exec_init( void )
226 if ( globs
.jobs
> cmdtab_size
)
228 cmdtab
= (_cmdtab_t
*)BJAM_REALLOC( cmdtab
, globs
.jobs
* sizeof( *cmdtab
) );
229 memset( cmdtab
+ cmdtab_size
, 0, ( globs
.jobs
- cmdtab_size
) * sizeof( *cmdtab
) );
230 cmdtab_size
= globs
.jobs
;
232 if ( globs
.jobs
> MAXIMUM_WAIT_OBJECTS
&& !process_queue
.read_okay
)
234 process_queue
.read_okay
= CreateEvent( NULL
, FALSE
, FALSE
, NULL
);
235 process_queue
.write_okay
= CreateEvent( NULL
, FALSE
, TRUE
, NULL
);
240 * exec_done - free resources.
242 void exec_done( void )
244 if ( process_queue
.read_okay
)
246 CloseHandle( process_queue
.read_okay
);
248 if ( process_queue
.write_okay
)
250 CloseHandle( process_queue
.write_okay
);
256 * exec_check() - preprocess and validate the command
261 string
const * command
,
264 int * error_max_length
267 /* Default shell does nothing when triggered with an empty or a
268 * whitespace-only command so we simply skip running it in that case. We
269 * still pass them on to non-default shells as we do not really know what
270 * they are going to do with such commands.
272 if ( list_empty( *pShell
) )
274 char const * s
= command
->value
;
275 while ( isspace( *s
) ) ++s
;
277 return EXEC_CHECK_NOOP
;
280 /* Check prerequisites for executing raw commands. */
281 if ( is_raw_command_request( *pShell
) )
283 long const raw_cmd_length
= raw_command_length( command
->value
);
284 if ( raw_cmd_length
< 0 )
286 /* Invalid characters detected - fallback to default shell. */
287 list_free( *pShell
);
290 else if ( raw_cmd_length
> MAX_RAW_COMMAND_LENGTH
)
292 *error_length
= raw_cmd_length
;
293 *error_max_length
= MAX_RAW_COMMAND_LENGTH
;
294 return EXEC_CHECK_TOO_LONG
;
297 return raw_cmd_length
? EXEC_CHECK_OK
: EXEC_CHECK_NOOP
;
300 /* Now we know we are using an external shell. Note that there is no need to
301 * check for too long command strings when using an external shell since we
302 * use a command file and assume no one is going to set up a JAMSHELL format
303 * string longer than a few hundred bytes at most which should be well under
304 * the total command string limit. Should someone actually construct such a
305 * JAMSHELL value it will get reported as an 'invalid parameter'
306 * CreateProcessA() Windows API failure which seems like a good enough
307 * result for such intentional mischief.
310 /* Check for too long command lines. */
311 return check_cmd_for_too_long_lines( command
->value
, maxline(),
312 error_length
, error_max_length
);
317 * exec_cmd() - launch an async command execution
319 * We assume exec_check() already verified that the given command can have its
320 * command string constructed as requested.
325 string
const * cmd_orig
,
327 ExecCmdCallback func
,
332 int const slot
= get_free_cmdtab_slot();
333 int const is_raw_cmd
= is_raw_command_request( shell
);
334 string cmd_local
[ 1 ];
336 /* Initialize default shell - anything more than /Q/C is non-portable. */
337 static LIST
* default_shell
;
338 if ( !default_shell
)
339 default_shell
= list_new( object_new( "cmd.exe /Q/C" ) );
341 /* Specifying no shell means requesting the default shell. */
342 if ( list_empty( shell
) )
343 shell
= default_shell
;
348 out_printf( "Executing raw command directly\n" );
351 out_printf( "Executing using a command file and the shell: " );
357 /* If we are running a raw command directly - trim its leading whitespaces
358 * as well as any trailing all-whitespace lines but keep any trailing
359 * whitespace in the final/only line containing something other than
364 char const * start
= cmd_orig
->value
;
365 char const * p
= cmd_orig
->value
+ cmd_orig
->size
;
366 char const * end
= p
;
367 while ( isspace( *start
) ) ++start
;
368 while ( p
> start
&& isspace( p
[ -1 ] ) )
371 string_new( cmd_local
);
372 string_append_range( cmd_local
, start
, end
);
373 assert( long(cmd_local
->size
) == raw_command_length( cmd_orig
->value
) );
375 /* If we are not running a raw command directly, prepare a command file to
376 * be executed using an external shell and the actual command string using
381 char const * const cmd_file
= prepare_command_file( cmd_orig
, slot
);
382 char const * argv
[ MAXARGC
+ 1 ]; /* +1 for NULL */
383 argv_from_shell( argv
, shell
, cmd_file
, slot
);
384 string_new_from_argv( cmd_local
, argv
);
387 /* Catch interrupts whenever commands are running. */
388 if ( !intr_installed
)
391 signal( SIGINT
, onintr
);
394 cmdtab
[ slot
].flags
= flags
;
396 /* Save input data into the selected running commands table slot. */
397 cmdtab
[ slot
].func
= func
;
398 cmdtab
[ slot
].closure
= closure
;
400 /* Invoke the actual external process using the constructed command line. */
401 invoke_cmd( cmd_local
->value
, slot
);
403 /* Free our local command string copy. */
404 string_free( cmd_local
);
409 * exec_wait() - wait for any of the async command processes to terminate
411 * Wait and drive at most one execution completion, while processing the I/O for
412 * all ongoing commands.
418 int exit_reason
; /* reason why a command completed */
420 /* Wait for a command to complete, while snarfing up any output. */
423 /* Check for a complete command, briefly. */
425 /* Read in the output of all running commands. */
427 /* Close out pending debug style dialogs. */
429 /* Process the completed command we found. */
430 if ( i
>= 0 ) { exit_reason
= EXIT_OK
; break; }
431 /* Check if a command ran out of time. */
433 if ( i
>= 0 ) { exit_reason
= EXIT_TIMEOUT
; break; }
436 /* We have a command... process it. */
442 /* The time data for the command. */
443 record_times( cmdtab
[ i
].pi
.hProcess
, &time
);
445 /* Removed the used temporary command file. */
446 if ( cmdtab
[ i
].command_file
->size
)
447 unlink( cmdtab
[ i
].command_file
->value
);
449 /* Find out the process exit code. */
450 GetExitCodeProcess( cmdtab
[ i
].pi
.hProcess
, &exit_code
);
452 /* The dispossition of the command. */
454 rstat
= EXEC_CMD_INTR
;
455 else if ( exit_code
)
456 rstat
= EXEC_CMD_FAIL
;
460 /* Call the callback, may call back to jam rule land. */
461 (*cmdtab
[ i
].func
)( cmdtab
[ i
].closure
, rstat
, &time
,
462 cmdtab
[ i
].buffer_out
->value
, cmdtab
[ i
].buffer_err
->value
,
465 /* Clean up our child process tracking data. No need to clear the
466 * temporary command file name as it gets reused.
468 closeWinHandle( &cmdtab
[ i
].pi
.hProcess
);
469 closeWinHandle( &cmdtab
[ i
].pi
.hThread
);
470 closeWinHandle( &cmdtab
[ i
].pipe_out
[ EXECCMD_PIPE_READ
] );
471 closeWinHandle( &cmdtab
[ i
].pipe_out
[ EXECCMD_PIPE_WRITE
] );
472 closeWinHandle( &cmdtab
[ i
].pipe_err
[ EXECCMD_PIPE_READ
] );
473 closeWinHandle( &cmdtab
[ i
].pipe_err
[ EXECCMD_PIPE_WRITE
] );
474 string_renew( cmdtab
[ i
].buffer_out
);
475 string_renew( cmdtab
[ i
].buffer_err
);
480 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
483 * Invoke the actual external process using the given command line. Track the
484 * process in our running commands table.
487 static void invoke_cmd( char const * const command
, int const slot
)
489 SECURITY_ATTRIBUTES sa
= { sizeof( SECURITY_ATTRIBUTES
), 0, 0 };
490 SECURITY_DESCRIPTOR sd
;
491 STARTUPINFOA si
= { sizeof( STARTUPINFOA
), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
494 /* Init the security data. */
495 InitializeSecurityDescriptor( &sd
, SECURITY_DESCRIPTOR_REVISION
);
496 SetSecurityDescriptorDacl( &sd
, TRUE
, NULL
, FALSE
);
497 sa
.lpSecurityDescriptor
= &sd
;
498 sa
.bInheritHandle
= TRUE
;
500 /* Create output buffers. */
501 string_new( cmdtab
[ slot
].buffer_out
);
502 string_new( cmdtab
[ slot
].buffer_err
);
504 /* Create pipes for communicating with the child process. */
505 if ( !CreatePipe( &cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_READ
],
506 &cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_WRITE
], &sa
, IO_BUFFER_SIZE
) )
508 reportWindowsError( "CreatePipe", slot
);
511 if ( globs
.pipe_action
&& !CreatePipe( &cmdtab
[ slot
].pipe_err
[
512 EXECCMD_PIPE_READ
], &cmdtab
[ slot
].pipe_err
[ EXECCMD_PIPE_WRITE
],
513 &sa
, IO_BUFFER_SIZE
) )
515 reportWindowsError( "CreatePipe", slot
);
519 /* Set handle inheritance off for the pipe ends the parent reads from. */
520 SetHandleInformation( cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_READ
],
521 HANDLE_FLAG_INHERIT
, 0 );
522 if ( globs
.pipe_action
)
523 SetHandleInformation( cmdtab
[ slot
].pipe_err
[ EXECCMD_PIPE_READ
],
524 HANDLE_FLAG_INHERIT
, 0 );
526 /* Hide the child window, if any. */
527 si
.dwFlags
|= STARTF_USESHOWWINDOW
;
528 si
.wShowWindow
= SW_HIDE
;
530 /* Redirect the child's output streams to our pipes. */
531 si
.dwFlags
|= STARTF_USESTDHANDLES
;
532 si
.hStdOutput
= cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_WRITE
];
533 si
.hStdError
= globs
.pipe_action
534 ? cmdtab
[ slot
].pipe_err
[ EXECCMD_PIPE_WRITE
]
535 : cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_WRITE
];
537 /* Let the child inherit stdin, as some commands assume it is available. */
538 si
.hStdInput
= GetStdHandle( STD_INPUT_HANDLE
);
541 out_printf( "Command string for CreateProcessA(): '%s'\n", command
);
543 /* Run the command by creating a sub-process for it. */
544 if ( !CreateProcessA(
545 NULL
, /* application name */
546 (char *)command
, /* command line */
547 NULL
, /* process attributes */
548 NULL
, /* thread attributes */
549 TRUE
, /* inherit handles */
550 CREATE_NEW_PROCESS_GROUP
, /* create flags */
551 NULL
, /* env vars, null inherits env */
552 NULL
, /* current dir, null is our current dir */
553 &si
, /* startup info */
554 &cmdtab
[ slot
].pi
) ) /* child process info, if created */
556 reportWindowsError( "CreateProcessA", slot
);
560 register_wait( slot
);
565 * For more details on Windows cmd.exe shell command-line length limitations see
566 * the following MSDN article:
567 * http://support.microsoft.com/default.aspx?scid=kb;en-us;830473
570 static int raw_maxline()
572 if ( IsWindowsVersionOrGreater(5,0,0) ) return 8191; /* XP */
573 if ( IsWindowsVersionOrGreater(4,0,0) ) return 2047; /* NT 4.x */
574 return 996; /* NT 3.5.1 */
580 if ( !result
) result
= raw_maxline();
586 * Closes a Windows HANDLE and resets its variable to 0.
589 static void closeWinHandle( HANDLE
* const handle
)
593 CloseHandle( *handle
);
600 * Frees and renews the given string.
603 static void string_renew( string
* const s
)
611 * raw_command_length() - valid raw command string length
613 * Checks whether the given command may be executed as a raw command. If yes,
614 * returns the corresponding command string length. If not, returns -1.
616 * Rules for constructing raw command strings:
617 * - Command may not contain unquoted shell I/O redirection characters.
618 * - May have at most one command line with non-whitespace content.
619 * - Leading whitespace trimmed.
620 * - Trailing all-whitespace lines trimmed.
621 * - Trailing whitespace on the sole command line kept (may theoretically
622 * affect the executed command).
625 static long raw_command_length( char const * command
)
628 char const * escape
= 0;
630 char const * newline
= 0;
632 /* Skip leading whitespace. */
633 while ( isspace( *command
) )
638 /* Look for newlines and unquoted I/O redirection. */
641 p
+= strcspn( p
, "\n\"'<>|\\" );
645 /* If our command contains non-whitespace content split over
646 * multiple lines we can not execute it directly.
649 while ( isspace( *++p
) );
654 escape
= escape
&& escape
== p
- 1 ? 0 : p
;
660 if ( escape
&& escape
== p
- 1 )
662 else if ( inquote
== *p
)
680 /* Return the number of characters the command will occupy. */
681 return ( newline
? newline
: p
) - command
;
685 /* 64-bit arithmetic helpers. */
687 /* Compute the carry bit from the addition of two 32-bit unsigned numbers. */
688 #define add_carry_bit( a, b ) ((((a) | (b)) >> 31) & (~((a) + (b)) >> 31) & 0x1)
690 /* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1
693 #define add_64_hi( h1, l1, h2, l2 ) ((h1) + (h2) + add_carry_bit(l1, l2))
697 * Add two 64-bit unsigned numbers, h1l1 and h2l2.
700 static FILETIME add_64
702 unsigned long h1
, unsigned long l1
,
703 unsigned long h2
, unsigned long l2
707 result
.dwLowDateTime
= l1
+ l2
;
708 result
.dwHighDateTime
= add_64_hi( h1
, l1
, h2
, l2
);
713 static FILETIME
add_FILETIME( FILETIME t1
, FILETIME t2
)
715 return add_64( t1
.dwHighDateTime
, t1
.dwLowDateTime
, t2
.dwHighDateTime
,
720 static FILETIME
negate_FILETIME( FILETIME t
)
722 /* 2s complement negation */
723 return add_64( ~t
.dwHighDateTime
, ~t
.dwLowDateTime
, 0, 1 );
728 * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
731 static double filetime_to_seconds( FILETIME
const ft
)
733 return ft
.dwHighDateTime
* ( (double)( 1UL << 31 ) * 2.0 * 1.0e-7 ) +
734 ft
.dwLowDateTime
* 1.0e-7;
738 static void record_times( HANDLE
const process
, timing_info
* const time
)
744 if ( GetProcessTimes( process
, &creation
, &exit
, &kernel
, &user
) )
746 time
->system
= filetime_to_seconds( kernel
);
747 time
->user
= filetime_to_seconds( user
);
748 timestamp_from_filetime( &time
->start
, &creation
);
749 timestamp_from_filetime( &time
->end
, &exit
);
754 static char ioBuffer
[ IO_BUFFER_SIZE
+ 1 ];
756 #define FORWARD_PIPE_NONE 0
757 #define FORWARD_PIPE_STDOUT 1
758 #define FORWARD_PIPE_STDERR 2
760 static void read_pipe
762 HANDLE in
, /* the pipe to read from */
767 DWORD bytesInBuffer
= 0;
768 DWORD bytesAvailable
= 0;
773 /* check if we have any data to read */
774 if ( !PeekNamedPipe( in
, NULL
, IO_BUFFER_SIZE
, NULL
,
775 &bytesAvailable
, NULL
) || bytesAvailable
== 0 )
778 /* we only read in the available bytes, to avoid blocking */
779 if ( !ReadFile( in
, ioBuffer
, bytesAvailable
<= IO_BUFFER_SIZE
?
780 bytesAvailable
: IO_BUFFER_SIZE
, &bytesInBuffer
, NULL
) || bytesInBuffer
== 0 )
783 /* Clean up some illegal chars. */
784 for ( i
= 0; i
< bytesInBuffer
; ++i
)
786 if ( ( (unsigned char)ioBuffer
[ i
] < 1 ) )
789 /* Null, terminate. */
790 ioBuffer
[ bytesInBuffer
] = '\0';
791 /* Append to the output. */
792 string_append( out
, ioBuffer
);
793 /* Copy it to our output if appropriate */
794 if ( forwarding_mode
== FORWARD_PIPE_STDOUT
)
795 out_data( ioBuffer
);
796 else if ( forwarding_mode
== FORWARD_PIPE_STDERR
)
797 err_data( ioBuffer
);
801 #define EARLY_OUTPUT( cmd ) \
802 ( ! ( cmd.flags & EXEC_CMD_QUIET ) )
804 #define FORWARD_STDOUT( c ) \
805 ( ( EARLY_OUTPUT( c ) && ( globs.pipe_action != 2 ) ) ? \
806 FORWARD_PIPE_STDOUT : FORWARD_PIPE_NONE )
807 #define FORWARD_STDERR( c ) \
808 ( ( EARLY_OUTPUT( c ) && ( globs.pipe_action & 2 ) ) ? \
809 FORWARD_PIPE_STDERR : FORWARD_PIPE_NONE )
811 static void read_output()
814 for ( i
= 0; i
< globs
.jobs
; ++i
)
815 if ( cmdtab
[ i
].pi
.hProcess
)
817 /* Read stdout data. */
818 if ( cmdtab
[ i
].pipe_out
[ EXECCMD_PIPE_READ
] )
819 read_pipe( cmdtab
[ i
].pipe_out
[ EXECCMD_PIPE_READ
],
820 cmdtab
[ i
].buffer_out
, FORWARD_STDOUT( cmdtab
[ i
] ) );
821 /* Read stderr data. */
822 if ( cmdtab
[ i
].pipe_err
[ EXECCMD_PIPE_READ
] )
823 read_pipe( cmdtab
[ i
].pipe_err
[ EXECCMD_PIPE_READ
],
824 cmdtab
[ i
].buffer_err
, FORWARD_STDERR( cmdtab
[ i
] ) );
828 static void CALLBACK
try_wait_callback( void * data
, BOOLEAN is_timeout
)
830 struct _cmdtab_t
* slot
= ( struct _cmdtab_t
* )data
;
831 WaitForSingleObject( process_queue
.write_okay
, INFINITE
);
832 process_queue
.job_index
= slot
- cmdtab
;
833 assert( !is_timeout
);
834 SetEvent( process_queue
.read_okay
);
835 /* Okay. Non-blocking. */
836 UnregisterWait( slot
->wait_handle
);
839 static int try_wait_impl( DWORD timeout
)
842 int res
= WaitForSingleObject( process_queue
.read_okay
, timeout
);
843 if ( res
!= WAIT_OBJECT_0
)
845 job_index
= process_queue
.job_index
;
846 SetEvent( process_queue
.write_okay
);
850 static void register_wait( int job_id
)
852 if ( globs
.jobs
> MAXIMUM_WAIT_OBJECTS
)
854 RegisterWaitForSingleObject( &cmdtab
[ job_id
].wait_handle
,
855 cmdtab
[ job_id
].pi
.hProcess
,
856 &try_wait_callback
, &cmdtab
[ job_id
], INFINITE
,
857 WT_EXECUTEDEFAULT
| WT_EXECUTEONLYONCE
);
862 * Waits for a single child process command to complete, or the timeout,
863 * whichever comes first. Returns the index of the completed command in the
864 * cmdtab array, or -1.
867 static int try_wait( int const timeoutMillis
)
869 if ( globs
.jobs
<= MAXIMUM_WAIT_OBJECTS
)
872 HANDLE active_handles
[ MAXIMUM_WAIT_OBJECTS
];
873 int job_ids
[ MAXIMUM_WAIT_OBJECTS
];
874 DWORD num_handles
= 0;
875 DWORD wait_api_result
;
876 for ( i
= 0; i
< globs
.jobs
; ++i
)
878 if( cmdtab
[ i
].pi
.hProcess
)
880 job_ids
[ num_handles
] = i
;
881 active_handles
[ num_handles
] = cmdtab
[ i
].pi
.hProcess
;
885 wait_api_result
= WaitForMultipleObjects( num_handles
, active_handles
, FALSE
, timeoutMillis
);
886 if ( WAIT_OBJECT_0
<= wait_api_result
&& wait_api_result
< WAIT_OBJECT_0
+ globs
.jobs
)
888 return job_ids
[ wait_api_result
- WAIT_OBJECT_0
];
897 return try_wait_impl( timeoutMillis
);
903 static int try_kill_one()
905 /* Only need to check if a timeout was specified with the -l option. */
906 if ( globs
.timeout
> 0 )
909 for ( i
= 0; i
< globs
.jobs
; ++i
)
910 if ( cmdtab
[ i
].pi
.hProcess
)
912 double const t
= running_time( cmdtab
[ i
].pi
.hProcess
);
913 if ( t
> (double)globs
.timeout
)
915 /* The job may have left an alert dialog around, try and get
916 * rid of it before killing the job itself.
918 close_alert( &cmdtab
[ i
].pi
);
919 /* We have a "runaway" job, kill it. */
920 kill_process_tree( cmdtab
[ i
].pi
.dwProcessId
,
921 cmdtab
[ i
].pi
.hProcess
);
922 /* And return its running commands table slot. */
931 static void close_alerts()
933 /* We only attempt this every 5 seconds or so, because it is not a cheap
934 * operation, and we will catch the alerts eventually. This check uses
935 * floats as some compilers define CLOCKS_PER_SEC as a float or double.
937 if ( ( (float)clock() / (float)( CLOCKS_PER_SEC
* 5 ) ) < ( 1.0 / 5.0 ) )
940 for ( i
= 0; i
< globs
.jobs
; ++i
)
941 if ( cmdtab
[ i
].pi
.hProcess
)
942 close_alert( &cmdtab
[ i
].pi
);
948 * Calc the current running time of an *active* process.
951 static double running_time( HANDLE
const process
)
957 if ( GetProcessTimes( process
, &creation
, &exit
, &kernel
, &user
) )
959 /* Compute the elapsed time. */
961 GetSystemTimeAsFileTime( ¤t
);
962 return filetime_to_seconds( add_FILETIME( current
,
963 negate_FILETIME( creation
) ) );
970 * Not really optimal, or efficient, but it is easier this way, and it is not
971 * like we are going to be killing thousands, or even tens of processes.
974 static void kill_process_tree( DWORD
const pid
, HANDLE
const process
)
976 HANDLE
const process_snapshot_h
= CreateToolhelp32Snapshot(
977 TH32CS_SNAPPROCESS
, 0 );
978 if ( INVALID_HANDLE_VALUE
!= process_snapshot_h
)
981 PROCESSENTRY32 pinfo
;
982 pinfo
.dwSize
= sizeof( PROCESSENTRY32
);
984 ok
= Process32First( process_snapshot_h
, &pinfo
);
986 ok
= Process32Next( process_snapshot_h
, &pinfo
) )
988 if ( pinfo
.th32ParentProcessID
== pid
)
990 /* Found a child, recurse to kill it and anything else below it.
992 HANDLE
const ph
= OpenProcess( PROCESS_ALL_ACCESS
, FALSE
,
993 pinfo
.th32ProcessID
);
996 kill_process_tree( pinfo
.th32ProcessID
, ph
);
1001 CloseHandle( process_snapshot_h
);
1003 /* Now that the children are all dead, kill the root. */
1004 TerminateProcess( process
, -2 );
1008 static double creation_time( HANDLE
const process
)
1014 return GetProcessTimes( process
, &creation
, &exit
, &kernel
, &user
)
1015 ? filetime_to_seconds( creation
)
1021 * Recursive check if first process is parent (directly or indirectly) of the
1022 * second one. Both processes are passed as process ids, not handles. Special
1023 * return value 2 means that the second process is smss.exe and its parent
1024 * process is System (first argument is ignored).
1027 static int is_parent_child( DWORD
const parent
, DWORD
const child
)
1029 HANDLE process_snapshot_h
= INVALID_HANDLE_VALUE
;
1033 if ( parent
== child
)
1036 process_snapshot_h
= CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS
, 0 );
1037 if ( INVALID_HANDLE_VALUE
!= process_snapshot_h
)
1040 PROCESSENTRY32 pinfo
;
1041 pinfo
.dwSize
= sizeof( PROCESSENTRY32
);
1043 ok
= Process32First( process_snapshot_h
, &pinfo
);
1045 ok
= Process32Next( process_snapshot_h
, &pinfo
) )
1047 if ( pinfo
.th32ProcessID
== child
)
1049 /* Unfortunately, process ids are not really unique. There might
1050 * be spurious "parent and child" relationship match between two
1051 * non-related processes if real parent process of a given
1052 * process has exited (while child process kept running as an
1053 * "orphan") and the process id of such parent process has been
1054 * reused by internals of the operating system when creating
1057 * Thus an additional check is needed - process creation time.
1058 * This check may fail (i.e. return 0) for system processes due
1059 * to insufficient privileges, and that is OK.
1061 double tchild
= 0.0;
1062 double tparent
= 0.0;
1063 HANDLE
const hchild
= OpenProcess( PROCESS_QUERY_INFORMATION
,
1064 FALSE
, pinfo
.th32ProcessID
);
1065 CloseHandle( process_snapshot_h
);
1067 /* csrss.exe may display message box like following:
1068 * xyz.exe - Unable To Locate Component
1069 * This application has failed to start because
1070 * boost_foo-bar.dll was not found. Re-installing the
1071 * application may fix the problem
1072 * This actually happens when starting a test process that
1073 * depends on a dynamic library which failed to build. We want
1074 * to automatically close these message boxes even though
1075 * csrss.exe is not our child process. We may depend on the fact
1076 * that (in all current versions of Windows) csrss.exe is a
1077 * direct child of the smss.exe process, which in turn is a
1078 * direct child of the System process, which always has process
1079 * id == 4. This check must be performed before comparing
1080 * process creation times.
1083 #ifdef UNICODE // no PROCESSENTRY32A
1084 if ( !wcsicmp( pinfo
.szExeFile
, L
"csrss.exe" ) &&
1086 if ( !stricmp( pinfo
.szExeFile
, "csrss.exe" ) &&
1088 is_parent_child( parent
, pinfo
.th32ParentProcessID
) == 2 )
1091 #ifdef UNICODE // no PROCESSENTRY32A
1092 if ( !wcsicmp( pinfo
.szExeFile
, L
"smss.exe" ) &&
1094 if ( !stricmp( pinfo
.szExeFile
, "smss.exe" ) &&
1096 ( pinfo
.th32ParentProcessID
== 4 ) )
1101 HANDLE hparent
= OpenProcess( PROCESS_QUERY_INFORMATION
,
1102 FALSE
, pinfo
.th32ParentProcessID
);
1105 tchild
= creation_time( hchild
);
1106 tparent
= creation_time( hparent
);
1107 CloseHandle( hparent
);
1109 CloseHandle( hchild
);
1112 /* Return 0 if one of the following is true:
1113 * 1. we failed to read process creation time
1114 * 2. child was created before alleged parent
1116 if ( ( tchild
== 0.0 ) || ( tparent
== 0.0 ) ||
1117 ( tchild
< tparent
) )
1120 return is_parent_child( parent
, pinfo
.th32ParentProcessID
) & 1;
1124 CloseHandle( process_snapshot_h
);
1132 * Called by the OS for each topmost window.
1135 BOOL CALLBACK
close_alert_window_enum( HWND hwnd
, LPARAM lParam
)
1137 char buf
[ 7 ] = { 0 };
1138 PROCESS_INFORMATION
const * const pi
= (PROCESS_INFORMATION
*)lParam
;
1142 /* We want to find and close any window that:
1144 * 2. is a dialog and
1145 * 3. is displayed by any of our child processes
1148 /* We assume hidden windows do not require user interaction. */
1149 !IsWindowVisible( hwnd
)
1150 /* Failed to read class name; presume it is not a dialog. */
1151 || !GetClassNameA( hwnd
, buf
, sizeof( buf
) )
1152 /* All Windows system dialogs use the same Window class name. */
1153 || strcmp( buf
, "#32770" ) )
1156 /* GetWindowThreadProcessId() returns 0 on error, otherwise thread id of
1157 * the window's message pump thread.
1159 tid
= GetWindowThreadProcessId( hwnd
, &pid
);
1160 if ( !tid
|| !is_parent_child( pi
->dwProcessId
, pid
) )
1163 /* Ask real nice. */
1164 PostMessageA( hwnd
, WM_CLOSE
, 0, 0 );
1166 /* Wait and see if it worked. If not, insist. */
1167 if ( WaitForSingleObject( pi
->hProcess
, 200 ) == WAIT_TIMEOUT
)
1169 PostThreadMessageA( tid
, WM_QUIT
, 0, 0 );
1170 WaitForSingleObject( pi
->hProcess
, 300 );
1173 /* Done, we do not want to check any other windows now. */
1178 static void close_alert( PROCESS_INFORMATION
const * const pi
)
1180 EnumWindows( &close_alert_window_enum
, (LPARAM
)pi
);
1185 * Open a command file to store the command into for executing using an external
1186 * shell. Returns a pointer to a FILE open for writing or 0 in case such a file
1187 * could not be opened. The file name used is stored back in the corresponding
1188 * running commands table slot.
1190 * Expects the running commands table slot's command_file attribute to contain
1191 * either a zeroed out string object or one prepared previously by this same
1195 static FILE * open_command_file( int const slot
)
1197 string
* const command_file
= cmdtab
[ slot
].command_file
;
1199 /* If the temporary command file name has not already been prepared for this
1200 * slot number, prepare a new one containing a '##' place holder that will
1201 * be changed later and needs to be located at a fixed distance from the
1204 if ( !command_file
->value
)
1206 DWORD
const procID
= GetCurrentProcessId();
1207 string
const * const tmpdir
= path_tmpdir();
1208 string_new( command_file
);
1209 string_reserve( command_file
, tmpdir
->size
+ 64 );
1210 command_file
->size
= sprintf( command_file
->value
,
1211 "%s\\jam%lu-%02d-##.bat", tmpdir
->value
, procID
, slot
);
1214 /* For some reason opening a command file can fail intermittently. But doing
1215 * some retries works. Most likely this is due to a previously existing file
1216 * of the same name that happens to still be opened by an active virus
1217 * scanner. Originally pointed out and fixed by Bronek Kozicki.
1219 * We first try to open several differently named files to avoid having to
1220 * wait idly if not absolutely necessary. Our temporary command file names
1221 * contain a fixed position place holder we use for generating different
1225 char * const index1
= command_file
->value
+ command_file
->size
- 6;
1226 char * const index2
= index1
+ 1;
1227 int waits_remaining
;
1228 assert( command_file
->value
< index1
);
1229 assert( index2
+ 1 < command_file
->value
+ command_file
->size
);
1230 assert( index2
[ 1 ] == '.' );
1231 for ( waits_remaining
= 3; ; --waits_remaining
)
1234 for ( index
= 0; index
!= 20; ++index
)
1237 *index1
= '0' + index
/ 10;
1238 *index2
= '0' + index
% 10;
1239 f
= fopen( command_file
->value
, "w" );
1242 if ( !waits_remaining
) break;
1252 * Prepare a command file to be executed using an external shell.
1255 static char const * prepare_command_file( string
const * command
, int slot
)
1257 FILE * const f
= open_command_file( slot
);
1260 err_printf( "failed to write command file!\n" );
1263 fputs( command
->value
, f
);
1265 return cmdtab
[ slot
].command_file
->value
;
1270 * Find a free slot in the running commands table.
1273 static int get_free_cmdtab_slot()
1276 for ( slot
= 0; slot
< globs
.jobs
; ++slot
)
1277 if ( !cmdtab
[ slot
].pi
.hProcess
)
1279 err_printf( "no slots for child!\n" );
1285 * Put together the final command string we are to run.
1288 static void string_new_from_argv( string
* result
, char const * const * argv
)
1291 assert( argv
[ 0 ] );
1292 string_copy( result
, *(argv
++) );
1295 string_push_back( result
, ' ' );
1296 string_push_back( result
, '"' );
1297 string_append( result
, *(argv
++) );
1298 string_push_back( result
, '"' );
1304 * Reports the last failed Windows API related error message.
1307 static void reportWindowsError( char const * const apiName
, int slot
)
1309 char * errorMessage
;
1313 DWORD
const errorCode
= GetLastError();
1314 DWORD apiResult
= FormatMessageA(
1315 FORMAT_MESSAGE_ALLOCATE_BUFFER
| /* __in DWORD dwFlags */
1316 FORMAT_MESSAGE_FROM_SYSTEM
|
1317 FORMAT_MESSAGE_IGNORE_INSERTS
,
1318 NULL
, /* __in_opt LPCVOID lpSource */
1319 errorCode
, /* __in DWORD dwMessageId */
1320 0, /* __in DWORD dwLanguageId */
1321 (LPSTR
)&errorMessage
, /* __out LPTSTR lpBuffer */
1322 0, /* __in DWORD nSize */
1323 0 ); /* __in_opt va_list * Arguments */
1325 /* Build a message as if the process had written to stderr. */
1326 if ( globs
.pipe_action
)
1327 err_buf
= cmdtab
[ slot
].buffer_err
;
1329 err_buf
= cmdtab
[ slot
].buffer_out
;
1330 string_append( err_buf
, apiName
);
1331 string_append( err_buf
, "() Windows API failed: " );
1332 sprintf( buf
, "%lu", errorCode
);
1333 string_append( err_buf
, buf
);
1336 string_append( err_buf
, ".\n" );
1339 string_append( err_buf
, " - " );
1340 string_append( err_buf
, errorMessage
);
1341 /* Make sure that the buffer is terminated with a newline */
1342 if( err_buf
->value
[ err_buf
->size
- 1 ] != '\n' )
1343 string_push_back( err_buf
, '\n' );
1344 LocalFree( errorMessage
);
1347 /* Since the process didn't actually start, use a blank timing_info. */
1350 timestamp_current( &time
.start
);
1351 timestamp_current( &time
.end
);
1353 /* Invoke the callback with a failure status. */
1354 (*cmdtab
[ slot
].func
)( cmdtab
[ slot
].closure
, EXEC_CMD_FAIL
, &time
,
1355 cmdtab
[ slot
].buffer_out
->value
, cmdtab
[ slot
].buffer_err
->value
,
1358 /* Clean up any handles that were opened. */
1359 closeWinHandle( &cmdtab
[ slot
].pi
.hProcess
);
1360 closeWinHandle( &cmdtab
[ slot
].pi
.hThread
);
1361 closeWinHandle( &cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_READ
] );
1362 closeWinHandle( &cmdtab
[ slot
].pipe_out
[ EXECCMD_PIPE_WRITE
] );
1363 closeWinHandle( &cmdtab
[ slot
].pipe_err
[ EXECCMD_PIPE_READ
] );
1364 closeWinHandle( &cmdtab
[ slot
].pipe_err
[ EXECCMD_PIPE_WRITE
] );
1365 string_renew( cmdtab
[ slot
].buffer_out
);
1366 string_renew( cmdtab
[ slot
].buffer_err
);
1370 #endif /* USE_EXECNT */