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 
59 #if defined(__GNUC__) || defined(__clang__)
60 #else
61 #pragma warning( push )
62 #pragma warning(disable: 4800) // 'BOOL' forced to 'true' or 'false'
63 #endif
64 #include <versionhelpers.h>
65 #if defined(__GNUC__) || defined(__clang__)
66 #else
67 #pragma warning( pop )
68 #endif
69 
70 
71 /* get the maximum shell command line length according to the OS */
72 static int32_t maxline();
73 /* valid raw command string length */
74 static int32_t raw_command_length( char const * command );
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 /* */
80 static FILETIME add_FILETIME( FILETIME t1, FILETIME t2 );
81 /* */
82 static FILETIME negate_FILETIME( FILETIME t );
83 /* record the timing info for the process */
84 static void record_times( HANDLE const, timing_info * const );
85 /* calc the current running time of an *active* process */
86 static double running_time( HANDLE const );
87 /* terminate the given process, after terminating all its children first */
88 static void kill_process_tree( DWORD const procesdId, HANDLE const );
89 /* waits for a command to complete or time out */
90 static int32_t try_wait( int32_t const timeoutMillis );
91 /* reads any pending output for running commands */
92 static void read_output();
93 /* checks if a command ran out of time, and kills it */
94 static int32_t try_kill_one();
95 /* is the first process a parent (direct or indirect) to the second one */
96 static int32_t is_parent_child( DWORD const parent, DWORD const child );
97 /* */
98 static void close_alert( PROCESS_INFORMATION const * const );
99 /* close any alerts hanging around */
100 static void close_alerts();
101 /* prepare a command file to be executed using an external shell */
102 static char const * prepare_command_file( string const * command, int32_t slot );
103 /* invoke the actual external process using the given command line */
104 static void invoke_cmd( char const * const command, int32_t const slot );
105 /* find a free slot in the running commands table */
106 static int32_t get_free_cmdtab_slot();
107 /* put together the final command string we are to run */
108 static void string_new_from_argv( string * result, char const * const * argv );
109 /* frees and renews the given string */
110 static void string_renew( string * const );
111 /* reports the last failed Windows API related error message */
112 static void reportWindowsError( char const * const apiName, int32_t slot );
113 /* closes a Windows HANDLE and resets its variable to 0. */
114 static void closeWinHandle( HANDLE * const handle );
115 /* Adds the job index to the list of currently active jobs. */
116 static void register_wait( int32_t job_id );
117 
118 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
119 
120 /* CreateProcessA() Windows API places a limit of 32768 characters (bytes) on
121  * the allowed command-line length, including a trailing Unicode (2-byte)
122  * nul-terminator character.
123  */
124 #define MAX_RAW_COMMAND_LENGTH 32766
125 
126  /* Communication buffers size */
127 #define IO_BUFFER_SIZE ( 64 * 1024 )
128 
129 /* We hold handles for pipes used to communicate with child processes in two
130  * element arrays indexed as follows.
131  */
132 #define EXECCMD_PIPE_READ 0
133 #define EXECCMD_PIPE_WRITE 1
134 
135 static int32_t intr_installed;
136 
137 
138 /* The list of commands we run. */
139 static struct _cmdtab_t
140 {
141     /* Temporary command file used to execute the action when needed. */
142     string command_file[ 1 ];
143 
144     /* Pipes for communicating with the child process. Parent reads from (0),
145      * child writes to (1).
146      */
147     HANDLE pipe_out[ 2 ];
148     HANDLE pipe_err[ 2 ];
149 
150     string buffer_out[ 1 ];  /* buffer to hold stdout, if any */
151     string buffer_err[ 1 ];  /* buffer to hold stderr, if any */
152 
153     PROCESS_INFORMATION pi;  /* running process information */
154 
155     HANDLE wait_handle;
156 
157     int32_t flags;
158 
159     /* Function called when the command completes. */
160     ExecCmdCallback func;
161 
162     /* Opaque data passed back to the 'func' callback. */
163     void * closure;
164 } * cmdtab = NULL;
165 static int32_t cmdtab_size = 0;
166 
167 /* A thread-safe single element queue.  Used by the worker threads
168  * to signal the main thread that a process is completed.
169  */
170 struct
171 {
172     int32_t job_index;
173     HANDLE read_okay;
174     HANDLE write_okay;
175 } process_queue;
176 
177 /*
178  * Execution unit tests.
179  */
180 
execnt_unit_test()181 void execnt_unit_test()
182 {
183 #if !defined( NDEBUG )
184     /* vc6 preprocessor is broken, so assert with these strings gets confused.
185      * Use a table instead.
186      */
187     {
188         typedef struct test { const char * command; int32_t result; } test;
189         test tests[] = {
190             { "", 0 },
191             { "  ", 0 },
192             { "x", 1 },
193             { "\nx", 1 },
194             { "x\n", 1 },
195             { "\nx\n", 1 },
196             { "\nx \n", 2 },
197             { "\nx \n ", 2 },
198             { " \n\t\t\v\r\r\n \t  x  \v \t\t\r\n\n\n   \n\n\v\t", 8 },
199             { "x\ny", -1 },
200             { "x\n\n y", -1 },
201             { "echo x > foo.bar", -1 },
202             { "echo x < foo.bar", -1 },
203             { "echo x | foo.bar", -1 },
204             { "echo x \">\" foo.bar", 18 },
205             { "echo x '<' foo.bar", 18 },
206             { "echo x \"|\" foo.bar", 18 },
207             { "echo x \\\">\\\" foo.bar", -1 },
208             { "echo x \\\"<\\\" foo.bar", -1 },
209             { "echo x \\\"|\\\" foo.bar", -1 },
210             { "\"echo x > foo.bar\"", 18 },
211             { "echo x \"'\"<' foo.bar", -1 },
212             { "echo x \\\\\"<\\\\\" foo.bar", 22 },
213             { "echo x \\x\\\"<\\\\\" foo.bar", -1 },
214             { 0 } };
215         test const * t;
216         for ( t = tests; t->command; ++t )
217             assert( raw_command_length( t->command ) == t->result );
218     }
219 
220     {
221         int32_t const length = maxline() + 9;
222         char * const cmd = (char *)BJAM_MALLOC_ATOMIC( size_t(length) + 1 );
223         memset( cmd, 'x', size_t(length) );
224         cmd[ length ] = 0;
225         assert( raw_command_length( cmd ) == length );
226         BJAM_FREE( cmd );
227     }
228 #endif
229 }
230 
231 /*
232  * exec_init() - global initialization
233  */
exec_init(void)234 void exec_init( void )
235 {
236     if ( globs.jobs > cmdtab_size )
237     {
238         cmdtab = (_cmdtab_t*)BJAM_REALLOC( cmdtab, globs.jobs * sizeof( *cmdtab ) );
239         memset( cmdtab + cmdtab_size, 0, ( globs.jobs - cmdtab_size ) * sizeof( *cmdtab ) );
240         cmdtab_size = globs.jobs;
241     }
242     if ( globs.jobs > MAXIMUM_WAIT_OBJECTS && !process_queue.read_okay )
243     {
244         process_queue.read_okay = CreateEvent( NULL, FALSE, FALSE, NULL );
245         process_queue.write_okay = CreateEvent( NULL, FALSE, TRUE, NULL );
246     }
247 }
248 
249 /*
250  * exec_done - free resources.
251  */
exec_done(void)252 void exec_done( void )
253 {
254     if ( process_queue.read_okay )
255     {
256         CloseHandle( process_queue.read_okay );
257     }
258     if ( process_queue.write_okay )
259     {
260         CloseHandle( process_queue.write_okay );
261     }
262     BJAM_FREE( cmdtab );
263 }
264 
265 /*
266  * exec_check() - preprocess and validate the command
267  */
268 
exec_check(string const * command,LIST ** pShell,int32_t * error_length,int32_t * error_max_length)269 int32_t exec_check
270 (
271     string const * command,
272     LIST * * pShell,
273     int32_t * error_length,
274     int32_t * error_max_length
275 )
276 {
277     /* Default shell does nothing when triggered with an empty or a
278      * whitespace-only command so we simply skip running it in that case. We
279      * still pass them on to non-default shells as we do not really know what
280      * they are going to do with such commands.
281      */
282     if ( list_empty( *pShell ) )
283     {
284         char const * s = command->value;
285         while ( isspace( *s ) ) ++s;
286         if ( !*s )
287             return EXEC_CHECK_NOOP;
288     }
289 
290     /* Check prerequisites for executing raw commands. */
291     if ( is_raw_command_request( *pShell ) )
292     {
293         int32_t const raw_cmd_length = raw_command_length( command->value );
294         if ( raw_cmd_length < 0 )
295         {
296             /* Invalid characters detected - fallback to default shell. */
297             list_free( *pShell );
298             *pShell = L0;
299         }
300         else if ( raw_cmd_length > MAX_RAW_COMMAND_LENGTH )
301         {
302             *error_length = raw_cmd_length;
303             *error_max_length = MAX_RAW_COMMAND_LENGTH;
304             return EXEC_CHECK_TOO_LONG;
305         }
306         else
307             return raw_cmd_length ? EXEC_CHECK_OK : EXEC_CHECK_NOOP;
308     }
309 
310     /* Now we know we are using an external shell. Note that there is no need to
311      * check for too long command strings when using an external shell since we
312      * use a command file and assume no one is going to set up a JAMSHELL format
313      * string longer than a few hundred bytes at most which should be well under
314      * the total command string limit. Should someone actually construct such a
315      * JAMSHELL value it will get reported as an 'invalid parameter'
316      * CreateProcessA() Windows API failure which seems like a good enough
317      * result for such intentional mischief.
318      */
319 
320     /* Check for too long command lines. */
321     return check_cmd_for_too_long_lines( command->value, shell_maxline(),
322         error_length, error_max_length );
323 }
324 
325 
326 /*
327  * exec_cmd() - launch an async command execution
328  *
329  * We assume exec_check() already verified that the given command can have its
330  * command string constructed as requested.
331  */
332 
exec_cmd(string const * cmd_orig,int32_t flags,ExecCmdCallback func,void * closure,LIST * shell)333 void exec_cmd
334 (
335     string const * cmd_orig,
336     int32_t flags,
337     ExecCmdCallback func,
338     void * closure,
339     LIST * shell
340 )
341 {
342     int32_t const slot = get_free_cmdtab_slot();
343     int32_t const is_raw_cmd = is_raw_command_request( shell );
344     string cmd_local[ 1 ];
345 
346     /* Initialize default shell - anything more than /Q/C is non-portable. */
347     static LIST * default_shell;
348     if ( !default_shell )
349         default_shell = list_new( object_new( "cmd.exe /Q/C" ) );
350 
351     /* Specifying no shell means requesting the default shell. */
352     if ( list_empty( shell ) )
353         shell = default_shell;
354 
355     if ( DEBUG_EXECCMD )
356     {
357         if ( is_raw_cmd )
358             out_printf( "Executing raw command directly\n" );
359         else
360         {
361             out_printf( "Executing using a command file and the shell: " );
362             list_print( shell );
363             out_printf( "\n" );
364         }
365     }
366 
367     /* If we are running a raw command directly - trim its leading whitespaces
368      * as well as any trailing all-whitespace lines but keep any trailing
369      * whitespace in the final/only line containing something other than
370      * whitespace).
371      */
372     if ( is_raw_cmd )
373     {
374         char const * start = cmd_orig->value;
375         char const * p = cmd_orig->value + cmd_orig->size;
376         char const * end = p;
377         while ( isspace( *start ) ) ++start;
378         while ( p > start && isspace( p[ -1 ] ) )
379             if ( *--p == '\n' )
380                 end = p;
381         string_new( cmd_local );
382         string_append_range( cmd_local, start, end );
383         assert( int32_t(cmd_local->size) == raw_command_length( cmd_orig->value ) );
384     }
385     /* If we are not running a raw command directly, prepare a command file to
386      * be executed using an external shell and the actual command string using
387      * that command file.
388      */
389     else
390     {
391         char const * const cmd_file = prepare_command_file( cmd_orig, slot );
392         char const * argv[ MAXARGC + 1 ];  /* +1 for NULL */
393         argv_from_shell( argv, shell, cmd_file, slot );
394         string_new_from_argv( cmd_local, argv );
395     }
396 
397     /* Catch interrupts whenever commands are running. */
398     if ( !intr_installed )
399     {
400         intr_installed = 1;
401         signal( SIGINT, onintr );
402     }
403 
404     cmdtab[ slot ].flags = flags;
405 
406     /* Save input data into the selected running commands table slot. */
407     cmdtab[ slot ].func = func;
408     cmdtab[ slot ].closure = closure;
409 
410     /* Invoke the actual external process using the constructed command line. */
411     invoke_cmd( cmd_local->value, slot );
412 
413     /* Free our local command string copy. */
414     string_free( cmd_local );
415 }
416 
417 
418 /*
419  * exec_wait() - wait for any of the async command processes to terminate
420  *
421  * Wait and drive at most one execution completion, while processing the I/O for
422  * all ongoing commands.
423  */
424 
exec_wait()425 void exec_wait()
426 {
427     int32_t i = -1;
428     int32_t exit_reason;  /* reason why a command completed */
429 
430     /* Wait for a command to complete, while snarfing up any output. */
431     while ( 1 )
432     {
433         /* Check for a complete command, briefly. */
434         i = try_wait( 500 );
435         /* Read in the output of all running commands. */
436         read_output();
437         /* Close out pending debug style dialogs. */
438         close_alerts();
439         /* Process the completed command we found. */
440         if ( i >= 0 ) { exit_reason = EXIT_OK; break; }
441         /* Check if a command ran out of time. */
442         i = try_kill_one();
443         if ( i >= 0 ) { exit_reason = EXIT_TIMEOUT; break; }
444     }
445 
446     /* We have a command... process it. */
447     {
448         DWORD exit_code;
449         timing_info time;
450         int32_t rstat;
451 
452         /* The time data for the command. */
453         record_times( cmdtab[ i ].pi.hProcess, &time );
454 
455         /* Removed the used temporary command file. */
456         if ( cmdtab[ i ].command_file->size )
457             unlink( cmdtab[ i ].command_file->value );
458 
459         /* Find out the process exit code. */
460         GetExitCodeProcess( cmdtab[ i ].pi.hProcess, &exit_code );
461 
462         /* The dispossition of the command. */
463         if ( interrupted() )
464             rstat = EXEC_CMD_INTR;
465         else if ( exit_code )
466             rstat = EXEC_CMD_FAIL;
467         else
468             rstat = EXEC_CMD_OK;
469 
470         /* Call the callback, may call back to jam rule land. */
471         (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time,
472             cmdtab[ i ].buffer_out->value, cmdtab[ i ].buffer_err->value,
473             exit_reason );
474 
475         /* Clean up our child process tracking data. No need to clear the
476          * temporary command file name as it gets reused.
477          */
478         closeWinHandle( &cmdtab[ i ].pi.hProcess );
479         closeWinHandle( &cmdtab[ i ].pi.hThread );
480         closeWinHandle( &cmdtab[ i ].pipe_out[ EXECCMD_PIPE_READ ] );
481         closeWinHandle( &cmdtab[ i ].pipe_out[ EXECCMD_PIPE_WRITE ] );
482         closeWinHandle( &cmdtab[ i ].pipe_err[ EXECCMD_PIPE_READ ] );
483         closeWinHandle( &cmdtab[ i ].pipe_err[ EXECCMD_PIPE_WRITE ] );
484         string_renew( cmdtab[ i ].buffer_out );
485         string_renew( cmdtab[ i ].buffer_err );
486     }
487 }
488 
489 
490 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
491 
492 /*
493  * Invoke the actual external process using the given command line. Track the
494  * process in our running commands table.
495  */
496 
invoke_cmd(char const * const command,int32_t const slot)497 static void invoke_cmd( char const * const command, int32_t const slot )
498 {
499     SECURITY_ATTRIBUTES sa = { sizeof( SECURITY_ATTRIBUTES ), 0, 0 };
500     SECURITY_DESCRIPTOR sd;
501     STARTUPINFOA si = { sizeof( STARTUPINFOA ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
502         0, 0, 0, 0, 0, 0 };
503 
504     /* Init the security data. */
505     InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION );
506     SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE );
507     sa.lpSecurityDescriptor = &sd;
508     sa.bInheritHandle = TRUE;
509 
510     /* Create output buffers. */
511     string_new( cmdtab[ slot ].buffer_out );
512     string_new( cmdtab[ slot ].buffer_err );
513 
514     /* Create pipes for communicating with the child process. */
515     if ( !CreatePipe( &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_READ ],
516         &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ], &sa, IO_BUFFER_SIZE ) )
517     {
518         reportWindowsError( "CreatePipe", slot );
519         return;
520     }
521     if ( globs.pipe_action && !CreatePipe( &cmdtab[ slot ].pipe_err[
522         EXECCMD_PIPE_READ ], &cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_WRITE ],
523         &sa, IO_BUFFER_SIZE ) )
524     {
525         reportWindowsError( "CreatePipe", slot );
526         return;
527     }
528 
529     /* Set handle inheritance off for the pipe ends the parent reads from. */
530     SetHandleInformation( cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_READ ],
531         HANDLE_FLAG_INHERIT, 0 );
532     if ( globs.pipe_action )
533         SetHandleInformation( cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_READ ],
534             HANDLE_FLAG_INHERIT, 0 );
535 
536     /* Hide the child window, if any. */
537     si.dwFlags |= STARTF_USESHOWWINDOW;
538     si.wShowWindow = SW_HIDE;
539 
540     /* Redirect the child's output streams to our pipes. */
541     si.dwFlags |= STARTF_USESTDHANDLES;
542     si.hStdOutput = cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ];
543     si.hStdError = globs.pipe_action
544         ? cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_WRITE ]
545         : cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ];
546 
547     /* Let the child inherit stdin, as some commands assume it is available. */
548     si.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
549 
550     if ( DEBUG_EXECCMD )
551         out_printf( "Command string for CreateProcessA(): '%s'\n", command );
552 
553     /* Run the command by creating a sub-process for it. */
554     if ( !CreateProcessA(
555         NULL                    ,  /* application name                     */
556         (char *)command         ,  /* command line                         */
557         NULL                    ,  /* process attributes                   */
558         NULL                    ,  /* thread attributes                    */
559         TRUE                    ,  /* inherit handles                      */
560         CREATE_NEW_PROCESS_GROUP,  /* create flags                         */
561         NULL                    ,  /* env vars, null inherits env          */
562         NULL                    ,  /* current dir, null is our current dir */
563         &si                     ,  /* startup info                         */
564         &cmdtab[ slot ].pi ) )     /* child process info, if created       */
565     {
566         reportWindowsError( "CreateProcessA", slot );
567         return;
568     }
569 
570     register_wait( slot );
571 }
572 
573 
574 /*
575  * For more details on Windows cmd.exe shell command-line length limitations see
576  * the following MSDN article:
577  *     http://support.microsoft.com/default.aspx?scid=kb;en-us;830473
578  */
579 
raw_maxline()580 static int32_t raw_maxline()
581 {
582     if ( IsWindowsVersionOrGreater(5,0,0) == TRUE ) return 8191;  /* XP       */
583     if ( IsWindowsVersionOrGreater(4,0,0) == TRUE ) return 2047;  /* NT 4.x   */
584     return 996;                                      /* NT 3.5.1 */
585 }
586 
maxline()587 static int32_t maxline()
588 {
589     static int32_t result;
590     if ( !result ) result = raw_maxline();
591     return result;
592 }
593 
594 
595 /*
596  * Closes a Windows HANDLE and resets its variable to 0.
597  */
598 
closeWinHandle(HANDLE * const handle)599 static void closeWinHandle( HANDLE * const handle )
600 {
601     if ( *handle )
602     {
603         CloseHandle( *handle );
604         *handle = 0;
605     }
606 }
607 
608 
609 /*
610  * Frees and renews the given string.
611  */
612 
string_renew(string * const s)613 static void string_renew( string * const s )
614 {
615     string_free( s );
616     string_new( s );
617 }
618 
619 
620 /*
621  * raw_command_length() - valid raw command string length
622  *
623  * Checks whether the given command may be executed as a raw command. If yes,
624  * returns the corresponding command string length. If not, returns -1.
625  *
626  * Rules for constructing raw command strings:
627  *   - Command may not contain unquoted shell I/O redirection characters.
628  *   - May have at most one command line with non-whitespace content.
629  *   - Leading whitespace trimmed.
630  *   - Trailing all-whitespace lines trimmed.
631  *   - Trailing whitespace on the sole command line kept (may theoretically
632  *     affect the executed command).
633  */
634 
raw_command_length(char const * command)635 static int32_t raw_command_length( char const * command )
636 {
637     char const * p;
638     char const * escape = 0;
639     char inquote = 0;
640     char const * newline = 0;
641 
642     /* Skip leading whitespace. */
643     while ( isspace( *command ) )
644         ++command;
645 
646     p = command;
647 
648     /* Look for newlines and unquoted I/O redirection. */
649     do
650     {
651         p += strcspn( p, "\n\"'<>|\\" );
652         switch ( *p )
653         {
654         case '\n':
655             /* If our command contains non-whitespace content split over
656              * multiple lines we can not execute it directly.
657              */
658             newline = p;
659             while ( isspace( *++p ) );
660             if ( *p ) return -1;
661             break;
662 
663         case '\\':
664             escape = escape && escape == p - 1 ? 0 : p;
665             ++p;
666             break;
667 
668         case '"':
669         case '\'':
670             if ( escape && escape == p - 1 )
671                 escape = 0;
672             else if ( inquote == *p )
673                 inquote = 0;
674             else if ( !inquote )
675                 inquote = *p;
676             ++p;
677             break;
678 
679         case '<':
680         case '>':
681         case '|':
682             if ( !inquote )
683                 return -1;
684             ++p;
685             break;
686         }
687     }
688     while ( *p );
689 
690     /* Return the number of characters the command will occupy. */
691     return int32_t(( newline ? newline : p ) - command);
692 }
693 
694 
695 /* 64-bit arithmetic helpers. */
696 
697 /* Compute the carry bit from the addition of two 32-bit unsigned numbers. */
698 #define add_carry_bit( a, b ) ((((a) | (b)) >> 31) & (~((a) + (b)) >> 31) & 0x1)
699 
700 /* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1
701  * and h2l2.
702  */
703 #define add_64_hi( h1, l1, h2, l2 ) ((h1) + (h2) + add_carry_bit(l1, l2))
704 
705 
706 /*
707  * Add two 64-bit unsigned numbers, h1l1 and h2l2.
708  */
709 
add_64(unsigned long h1,unsigned long l1,unsigned long h2,unsigned long l2)710 static FILETIME add_64
711 (
712     unsigned long h1, unsigned long l1,
713     unsigned long h2, unsigned long l2
714 )
715 {
716     FILETIME result;
717     result.dwLowDateTime = l1 + l2;
718     result.dwHighDateTime = add_64_hi( h1, l1, h2, l2 );
719     return result;
720 }
721 
722 
add_FILETIME(FILETIME t1,FILETIME t2)723 static FILETIME add_FILETIME( FILETIME t1, FILETIME t2 )
724 {
725     return add_64( t1.dwHighDateTime, t1.dwLowDateTime, t2.dwHighDateTime,
726         t2.dwLowDateTime );
727 }
728 
729 
negate_FILETIME(FILETIME t)730 static FILETIME negate_FILETIME( FILETIME t )
731 {
732     /* 2s complement negation */
733     return add_64( ~t.dwHighDateTime, ~t.dwLowDateTime, 0, 1 );
734 }
735 
736 
737 /*
738  * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
739  */
740 
filetime_to_seconds(FILETIME const ft)741 static double filetime_to_seconds( FILETIME const ft )
742 {
743     return ft.dwHighDateTime * ( (double)( 1UL << 31 ) * 2.0 * 1.0e-7 ) +
744         ft.dwLowDateTime * 1.0e-7;
745 }
746 
747 
record_times(HANDLE const process,timing_info * const time)748 static void record_times( HANDLE const process, timing_info * const time )
749 {
750     FILETIME creation;
751     FILETIME exit;
752     FILETIME kernel;
753     FILETIME user;
754     if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
755     {
756         time->system = filetime_to_seconds( kernel );
757         time->user = filetime_to_seconds( user );
758         timestamp_from_filetime( &time->start, &creation );
759         timestamp_from_filetime( &time->end, &exit );
760     }
761 }
762 
763 
764 static char ioBuffer[ IO_BUFFER_SIZE + 1 ];
765 
766 #define FORWARD_PIPE_NONE 0
767 #define FORWARD_PIPE_STDOUT 1
768 #define FORWARD_PIPE_STDERR 2
769 
read_pipe(HANDLE in,string * out,int32_t forwarding_mode)770 static void read_pipe
771 (
772     HANDLE   in,  /* the pipe to read from */
773     string * out,
774     int32_t      forwarding_mode
775 )
776 {
777     DWORD bytesInBuffer = 0;
778     DWORD bytesAvailable = 0;
779     DWORD i;
780 
781     for (;;)
782     {
783         /* check if we have any data to read */
784         if ( !PeekNamedPipe( in, NULL, IO_BUFFER_SIZE, NULL,
785             &bytesAvailable, NULL ) || bytesAvailable == 0 )
786             return;
787 
788         /* we only read in the available bytes, to avoid blocking */
789         if ( !ReadFile( in, ioBuffer, bytesAvailable <= IO_BUFFER_SIZE ?
790             bytesAvailable : IO_BUFFER_SIZE, &bytesInBuffer, NULL ) || bytesInBuffer == 0 )
791             return;
792 
793         /* Clean up some illegal chars. */
794         for ( i = 0; i < bytesInBuffer; ++i )
795         {
796             if ( ( (unsigned char)ioBuffer[ i ] < 1 ) )
797                 ioBuffer[ i ] = '?';
798         }
799         /* Null, terminate. */
800         ioBuffer[ bytesInBuffer ] = '\0';
801         /* Append to the output. */
802         string_append( out, ioBuffer );
803         /* Copy it to our output if appropriate */
804         if ( forwarding_mode == FORWARD_PIPE_STDOUT )
805             out_data( ioBuffer );
806         else if ( forwarding_mode == FORWARD_PIPE_STDERR )
807             err_data( ioBuffer );
808     }
809 }
810 
811 #define EARLY_OUTPUT( cmd ) \
812     ( ! ( cmd.flags & EXEC_CMD_QUIET ) )
813 
814 #define FORWARD_STDOUT( c )                                 \
815     ( ( EARLY_OUTPUT( c ) && ( globs.pipe_action != 2 ) ) ? \
816         FORWARD_PIPE_STDOUT : FORWARD_PIPE_NONE )
817 #define FORWARD_STDERR( c )                                 \
818     ( ( EARLY_OUTPUT( c ) && ( globs.pipe_action & 2 ) ) ?  \
819         FORWARD_PIPE_STDERR : FORWARD_PIPE_NONE )
820 
read_output()821 static void read_output()
822 {
823     int32_t i;
824     for ( i = 0; i < globs.jobs; ++i )
825         if ( cmdtab[ i ].pi.hProcess )
826         {
827             /* Read stdout data. */
828             if ( cmdtab[ i ].pipe_out[ EXECCMD_PIPE_READ ] )
829                 read_pipe( cmdtab[ i ].pipe_out[ EXECCMD_PIPE_READ ],
830                     cmdtab[ i ].buffer_out, FORWARD_STDOUT( cmdtab[ i ] ) );
831             /* Read stderr data. */
832             if ( cmdtab[ i ].pipe_err[ EXECCMD_PIPE_READ ] )
833                 read_pipe( cmdtab[ i ].pipe_err[ EXECCMD_PIPE_READ ],
834                     cmdtab[ i ].buffer_err, FORWARD_STDERR( cmdtab[ i ] ) );
835         }
836 }
837 
try_wait_callback(void * data,BOOLEAN is_timeout)838 static void CALLBACK try_wait_callback( void * data, BOOLEAN is_timeout )
839 {
840     struct _cmdtab_t * slot = ( struct _cmdtab_t * )data;
841     WaitForSingleObject( process_queue.write_okay, INFINITE );
842     process_queue.job_index = int32_t(slot - cmdtab);
843     assert( !is_timeout );
844     SetEvent( process_queue.read_okay );
845     /* Okay.  Non-blocking. */
846     UnregisterWait( slot->wait_handle );
847 }
848 
try_wait_impl(DWORD timeout)849 static int32_t try_wait_impl( DWORD timeout )
850 {
851     int32_t job_index;
852     int32_t res = WaitForSingleObject( process_queue.read_okay, timeout );
853     if ( res != WAIT_OBJECT_0 )
854         return -1;
855     job_index = process_queue.job_index;
856     SetEvent( process_queue.write_okay );
857     return job_index;
858 }
859 
register_wait(int32_t job_id)860 static void register_wait( int32_t job_id )
861 {
862     if ( globs.jobs > MAXIMUM_WAIT_OBJECTS )
863     {
864         RegisterWaitForSingleObject( &cmdtab[ job_id ].wait_handle,
865             cmdtab[ job_id ].pi.hProcess,
866             &try_wait_callback, &cmdtab[ job_id ], INFINITE,
867             WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE );
868     }
869 }
870 
871 /*
872  * Waits for a single child process command to complete, or the timeout,
873  * whichever comes first. Returns the index of the completed command in the
874  * cmdtab array, or -1.
875  */
876 
try_wait(int32_t const timeoutMillis)877 static int32_t try_wait( int32_t const timeoutMillis )
878 {
879     if ( globs.jobs <= MAXIMUM_WAIT_OBJECTS )
880     {
881         int32_t i;
882         HANDLE active_handles[ MAXIMUM_WAIT_OBJECTS ];
883         int32_t job_ids[ MAXIMUM_WAIT_OBJECTS ];
884         DWORD num_handles = 0;
885         DWORD wait_api_result;
886         for ( i = 0; i < globs.jobs; ++i )
887         {
888             if( cmdtab[ i ].pi.hProcess )
889             {
890                 job_ids[ num_handles ] = i;
891                 active_handles[ num_handles ] = cmdtab[ i ].pi.hProcess;
892                 ++num_handles;
893             }
894         }
895         wait_api_result = WaitForMultipleObjects( num_handles, active_handles, FALSE, timeoutMillis );
896         if ( WAIT_OBJECT_0 <= wait_api_result && wait_api_result < WAIT_OBJECT_0 + globs.jobs )
897         {
898             return job_ids[ wait_api_result - WAIT_OBJECT_0 ];
899         }
900         else
901         {
902             return -1;
903         }
904     }
905     else
906     {
907         return try_wait_impl( timeoutMillis );
908     }
909 
910 }
911 
912 
try_kill_one()913 static int32_t try_kill_one()
914 {
915     /* Only need to check if a timeout was specified with the -l option. */
916     if ( globs.timeout > 0 )
917     {
918         int32_t i;
919         for ( i = 0; i < globs.jobs; ++i )
920             if ( cmdtab[ i ].pi.hProcess )
921             {
922                 double const t = running_time( cmdtab[ i ].pi.hProcess );
923                 if ( t > (double)globs.timeout )
924                 {
925                     /* The job may have left an alert dialog around, try and get
926                      * rid of it before killing the job itself.
927                      */
928                     close_alert( &cmdtab[ i ].pi );
929                     /* We have a "runaway" job, kill it. */
930                     kill_process_tree( cmdtab[ i ].pi.dwProcessId,
931                         cmdtab[ i ].pi.hProcess );
932                     /* And return its running commands table slot. */
933                     return i;
934                 }
935             }
936     }
937     return -1;
938 }
939 
940 
close_alerts()941 static void close_alerts()
942 {
943     /* We only attempt this every 5 seconds or so, because it is not a cheap
944      * operation, and we will catch the alerts eventually. This check uses
945      * floats as some compilers define CLOCKS_PER_SEC as a float or double.
946      */
947     if ( ( (float)clock() / (float)( CLOCKS_PER_SEC * 5 ) ) < ( 1.0 / 5.0 ) )
948     {
949         int32_t i;
950         for ( i = 0; i < globs.jobs; ++i )
951             if ( cmdtab[ i ].pi.hProcess )
952                 close_alert( &cmdtab[ i ].pi );
953     }
954 }
955 
956 
957 /*
958  * Calc the current running time of an *active* process.
959  */
960 
running_time(HANDLE const process)961 static double running_time( HANDLE const process )
962 {
963     FILETIME creation;
964     FILETIME exit;
965     FILETIME kernel;
966     FILETIME user;
967     if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
968     {
969         /* Compute the elapsed time. */
970         FILETIME current;
971         GetSystemTimeAsFileTime( &current );
972         return filetime_to_seconds( add_FILETIME( current,
973             negate_FILETIME( creation ) ) );
974     }
975     return 0.0;
976 }
977 
978 
979 /*
980  * Not really optimal, or efficient, but it is easier this way, and it is not
981  * like we are going to be killing thousands, or even tens of processes.
982  */
983 
kill_process_tree(DWORD const pid,HANDLE const process)984 static void kill_process_tree( DWORD const pid, HANDLE const process )
985 {
986     HANDLE const process_snapshot_h = CreateToolhelp32Snapshot(
987         TH32CS_SNAPPROCESS, 0 );
988     if ( INVALID_HANDLE_VALUE != process_snapshot_h )
989     {
990         BOOL ok = TRUE;
991         PROCESSENTRY32 pinfo;
992         pinfo.dwSize = sizeof( PROCESSENTRY32 );
993         for (
994             ok = Process32First( process_snapshot_h, &pinfo );
995             ok == TRUE;
996             ok = Process32Next( process_snapshot_h, &pinfo ) )
997         {
998             if ( pinfo.th32ParentProcessID == pid )
999             {
1000                 /* Found a child, recurse to kill it and anything else below it.
1001                  */
1002                 HANDLE const ph = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
1003                     pinfo.th32ProcessID );
1004                 if ( ph )
1005                 {
1006                     kill_process_tree( pinfo.th32ProcessID, ph );
1007                     CloseHandle( ph );
1008                 }
1009             }
1010         }
1011         CloseHandle( process_snapshot_h );
1012     }
1013     /* Now that the children are all dead, kill the root. */
1014     TerminateProcess( process, -2 );
1015 }
1016 
1017 
creation_time(HANDLE const process)1018 static double creation_time( HANDLE const process )
1019 {
1020     FILETIME creation;
1021     FILETIME exit;
1022     FILETIME kernel;
1023     FILETIME user;
1024     return GetProcessTimes( process, &creation, &exit, &kernel, &user )
1025         ? filetime_to_seconds( creation )
1026         : 0.0;
1027 }
1028 
1029 
1030 /*
1031  * Recursive check if first process is parent (directly or indirectly) of the
1032  * second one. Both processes are passed as process ids, not handles. Special
1033  * return value 2 means that the second process is smss.exe and its parent
1034  * process is System (first argument is ignored).
1035  */
1036 
is_parent_child(DWORD const parent,DWORD const child)1037 static int32_t is_parent_child( DWORD const parent, DWORD const child )
1038 {
1039     HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
1040 
1041     if ( !child )
1042         return 0;
1043     if ( parent == child )
1044         return 1;
1045 
1046     process_snapshot_h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
1047     if ( INVALID_HANDLE_VALUE != process_snapshot_h )
1048     {
1049         BOOL ok = TRUE;
1050         PROCESSENTRY32 pinfo;
1051         pinfo.dwSize = sizeof( PROCESSENTRY32 );
1052         for (
1053             ok = Process32First( process_snapshot_h, &pinfo );
1054             ok == TRUE;
1055             ok = Process32Next( process_snapshot_h, &pinfo ) )
1056         {
1057             if ( pinfo.th32ProcessID == child )
1058             {
1059                 /* Unfortunately, process ids are not really unique. There might
1060                  * be spurious "parent and child" relationship match between two
1061                  * non-related processes if real parent process of a given
1062                  * process has exited (while child process kept running as an
1063                  * "orphan") and the process id of such parent process has been
1064                  * reused by internals of the operating system when creating
1065                  * another process.
1066                  *
1067                  * Thus an additional check is needed - process creation time.
1068                  * This check may fail (i.e. return 0) for system processes due
1069                  * to insufficient privileges, and that is OK.
1070                  */
1071                 double tchild = 0.0;
1072                 double tparent = 0.0;
1073                 HANDLE const hchild = OpenProcess( PROCESS_QUERY_INFORMATION,
1074                     FALSE, pinfo.th32ProcessID );
1075                 CloseHandle( process_snapshot_h );
1076 
1077                 /* csrss.exe may display message box like following:
1078                  *   xyz.exe - Unable To Locate Component
1079                  *   This application has failed to start because
1080                  *   boost_foo-bar.dll was not found. Re-installing the
1081                  *   application may fix the problem
1082                  * This actually happens when starting a test process that
1083                  * depends on a dynamic library which failed to build. We want
1084                  * to automatically close these message boxes even though
1085                  * csrss.exe is not our child process. We may depend on the fact
1086                  * that (in all current versions of Windows) csrss.exe is a
1087                  * direct child of the smss.exe process, which in turn is a
1088                  * direct child of the System process, which always has process
1089                  * id == 4. This check must be performed before comparing
1090                  * process creation times.
1091                  */
1092 
1093 #ifdef UNICODE  // no PROCESSENTRY32A
1094                 if ( !wcsicmp( pinfo.szExeFile, L"csrss.exe" ) &&
1095 #else
1096                 if ( !stricmp( pinfo.szExeFile, "csrss.exe" ) &&
1097 #endif
1098                     is_parent_child( parent, pinfo.th32ParentProcessID ) == 2 )
1099                     return 1;
1100 
1101 #ifdef UNICODE  // no PROCESSENTRY32A
1102                 if ( !wcsicmp( pinfo.szExeFile, L"smss.exe" ) &&
1103 #else
1104                 if ( !stricmp( pinfo.szExeFile, "smss.exe" ) &&
1105 #endif
1106                     ( pinfo.th32ParentProcessID == 4 ) )
1107                     return 2;
1108 
1109                 if ( hchild )
1110                 {
1111                     HANDLE hparent = OpenProcess( PROCESS_QUERY_INFORMATION,
1112                         FALSE, pinfo.th32ParentProcessID );
1113                     if ( hparent )
1114                     {
1115                         tchild = creation_time( hchild );
1116                         tparent = creation_time( hparent );
1117                         CloseHandle( hparent );
1118                     }
1119                     CloseHandle( hchild );
1120                 }
1121 
1122                 /* Return 0 if one of the following is true:
1123                  *  1. we failed to read process creation time
1124                  *  2. child was created before alleged parent
1125                  */
1126                 if ( ( tchild == 0.0 ) || ( tparent == 0.0 ) ||
1127                     ( tchild < tparent ) )
1128                     return 0;
1129 
1130                 return is_parent_child( parent, pinfo.th32ParentProcessID ) & 1;
1131             }
1132         }
1133 
1134         CloseHandle( process_snapshot_h );
1135     }
1136 
1137     return 0;
1138 }
1139 
1140 
1141 /*
1142  * Called by the OS for each topmost window.
1143  */
1144 
close_alert_window_enum(HWND hwnd,LPARAM lParam)1145 BOOL CALLBACK close_alert_window_enum( HWND hwnd, LPARAM lParam )
1146 {
1147     char buf[ 7 ] = { 0 };
1148     PROCESS_INFORMATION const * const pi = (PROCESS_INFORMATION *)lParam;
1149     DWORD pid;
1150     DWORD tid;
1151 
1152     /* We want to find and close any window that:
1153      *  1. is visible and
1154      *  2. is a dialog and
1155      *  3. is displayed by any of our child processes
1156      */
1157     if (
1158         /* We assume hidden windows do not require user interaction. */
1159         !IsWindowVisible( hwnd )
1160         /* Failed to read class name; presume it is not a dialog. */
1161         || !GetClassNameA( hwnd, buf, sizeof( buf ) )
1162         /* All Windows system dialogs use the same Window class name. */
1163         || strcmp( buf, "#32770" ) )
1164         return TRUE;
1165 
1166     /* GetWindowThreadProcessId() returns 0 on error, otherwise thread id of
1167      * the window's message pump thread.
1168      */
1169     tid = GetWindowThreadProcessId( hwnd, &pid );
1170     if ( !tid || !is_parent_child( pi->dwProcessId, pid ) )
1171         return TRUE;
1172 
1173     /* Ask real nice. */
1174     PostMessageA( hwnd, WM_CLOSE, 0, 0 );
1175 
1176     /* Wait and see if it worked. If not, insist. */
1177     if ( WaitForSingleObject( pi->hProcess, 200 ) == WAIT_TIMEOUT )
1178     {
1179         PostThreadMessageA( tid, WM_QUIT, 0, 0 );
1180         WaitForSingleObject( pi->hProcess, 300 );
1181     }
1182 
1183     /* Done, we do not want to check any other windows now. */
1184     return FALSE;
1185 }
1186 
1187 
close_alert(PROCESS_INFORMATION const * const pi)1188 static void close_alert( PROCESS_INFORMATION const * const pi )
1189 {
1190     EnumWindows( &close_alert_window_enum, (LPARAM)pi );
1191 }
1192 
1193 
1194 /*
1195  * Open a command file to store the command into for executing using an external
1196  * shell. Returns a pointer to a FILE open for writing or 0 in case such a file
1197  * could not be opened. The file name used is stored back in the corresponding
1198  * running commands table slot.
1199  *
1200  * Expects the running commands table slot's command_file attribute to contain
1201  * either a zeroed out string object or one prepared previously by this same
1202  * function.
1203  */
1204 
open_command_file(int32_t const slot)1205 static FILE * open_command_file( int32_t const slot )
1206 {
1207     string * const command_file = cmdtab[ slot ].command_file;
1208 
1209     /* If the temporary command file name has not already been prepared for this
1210      * slot number, prepare a new one containing a '##' place holder that will
1211      * be changed later and needs to be located at a fixed distance from the
1212      * end.
1213      */
1214     if ( !command_file->value )
1215     {
1216         DWORD const procID = GetCurrentProcessId();
1217         string const * const tmpdir = path_tmpdir();
1218         string_new( command_file );
1219         string_reserve( command_file, tmpdir->size + 64 );
1220         command_file->size = sprintf( command_file->value,
1221             "%s\\jam%lu-%02d-##.bat", tmpdir->value, procID, slot );
1222     }
1223 
1224     /* For some reason opening a command file can fail intermittently. But doing
1225      * some retries works. Most likely this is due to a previously existing file
1226      * of the same name that happens to still be opened by an active virus
1227      * scanner. Originally pointed out and fixed by Bronek Kozicki.
1228      *
1229      * We first try to open several differently named files to avoid having to
1230      * wait idly if not absolutely necessary. Our temporary command file names
1231      * contain a fixed position place holder we use for generating different
1232      * file names.
1233      */
1234     {
1235         char * const index1 = command_file->value + command_file->size - 6;
1236         char * const index2 = index1 + 1;
1237         int32_t waits_remaining;
1238         assert( command_file->value < index1 );
1239         assert( index2 + 1 < command_file->value + command_file->size );
1240         assert( index2[ 1 ] == '.' );
1241         for ( waits_remaining = 3; ; --waits_remaining )
1242         {
1243             int32_t index;
1244             for ( index = 0; index != 20; ++index )
1245             {
1246                 FILE * f;
1247                 *index1 = '0' + index / 10;
1248                 *index2 = '0' + index % 10;
1249                 f = fopen( command_file->value, "w" );
1250                 if ( f ) return f;
1251             }
1252             if ( !waits_remaining ) break;
1253             Sleep( 250 );
1254         }
1255     }
1256 
1257     return 0;
1258 }
1259 
1260 
1261 /*
1262  * Prepare a command file to be executed using an external shell.
1263  */
1264 
prepare_command_file(string const * command,int32_t slot)1265 static char const * prepare_command_file( string const * command, int32_t slot )
1266 {
1267     FILE * const f = open_command_file( slot );
1268     if ( !f )
1269     {
1270         err_printf( "failed to write command file!\n" );
1271         exit( EXITBAD );
1272     }
1273     fputs( command->value, f );
1274     fclose( f );
1275     return cmdtab[ slot ].command_file->value;
1276 }
1277 
1278 
1279 /*
1280  * Find a free slot in the running commands table.
1281  */
1282 
get_free_cmdtab_slot()1283 static int32_t get_free_cmdtab_slot()
1284 {
1285     int32_t slot;
1286     for ( slot = 0; slot < globs.jobs; ++slot )
1287         if ( !cmdtab[ slot ].pi.hProcess )
1288             return slot;
1289     err_printf( "no slots for child!\n" );
1290     exit( EXITBAD );
1291 }
1292 
1293 
1294 /*
1295  * Put together the final command string we are to run.
1296  */
1297 
string_new_from_argv(string * result,char const * const * argv)1298 static void string_new_from_argv( string * result, char const * const * argv )
1299 {
1300     assert( argv );
1301     assert( argv[ 0 ] );
1302     string_copy( result, *(argv++) );
1303     while ( *argv )
1304     {
1305         string_push_back( result, ' ' );
1306         string_push_back( result, '"' );
1307         string_append( result, *(argv++) );
1308         string_push_back( result, '"' );
1309     }
1310 }
1311 
1312 
1313 /*
1314  * Reports the last failed Windows API related error message.
1315  */
1316 
reportWindowsError(char const * const apiName,int32_t slot)1317 static void reportWindowsError( char const * const apiName, int32_t slot )
1318 {
1319     char * errorMessage;
1320     char buf[24];
1321     string * err_buf;
1322     timing_info time;
1323     DWORD const errorCode = GetLastError();
1324     DWORD apiResult = FormatMessageA(
1325         FORMAT_MESSAGE_ALLOCATE_BUFFER |  /* __in      DWORD dwFlags       */
1326         FORMAT_MESSAGE_FROM_SYSTEM |
1327         FORMAT_MESSAGE_IGNORE_INSERTS,
1328         NULL,                             /* __in_opt  LPCVOID lpSource    */
1329         errorCode,                        /* __in      DWORD dwMessageId   */
1330         0,                                /* __in      DWORD dwLanguageId  */
1331         (LPSTR)&errorMessage,             /* __out     LPTSTR lpBuffer     */
1332         0,                                /* __in      DWORD nSize         */
1333         0 );                              /* __in_opt  va_list * Arguments */
1334 
1335     /* Build a message as if the process had written to stderr. */
1336     if ( globs.pipe_action )
1337         err_buf = cmdtab[ slot ].buffer_err;
1338     else
1339         err_buf = cmdtab[ slot ].buffer_out;
1340     string_append( err_buf, apiName );
1341     string_append( err_buf, "() Windows API failed: " );
1342     sprintf( buf, "%lu", errorCode );
1343     string_append( err_buf, buf );
1344 
1345     if ( !apiResult )
1346         string_append( err_buf, ".\n" );
1347     else
1348     {
1349         string_append( err_buf, " - " );
1350         string_append( err_buf, errorMessage );
1351         /* Make sure that the buffer is terminated with a newline */
1352         if( err_buf->value[ err_buf->size - 1 ] != '\n' )
1353             string_push_back( err_buf, '\n' );
1354         LocalFree( errorMessage );
1355     }
1356 
1357     /* Since the process didn't actually start, use a blank timing_info. */
1358     time.system = 0;
1359     time.user = 0;
1360     timestamp_current( &time.start );
1361     timestamp_current( &time.end );
1362 
1363     /* Invoke the callback with a failure status. */
1364     (*cmdtab[ slot ].func)( cmdtab[ slot ].closure, EXEC_CMD_FAIL, &time,
1365         cmdtab[ slot ].buffer_out->value, cmdtab[ slot ].buffer_err->value,
1366         EXIT_OK );
1367 
1368     /* Clean up any handles that were opened. */
1369     closeWinHandle( &cmdtab[ slot ].pi.hProcess );
1370     closeWinHandle( &cmdtab[ slot ].pi.hThread );
1371     closeWinHandle( &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_READ ] );
1372     closeWinHandle( &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ] );
1373     closeWinHandle( &cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_READ ] );
1374     closeWinHandle( &cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_WRITE ] );
1375     string_renew( cmdtab[ slot ].buffer_out );
1376     string_renew( cmdtab[ slot ].buffer_err );
1377 }
1378 
shell_maxline()1379 int32_t shell_maxline()
1380 {
1381     return maxline();
1382 }
1383 
1384 
1385 #endif /* USE_EXECNT */
1386