]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/execnt.cpp
f8934fd3652b72704f1c0b34035a41b4bc1d0bbc
[ceph.git] / ceph / src / boost / tools / build / src / engine / execnt.cpp
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 copy at
12 * http://www.boost.org/LICENSE_1_0.txt)
13 */
14
15 /*
16 * execnt.c - execute a shell command on Windows NT
17 *
18 * If $(JAMSHELL) is defined, uses that to formulate the actual command. The
19 * default is: cmd.exe /Q/C
20 *
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.
24 *
25 * Each $(JAMSHELL) placeholder must be specified as a separate individual
26 * element in a jam variable value.
27 *
28 * Do not just set JAMSHELL to cmd.exe - it will not work!
29 *
30 * External routines:
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
34 *
35 * Internal routines:
36 * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
37 */
38
39 #include "jam.h"
40 #include "output.h"
41 #ifdef USE_EXECNT
42 #include "execcmd.h"
43
44 #include "lists.h"
45 #include "output.h"
46 #include "pathsys.h"
47 #include "string.h"
48
49 #include <assert.h>
50 #include <ctype.h>
51 #include <errno.h>
52 #include <time.h>
53
54 #define WIN32_LEAN_AND_MEAN
55 #include <windows.h>
56 #include <process.h>
57 #include <tlhelp32.h>
58 #include <versionhelpers.h>
59
60
61 /* get the maximum shell command line length according to the OS */
62 static int maxline();
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 );
69 /* */
70 static FILETIME add_FILETIME( FILETIME t1, FILETIME t2 );
71 /* */
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 );
87 /* */
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 );
107
108 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
109
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.
113 */
114 #define MAX_RAW_COMMAND_LENGTH 32766
115
116 /* Communication buffers size */
117 #define IO_BUFFER_SIZE ( 64 * 1024 )
118
119 /* We hold handles for pipes used to communicate with child processes in two
120 * element arrays indexed as follows.
121 */
122 #define EXECCMD_PIPE_READ 0
123 #define EXECCMD_PIPE_WRITE 1
124
125 static int intr_installed;
126
127
128 /* The list of commands we run. */
129 static struct _cmdtab_t
130 {
131 /* Temporary command file used to execute the action when needed. */
132 string command_file[ 1 ];
133
134 /* Pipes for communicating with the child process. Parent reads from (0),
135 * child writes to (1).
136 */
137 HANDLE pipe_out[ 2 ];
138 HANDLE pipe_err[ 2 ];
139
140 string buffer_out[ 1 ]; /* buffer to hold stdout, if any */
141 string buffer_err[ 1 ]; /* buffer to hold stderr, if any */
142
143 PROCESS_INFORMATION pi; /* running process information */
144
145 HANDLE wait_handle;
146
147 int flags;
148
149 /* Function called when the command completes. */
150 ExecCmdCallback func;
151
152 /* Opaque data passed back to the 'func' callback. */
153 void * closure;
154 } * cmdtab = NULL;
155 static int cmdtab_size = 0;
156
157 /* A thread-safe single element queue. Used by the worker threads
158 * to signal the main thread that a process is completed.
159 */
160 struct
161 {
162 int job_index;
163 HANDLE read_okay;
164 HANDLE write_okay;
165 } process_queue;
166
167 /*
168 * Execution unit tests.
169 */
170
171 void execnt_unit_test()
172 {
173 #if !defined( NDEBUG )
174 /* vc6 preprocessor is broken, so assert with these strings gets confused.
175 * Use a table instead.
176 */
177 {
178 typedef struct test { const char * command; int result; } test;
179 test tests[] = {
180 { "", 0 },
181 { " ", 0 },
182 { "x", 1 },
183 { "\nx", 1 },
184 { "x\n", 1 },
185 { "\nx\n", 1 },
186 { "\nx \n", 2 },
187 { "\nx \n ", 2 },
188 { " \n\t\t\v\r\r\n \t x \v \t\t\r\n\n\n \n\n\v\t", 8 },
189 { "x\ny", -1 },
190 { "x\n\n y", -1 },
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 },
204 { 0 } };
205 test const * t;
206 for ( t = tests; t->command; ++t )
207 assert( raw_command_length( t->command ) == t->result );
208 }
209
210 {
211 int const length = maxline() + 9;
212 char * const cmd = (char *)BJAM_MALLOC_ATOMIC( length + 1 );
213 memset( cmd, 'x', length );
214 cmd[ length ] = 0;
215 assert( raw_command_length( cmd ) == length );
216 BJAM_FREE( cmd );
217 }
218 #endif
219 }
220
221 /*
222 * exec_init() - global initialization
223 */
224 void exec_init( void )
225 {
226 if ( globs.jobs > cmdtab_size )
227 {
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;
231 }
232 if ( globs.jobs > MAXIMUM_WAIT_OBJECTS && !process_queue.read_okay )
233 {
234 process_queue.read_okay = CreateEvent( NULL, FALSE, FALSE, NULL );
235 process_queue.write_okay = CreateEvent( NULL, FALSE, TRUE, NULL );
236 }
237 }
238
239 /*
240 * exec_done - free resources.
241 */
242 void exec_done( void )
243 {
244 if ( process_queue.read_okay )
245 {
246 CloseHandle( process_queue.read_okay );
247 }
248 if ( process_queue.write_okay )
249 {
250 CloseHandle( process_queue.write_okay );
251 }
252 BJAM_FREE( cmdtab );
253 }
254
255 /*
256 * exec_check() - preprocess and validate the command
257 */
258
259 int exec_check
260 (
261 string const * command,
262 LIST * * pShell,
263 int * error_length,
264 int * error_max_length
265 )
266 {
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.
271 */
272 if ( list_empty( *pShell ) )
273 {
274 char const * s = command->value;
275 while ( isspace( *s ) ) ++s;
276 if ( !*s )
277 return EXEC_CHECK_NOOP;
278 }
279
280 /* Check prerequisites for executing raw commands. */
281 if ( is_raw_command_request( *pShell ) )
282 {
283 long const raw_cmd_length = raw_command_length( command->value );
284 if ( raw_cmd_length < 0 )
285 {
286 /* Invalid characters detected - fallback to default shell. */
287 list_free( *pShell );
288 *pShell = L0;
289 }
290 else if ( raw_cmd_length > MAX_RAW_COMMAND_LENGTH )
291 {
292 *error_length = raw_cmd_length;
293 *error_max_length = MAX_RAW_COMMAND_LENGTH;
294 return EXEC_CHECK_TOO_LONG;
295 }
296 else
297 return raw_cmd_length ? EXEC_CHECK_OK : EXEC_CHECK_NOOP;
298 }
299
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.
308 */
309
310 /* Check for too long command lines. */
311 return check_cmd_for_too_long_lines( command->value, maxline(),
312 error_length, error_max_length );
313 }
314
315
316 /*
317 * exec_cmd() - launch an async command execution
318 *
319 * We assume exec_check() already verified that the given command can have its
320 * command string constructed as requested.
321 */
322
323 void exec_cmd
324 (
325 string const * cmd_orig,
326 int flags,
327 ExecCmdCallback func,
328 void * closure,
329 LIST * shell
330 )
331 {
332 int const slot = get_free_cmdtab_slot();
333 int const is_raw_cmd = is_raw_command_request( shell );
334 string cmd_local[ 1 ];
335
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" ) );
340
341 /* Specifying no shell means requesting the default shell. */
342 if ( list_empty( shell ) )
343 shell = default_shell;
344
345 if ( DEBUG_EXECCMD )
346 {
347 if ( is_raw_cmd )
348 out_printf( "Executing raw command directly\n" );
349 else
350 {
351 out_printf( "Executing using a command file and the shell: " );
352 list_print( shell );
353 out_printf( "\n" );
354 }
355 }
356
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
360 * whitespace).
361 */
362 if ( is_raw_cmd )
363 {
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 ] ) )
369 if ( *--p == '\n' )
370 end = p;
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 ) );
374 }
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
377 * that command file.
378 */
379 else
380 {
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 );
385 }
386
387 /* Catch interrupts whenever commands are running. */
388 if ( !intr_installed )
389 {
390 intr_installed = 1;
391 signal( SIGINT, onintr );
392 }
393
394 cmdtab[ slot ].flags = flags;
395
396 /* Save input data into the selected running commands table slot. */
397 cmdtab[ slot ].func = func;
398 cmdtab[ slot ].closure = closure;
399
400 /* Invoke the actual external process using the constructed command line. */
401 invoke_cmd( cmd_local->value, slot );
402
403 /* Free our local command string copy. */
404 string_free( cmd_local );
405 }
406
407
408 /*
409 * exec_wait() - wait for any of the async command processes to terminate
410 *
411 * Wait and drive at most one execution completion, while processing the I/O for
412 * all ongoing commands.
413 */
414
415 void exec_wait()
416 {
417 int i = -1;
418 int exit_reason; /* reason why a command completed */
419
420 /* Wait for a command to complete, while snarfing up any output. */
421 while ( 1 )
422 {
423 /* Check for a complete command, briefly. */
424 i = try_wait( 500 );
425 /* Read in the output of all running commands. */
426 read_output();
427 /* Close out pending debug style dialogs. */
428 close_alerts();
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. */
432 i = try_kill_one();
433 if ( i >= 0 ) { exit_reason = EXIT_TIMEOUT; break; }
434 }
435
436 /* We have a command... process it. */
437 {
438 DWORD exit_code;
439 timing_info time;
440 int rstat;
441
442 /* The time data for the command. */
443 record_times( cmdtab[ i ].pi.hProcess, &time );
444
445 /* Removed the used temporary command file. */
446 if ( cmdtab[ i ].command_file->size )
447 unlink( cmdtab[ i ].command_file->value );
448
449 /* Find out the process exit code. */
450 GetExitCodeProcess( cmdtab[ i ].pi.hProcess, &exit_code );
451
452 /* The dispossition of the command. */
453 if ( interrupted() )
454 rstat = EXEC_CMD_INTR;
455 else if ( exit_code )
456 rstat = EXEC_CMD_FAIL;
457 else
458 rstat = EXEC_CMD_OK;
459
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,
463 exit_reason );
464
465 /* Clean up our child process tracking data. No need to clear the
466 * temporary command file name as it gets reused.
467 */
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 );
476 }
477 }
478
479
480 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
481
482 /*
483 * Invoke the actual external process using the given command line. Track the
484 * process in our running commands table.
485 */
486
487 static void invoke_cmd( char const * const command, int const slot )
488 {
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,
492 0, 0, 0, 0, 0, 0 };
493
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;
499
500 /* Create output buffers. */
501 string_new( cmdtab[ slot ].buffer_out );
502 string_new( cmdtab[ slot ].buffer_err );
503
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 ) )
507 {
508 reportWindowsError( "CreatePipe", slot );
509 return;
510 }
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 ) )
514 {
515 reportWindowsError( "CreatePipe", slot );
516 return;
517 }
518
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 );
525
526 /* Hide the child window, if any. */
527 si.dwFlags |= STARTF_USESHOWWINDOW;
528 si.wShowWindow = SW_HIDE;
529
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 ];
536
537 /* Let the child inherit stdin, as some commands assume it is available. */
538 si.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
539
540 if ( DEBUG_EXECCMD )
541 out_printf( "Command string for CreateProcessA(): '%s'\n", command );
542
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 */
555 {
556 reportWindowsError( "CreateProcessA", slot );
557 return;
558 }
559
560 register_wait( slot );
561 }
562
563
564 /*
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
568 */
569
570 static int raw_maxline()
571 {
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 */
575 }
576
577 static int maxline()
578 {
579 static int result;
580 if ( !result ) result = raw_maxline();
581 return result;
582 }
583
584
585 /*
586 * Closes a Windows HANDLE and resets its variable to 0.
587 */
588
589 static void closeWinHandle( HANDLE * const handle )
590 {
591 if ( *handle )
592 {
593 CloseHandle( *handle );
594 *handle = 0;
595 }
596 }
597
598
599 /*
600 * Frees and renews the given string.
601 */
602
603 static void string_renew( string * const s )
604 {
605 string_free( s );
606 string_new( s );
607 }
608
609
610 /*
611 * raw_command_length() - valid raw command string length
612 *
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.
615 *
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).
623 */
624
625 static long raw_command_length( char const * command )
626 {
627 char const * p;
628 char const * escape = 0;
629 char inquote = 0;
630 char const * newline = 0;
631
632 /* Skip leading whitespace. */
633 while ( isspace( *command ) )
634 ++command;
635
636 p = command;
637
638 /* Look for newlines and unquoted I/O redirection. */
639 do
640 {
641 p += strcspn( p, "\n\"'<>|\\" );
642 switch ( *p )
643 {
644 case '\n':
645 /* If our command contains non-whitespace content split over
646 * multiple lines we can not execute it directly.
647 */
648 newline = p;
649 while ( isspace( *++p ) );
650 if ( *p ) return -1;
651 break;
652
653 case '\\':
654 escape = escape && escape == p - 1 ? 0 : p;
655 ++p;
656 break;
657
658 case '"':
659 case '\'':
660 if ( escape && escape == p - 1 )
661 escape = 0;
662 else if ( inquote == *p )
663 inquote = 0;
664 else if ( !inquote )
665 inquote = *p;
666 ++p;
667 break;
668
669 case '<':
670 case '>':
671 case '|':
672 if ( !inquote )
673 return -1;
674 ++p;
675 break;
676 }
677 }
678 while ( *p );
679
680 /* Return the number of characters the command will occupy. */
681 return ( newline ? newline : p ) - command;
682 }
683
684
685 /* 64-bit arithmetic helpers. */
686
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)
689
690 /* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1
691 * and h2l2.
692 */
693 #define add_64_hi( h1, l1, h2, l2 ) ((h1) + (h2) + add_carry_bit(l1, l2))
694
695
696 /*
697 * Add two 64-bit unsigned numbers, h1l1 and h2l2.
698 */
699
700 static FILETIME add_64
701 (
702 unsigned long h1, unsigned long l1,
703 unsigned long h2, unsigned long l2
704 )
705 {
706 FILETIME result;
707 result.dwLowDateTime = l1 + l2;
708 result.dwHighDateTime = add_64_hi( h1, l1, h2, l2 );
709 return result;
710 }
711
712
713 static FILETIME add_FILETIME( FILETIME t1, FILETIME t2 )
714 {
715 return add_64( t1.dwHighDateTime, t1.dwLowDateTime, t2.dwHighDateTime,
716 t2.dwLowDateTime );
717 }
718
719
720 static FILETIME negate_FILETIME( FILETIME t )
721 {
722 /* 2s complement negation */
723 return add_64( ~t.dwHighDateTime, ~t.dwLowDateTime, 0, 1 );
724 }
725
726
727 /*
728 * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
729 */
730
731 static double filetime_to_seconds( FILETIME const ft )
732 {
733 return ft.dwHighDateTime * ( (double)( 1UL << 31 ) * 2.0 * 1.0e-7 ) +
734 ft.dwLowDateTime * 1.0e-7;
735 }
736
737
738 static void record_times( HANDLE const process, timing_info * const time )
739 {
740 FILETIME creation;
741 FILETIME exit;
742 FILETIME kernel;
743 FILETIME user;
744 if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
745 {
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 );
750 }
751 }
752
753
754 static char ioBuffer[ IO_BUFFER_SIZE + 1 ];
755
756 #define FORWARD_PIPE_NONE 0
757 #define FORWARD_PIPE_STDOUT 1
758 #define FORWARD_PIPE_STDERR 2
759
760 static void read_pipe
761 (
762 HANDLE in, /* the pipe to read from */
763 string * out,
764 int forwarding_mode
765 )
766 {
767 DWORD bytesInBuffer = 0;
768 DWORD bytesAvailable = 0;
769 DWORD i;
770
771 for (;;)
772 {
773 /* check if we have any data to read */
774 if ( !PeekNamedPipe( in, NULL, IO_BUFFER_SIZE, NULL,
775 &bytesAvailable, NULL ) || bytesAvailable == 0 )
776 return;
777
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 )
781 return;
782
783 /* Clean up some illegal chars. */
784 for ( i = 0; i < bytesInBuffer; ++i )
785 {
786 if ( ( (unsigned char)ioBuffer[ i ] < 1 ) )
787 ioBuffer[ i ] = '?';
788 }
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 );
798 }
799 }
800
801 #define EARLY_OUTPUT( cmd ) \
802 ( ! ( cmd.flags & EXEC_CMD_QUIET ) )
803
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 )
810
811 static void read_output()
812 {
813 int i;
814 for ( i = 0; i < globs.jobs; ++i )
815 if ( cmdtab[ i ].pi.hProcess )
816 {
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 ] ) );
825 }
826 }
827
828 static void CALLBACK try_wait_callback( void * data, BOOLEAN is_timeout )
829 {
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 );
837 }
838
839 static int try_wait_impl( DWORD timeout )
840 {
841 int job_index;
842 int res = WaitForSingleObject( process_queue.read_okay, timeout );
843 if ( res != WAIT_OBJECT_0 )
844 return -1;
845 job_index = process_queue.job_index;
846 SetEvent( process_queue.write_okay );
847 return job_index;
848 }
849
850 static void register_wait( int job_id )
851 {
852 if ( globs.jobs > MAXIMUM_WAIT_OBJECTS )
853 {
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 );
858 }
859 }
860
861 /*
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.
865 */
866
867 static int try_wait( int const timeoutMillis )
868 {
869 if ( globs.jobs <= MAXIMUM_WAIT_OBJECTS )
870 {
871 int i;
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 )
877 {
878 if( cmdtab[ i ].pi.hProcess )
879 {
880 job_ids[ num_handles ] = i;
881 active_handles[ num_handles ] = cmdtab[ i ].pi.hProcess;
882 ++num_handles;
883 }
884 }
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 )
887 {
888 return job_ids[ wait_api_result - WAIT_OBJECT_0 ];
889 }
890 else
891 {
892 return -1;
893 }
894 }
895 else
896 {
897 return try_wait_impl( timeoutMillis );
898 }
899
900 }
901
902
903 static int try_kill_one()
904 {
905 /* Only need to check if a timeout was specified with the -l option. */
906 if ( globs.timeout > 0 )
907 {
908 int i;
909 for ( i = 0; i < globs.jobs; ++i )
910 if ( cmdtab[ i ].pi.hProcess )
911 {
912 double const t = running_time( cmdtab[ i ].pi.hProcess );
913 if ( t > (double)globs.timeout )
914 {
915 /* The job may have left an alert dialog around, try and get
916 * rid of it before killing the job itself.
917 */
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. */
923 return i;
924 }
925 }
926 }
927 return -1;
928 }
929
930
931 static void close_alerts()
932 {
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.
936 */
937 if ( ( (float)clock() / (float)( CLOCKS_PER_SEC * 5 ) ) < ( 1.0 / 5.0 ) )
938 {
939 int i;
940 for ( i = 0; i < globs.jobs; ++i )
941 if ( cmdtab[ i ].pi.hProcess )
942 close_alert( &cmdtab[ i ].pi );
943 }
944 }
945
946
947 /*
948 * Calc the current running time of an *active* process.
949 */
950
951 static double running_time( HANDLE const process )
952 {
953 FILETIME creation;
954 FILETIME exit;
955 FILETIME kernel;
956 FILETIME user;
957 if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
958 {
959 /* Compute the elapsed time. */
960 FILETIME current;
961 GetSystemTimeAsFileTime( &current );
962 return filetime_to_seconds( add_FILETIME( current,
963 negate_FILETIME( creation ) ) );
964 }
965 return 0.0;
966 }
967
968
969 /*
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.
972 */
973
974 static void kill_process_tree( DWORD const pid, HANDLE const process )
975 {
976 HANDLE const process_snapshot_h = CreateToolhelp32Snapshot(
977 TH32CS_SNAPPROCESS, 0 );
978 if ( INVALID_HANDLE_VALUE != process_snapshot_h )
979 {
980 BOOL ok = TRUE;
981 PROCESSENTRY32 pinfo;
982 pinfo.dwSize = sizeof( PROCESSENTRY32 );
983 for (
984 ok = Process32First( process_snapshot_h, &pinfo );
985 ok == TRUE;
986 ok = Process32Next( process_snapshot_h, &pinfo ) )
987 {
988 if ( pinfo.th32ParentProcessID == pid )
989 {
990 /* Found a child, recurse to kill it and anything else below it.
991 */
992 HANDLE const ph = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
993 pinfo.th32ProcessID );
994 if ( ph )
995 {
996 kill_process_tree( pinfo.th32ProcessID, ph );
997 CloseHandle( ph );
998 }
999 }
1000 }
1001 CloseHandle( process_snapshot_h );
1002 }
1003 /* Now that the children are all dead, kill the root. */
1004 TerminateProcess( process, -2 );
1005 }
1006
1007
1008 static double creation_time( HANDLE const process )
1009 {
1010 FILETIME creation;
1011 FILETIME exit;
1012 FILETIME kernel;
1013 FILETIME user;
1014 return GetProcessTimes( process, &creation, &exit, &kernel, &user )
1015 ? filetime_to_seconds( creation )
1016 : 0.0;
1017 }
1018
1019
1020 /*
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).
1025 */
1026
1027 static int is_parent_child( DWORD const parent, DWORD const child )
1028 {
1029 HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
1030
1031 if ( !child )
1032 return 0;
1033 if ( parent == child )
1034 return 1;
1035
1036 process_snapshot_h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
1037 if ( INVALID_HANDLE_VALUE != process_snapshot_h )
1038 {
1039 BOOL ok = TRUE;
1040 PROCESSENTRY32 pinfo;
1041 pinfo.dwSize = sizeof( PROCESSENTRY32 );
1042 for (
1043 ok = Process32First( process_snapshot_h, &pinfo );
1044 ok == TRUE;
1045 ok = Process32Next( process_snapshot_h, &pinfo ) )
1046 {
1047 if ( pinfo.th32ProcessID == child )
1048 {
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
1055 * another process.
1056 *
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.
1060 */
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 );
1066
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.
1081 */
1082
1083 #ifdef UNICODE // no PROCESSENTRY32A
1084 if ( !wcsicmp( pinfo.szExeFile, L"csrss.exe" ) &&
1085 #else
1086 if ( !stricmp( pinfo.szExeFile, "csrss.exe" ) &&
1087 #endif
1088 is_parent_child( parent, pinfo.th32ParentProcessID ) == 2 )
1089 return 1;
1090
1091 #ifdef UNICODE // no PROCESSENTRY32A
1092 if ( !wcsicmp( pinfo.szExeFile, L"smss.exe" ) &&
1093 #else
1094 if ( !stricmp( pinfo.szExeFile, "smss.exe" ) &&
1095 #endif
1096 ( pinfo.th32ParentProcessID == 4 ) )
1097 return 2;
1098
1099 if ( hchild )
1100 {
1101 HANDLE hparent = OpenProcess( PROCESS_QUERY_INFORMATION,
1102 FALSE, pinfo.th32ParentProcessID );
1103 if ( hparent )
1104 {
1105 tchild = creation_time( hchild );
1106 tparent = creation_time( hparent );
1107 CloseHandle( hparent );
1108 }
1109 CloseHandle( hchild );
1110 }
1111
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
1115 */
1116 if ( ( tchild == 0.0 ) || ( tparent == 0.0 ) ||
1117 ( tchild < tparent ) )
1118 return 0;
1119
1120 return is_parent_child( parent, pinfo.th32ParentProcessID ) & 1;
1121 }
1122 }
1123
1124 CloseHandle( process_snapshot_h );
1125 }
1126
1127 return 0;
1128 }
1129
1130
1131 /*
1132 * Called by the OS for each topmost window.
1133 */
1134
1135 BOOL CALLBACK close_alert_window_enum( HWND hwnd, LPARAM lParam )
1136 {
1137 char buf[ 7 ] = { 0 };
1138 PROCESS_INFORMATION const * const pi = (PROCESS_INFORMATION *)lParam;
1139 DWORD pid;
1140 DWORD tid;
1141
1142 /* We want to find and close any window that:
1143 * 1. is visible and
1144 * 2. is a dialog and
1145 * 3. is displayed by any of our child processes
1146 */
1147 if (
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" ) )
1154 return TRUE;
1155
1156 /* GetWindowThreadProcessId() returns 0 on error, otherwise thread id of
1157 * the window's message pump thread.
1158 */
1159 tid = GetWindowThreadProcessId( hwnd, &pid );
1160 if ( !tid || !is_parent_child( pi->dwProcessId, pid ) )
1161 return TRUE;
1162
1163 /* Ask real nice. */
1164 PostMessageA( hwnd, WM_CLOSE, 0, 0 );
1165
1166 /* Wait and see if it worked. If not, insist. */
1167 if ( WaitForSingleObject( pi->hProcess, 200 ) == WAIT_TIMEOUT )
1168 {
1169 PostThreadMessageA( tid, WM_QUIT, 0, 0 );
1170 WaitForSingleObject( pi->hProcess, 300 );
1171 }
1172
1173 /* Done, we do not want to check any other windows now. */
1174 return FALSE;
1175 }
1176
1177
1178 static void close_alert( PROCESS_INFORMATION const * const pi )
1179 {
1180 EnumWindows( &close_alert_window_enum, (LPARAM)pi );
1181 }
1182
1183
1184 /*
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.
1189 *
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
1192 * function.
1193 */
1194
1195 static FILE * open_command_file( int const slot )
1196 {
1197 string * const command_file = cmdtab[ slot ].command_file;
1198
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
1202 * end.
1203 */
1204 if ( !command_file->value )
1205 {
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 );
1212 }
1213
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.
1218 *
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
1222 * file names.
1223 */
1224 {
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 )
1232 {
1233 int index;
1234 for ( index = 0; index != 20; ++index )
1235 {
1236 FILE * f;
1237 *index1 = '0' + index / 10;
1238 *index2 = '0' + index % 10;
1239 f = fopen( command_file->value, "w" );
1240 if ( f ) return f;
1241 }
1242 if ( !waits_remaining ) break;
1243 Sleep( 250 );
1244 }
1245 }
1246
1247 return 0;
1248 }
1249
1250
1251 /*
1252 * Prepare a command file to be executed using an external shell.
1253 */
1254
1255 static char const * prepare_command_file( string const * command, int slot )
1256 {
1257 FILE * const f = open_command_file( slot );
1258 if ( !f )
1259 {
1260 err_printf( "failed to write command file!\n" );
1261 exit( EXITBAD );
1262 }
1263 fputs( command->value, f );
1264 fclose( f );
1265 return cmdtab[ slot ].command_file->value;
1266 }
1267
1268
1269 /*
1270 * Find a free slot in the running commands table.
1271 */
1272
1273 static int get_free_cmdtab_slot()
1274 {
1275 int slot;
1276 for ( slot = 0; slot < globs.jobs; ++slot )
1277 if ( !cmdtab[ slot ].pi.hProcess )
1278 return slot;
1279 err_printf( "no slots for child!\n" );
1280 exit( EXITBAD );
1281 }
1282
1283
1284 /*
1285 * Put together the final command string we are to run.
1286 */
1287
1288 static void string_new_from_argv( string * result, char const * const * argv )
1289 {
1290 assert( argv );
1291 assert( argv[ 0 ] );
1292 string_copy( result, *(argv++) );
1293 while ( *argv )
1294 {
1295 string_push_back( result, ' ' );
1296 string_push_back( result, '"' );
1297 string_append( result, *(argv++) );
1298 string_push_back( result, '"' );
1299 }
1300 }
1301
1302
1303 /*
1304 * Reports the last failed Windows API related error message.
1305 */
1306
1307 static void reportWindowsError( char const * const apiName, int slot )
1308 {
1309 char * errorMessage;
1310 char buf[24];
1311 string * err_buf;
1312 timing_info time;
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 */
1324
1325 /* Build a message as if the process had written to stderr. */
1326 if ( globs.pipe_action )
1327 err_buf = cmdtab[ slot ].buffer_err;
1328 else
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 );
1334
1335 if ( !apiResult )
1336 string_append( err_buf, ".\n" );
1337 else
1338 {
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 );
1345 }
1346
1347 /* Since the process didn't actually start, use a blank timing_info. */
1348 time.system = 0;
1349 time.user = 0;
1350 timestamp_current( &time.start );
1351 timestamp_current( &time.end );
1352
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,
1356 EXIT_OK );
1357
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 );
1367 }
1368
1369
1370 #endif /* USE_EXECNT */