mirror of
https://github.com/boostorg/build.git
synced 2026-02-14 00:32:11 +00:00
Boost Jam code cleanup - added a new exec_check() exec*.c module platform specific functions and moved all command validation into them. MAXLINE macro is no longer needed globally for all platforms, and those platforms that do not have a fixed constant for their maximum command line length (e.g. Windows) may now hold that knowledge inside their exec*.c modules and not export it in any way. Windows execnt.c implementation still does some extra command-trimming that needs to be cleaned up.
[SVN r79078]
This commit is contained in:
@@ -70,6 +70,29 @@ void argv_from_shell( char const * * argv, LIST * shell, char const * command,
|
||||
}
|
||||
|
||||
|
||||
/* Returns whether the given command string contains lines longer than the given
|
||||
* maximum.
|
||||
*/
|
||||
int check_cmd_for_too_long_lines( char const * command, int const max,
|
||||
int * const error_length, int * const error_max_length )
|
||||
{
|
||||
while ( *command )
|
||||
{
|
||||
size_t const l = strcspn( command, "\n" );
|
||||
if ( l > max )
|
||||
{
|
||||
*error_length = l;
|
||||
*error_max_length = max;
|
||||
return EXEC_CHECK_LINE_TOO_LONG;
|
||||
}
|
||||
command += l;
|
||||
if ( *command )
|
||||
++command;
|
||||
}
|
||||
return EXEC_CHECK_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Checks whether the given shell list is actually a request to execute raw
|
||||
* commands without an external shell.
|
||||
*/
|
||||
|
||||
@@ -42,6 +42,19 @@ typedef void (* ExecCmdCallback)
|
||||
#define EXEC_CMD_FAIL 1
|
||||
#define EXEC_CMD_INTR 2
|
||||
|
||||
int exec_check
|
||||
(
|
||||
string * command,
|
||||
LIST * * pShell,
|
||||
int * error_length,
|
||||
int * error_max_length
|
||||
);
|
||||
|
||||
/* exec_check() return codes. */
|
||||
#define EXEC_CHECK_OK 101
|
||||
#define EXEC_CHECK_LINE_TOO_LONG 102
|
||||
#define EXEC_CHECK_TOO_LONG 103
|
||||
|
||||
void exec_cmd
|
||||
(
|
||||
string const * command,
|
||||
@@ -80,5 +93,10 @@ int interrupted( void );
|
||||
*/
|
||||
int is_raw_command_request( LIST * shell );
|
||||
|
||||
/* Utility worker for exec_check() checking whether all the given command lines
|
||||
* are under the specified length limit.
|
||||
*/
|
||||
int check_cmd_for_too_long_lines( char const * command, int const max,
|
||||
int * const error_length, int * const error_max_length );
|
||||
|
||||
#endif
|
||||
|
||||
@@ -48,13 +48,13 @@
|
||||
* Do not just set JAMSHELL to cmd.exe - it will not work!
|
||||
*
|
||||
* External routines:
|
||||
* exec_check() - preprocess and validate the command.
|
||||
* exec_cmd() - launch an async command execution.
|
||||
* exec_wait() - wait for any of the async command processes to terminate.
|
||||
*/
|
||||
|
||||
/* get the maximum shell command line length according to the OS */
|
||||
int maxline();
|
||||
|
||||
static int maxline();
|
||||
/* trim leading and trailing whitespace */
|
||||
void string_new_trimmed( string * pResult, string const * source );
|
||||
/* is the command suitable for direct execution via CreateProcessA() */
|
||||
@@ -187,8 +187,76 @@ void execnt_unit_test()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* exec_check() - preprocess and validate the command.
|
||||
*/
|
||||
|
||||
int exec_check
|
||||
(
|
||||
string * command,
|
||||
LIST * * pShell,
|
||||
int * error_length,
|
||||
int * error_max_length
|
||||
)
|
||||
{
|
||||
/* Trim all leading and trailing leading whitespace. */
|
||||
string cmd_local[ 1 ];
|
||||
string_new_trimmed( cmd_local, command );
|
||||
|
||||
/* Check prerequisites for executing raw commands.
|
||||
*
|
||||
* JAMSHELL setting of "%", indicates that the command should be invoked
|
||||
* directly if it satisfies all the spawnability criteria or using a batch
|
||||
* file and the default shell if not.
|
||||
*/
|
||||
if ( is_raw_command_request( *pShell ) )
|
||||
{
|
||||
int const raw_cmd_length = can_spawn( cmd_local->value );
|
||||
if ( raw_cmd_length < maxline() )
|
||||
{
|
||||
/* Fallback to default shell. */
|
||||
list_free( *pShell );
|
||||
*pShell = L0;
|
||||
}
|
||||
else if ( raw_cmd_length > MAX_RAW_COMMAND_LENGTH )
|
||||
{
|
||||
*error_length = raw_cmd_length;
|
||||
*error_max_length = MAX_RAW_COMMAND_LENGTH;
|
||||
string_free( cmd_local );
|
||||
return EXEC_CHECK_TOO_LONG;
|
||||
}
|
||||
else
|
||||
{
|
||||
string_free( cmd_local );
|
||||
return EXEC_CHECK_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know we are using an external shell. Note that there is no need to
|
||||
* check for too long command strings when using an external shell since we
|
||||
* use a command file and assume no one is going to set up a JAMSHELL format
|
||||
* string longer than a few hundred bytes at most which should be well under
|
||||
* the total command string limit. Should someone actually construct such a
|
||||
* JAMSHELL value it will get reported as an 'invalid parameter'
|
||||
* CreateProcessA() Windows API failure which seems like a good enough
|
||||
* result for such intentional mischief.
|
||||
*/
|
||||
|
||||
/* Check for too long command lines. */
|
||||
{
|
||||
int const result = check_cmd_for_too_long_lines( cmd_local->value,
|
||||
maxline(), error_length, error_max_length );
|
||||
string_free( cmd_local );
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* exec_cmd() - launch an async command execution.
|
||||
*
|
||||
* We assume exec_check() already verified that the given command can have its
|
||||
* command string constructed as requested.
|
||||
*/
|
||||
|
||||
void exec_cmd
|
||||
@@ -202,7 +270,7 @@ void exec_cmd
|
||||
)
|
||||
{
|
||||
int const slot = get_free_cmdtab_slot();
|
||||
int is_raw_cmd = is_raw_command_request( shell );
|
||||
int const is_raw_cmd = is_raw_command_request( shell );
|
||||
string cmd_local[ 1 ];
|
||||
|
||||
/* Initialize default shell - anything more than /Q/C is non-portable. */
|
||||
@@ -213,21 +281,6 @@ void exec_cmd
|
||||
/* Trim all leading and trailing leading whitespace. */
|
||||
string_new_trimmed( cmd_local, cmd_orig );
|
||||
|
||||
/* Check to see if we need to hack around the line-length limitation. Look
|
||||
* for a JAMSHELL setting of "%", indicating that the command should be
|
||||
* invoked directly.
|
||||
*/
|
||||
if ( is_raw_cmd )
|
||||
{
|
||||
/* Check to see if we need to hack around the line-length limitation.
|
||||
* JAMSHELL setting of "%", indicates that the command should be invoked
|
||||
* directly if it satisfies all the spawnability criteria or using a
|
||||
* batch file and the default shell if not.
|
||||
*/
|
||||
is_raw_cmd = can_spawn( cmd_local->value ) >= MAXLINE;
|
||||
shell = L0;
|
||||
}
|
||||
|
||||
/* Specifying no shell means requesting the default shell. */
|
||||
if ( list_empty( shell ) )
|
||||
shell = default_shell;
|
||||
@@ -295,14 +348,6 @@ void exec_cmd
|
||||
string_copy( cmdtab[ slot ].command, cmd_orig->value );
|
||||
}
|
||||
|
||||
if ( cmd_local->size > MAX_RAW_COMMAND_LENGTH )
|
||||
{
|
||||
printf( "Command line too long (%d characters). Maximum executable "
|
||||
"command-line length is %d.", cmd_local->size,
|
||||
MAX_RAW_COMMAND_LENGTH );
|
||||
exit( EXITBAD );
|
||||
}
|
||||
|
||||
/* Invoke the actual external process using the constructed command line. */
|
||||
invoke_cmd( cmd_local->value, slot );
|
||||
|
||||
@@ -507,7 +552,7 @@ static int raw_maxline()
|
||||
return 996; /* NT 3.5.1 */
|
||||
}
|
||||
|
||||
int maxline()
|
||||
static int maxline()
|
||||
{
|
||||
static result;
|
||||
if ( !result ) result = raw_maxline();
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
* Do not just set JAMSHELL to /bin/sh - it will not work!
|
||||
*
|
||||
* External routines:
|
||||
* exec_check() - preprocess and validate the command.
|
||||
* exec_cmd() - launch an async command execution.
|
||||
* exec_wait() - wait for any of the async command processes to terminate.
|
||||
*/
|
||||
@@ -97,6 +98,25 @@ static struct
|
||||
} cmdtab[ MAXJOBS ] = { { 0 } };
|
||||
|
||||
|
||||
/*
|
||||
* exec_check() - preprocess and validate the command.
|
||||
*/
|
||||
|
||||
int exec_check
|
||||
(
|
||||
string * command,
|
||||
LIST * * pShell,
|
||||
int * error_length,
|
||||
int * error_max_length
|
||||
)
|
||||
{
|
||||
return is_raw_command_request( *pShell )
|
||||
? EXEC_CHECK_OK
|
||||
: check_cmd_for_too_long_lines( command->value, MAXLINE, error_length,
|
||||
error_max_length );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* exec_cmd() - launch an async command execution.
|
||||
*/
|
||||
|
||||
@@ -46,10 +46,7 @@
|
||||
#define OSMINOR "OS=NT"
|
||||
#define OS_NT
|
||||
#define SPLITPATH ';'
|
||||
/* Windows NT 3.51 only allows 996 chars per line, but we deal with the problem
|
||||
* in "execnt.c".
|
||||
*/
|
||||
#define MAXLINE (maxline()) /* longest 'together' actions */
|
||||
#define MAXLINE (undefined__see_execnt_c) /* max chars per command line */
|
||||
#define USE_EXECNT
|
||||
#define USE_PATHUNIX
|
||||
#define PATH_DELIM '\\'
|
||||
@@ -93,7 +90,7 @@
|
||||
#define OSMINOR "OS=MINGW"
|
||||
#define OS_NT
|
||||
#define SPLITPATH ';'
|
||||
#define MAXLINE 996 /* longest 'together' actions */
|
||||
#define MAXLINE 996 /* max chars per command line */
|
||||
#define USE_EXECUNIX
|
||||
#define USE_PATHUNIX
|
||||
#define PATH_DELIM '\\'
|
||||
@@ -115,7 +112,7 @@
|
||||
|
||||
#ifdef _AIX
|
||||
#define unix
|
||||
#define MAXLINE 23552 /* 24k - 1k, longest 'together' actions */
|
||||
#define MAXLINE 23552 /* 24k - 1k, max chars per command line */
|
||||
#define OSMINOR "OS=AIX"
|
||||
#define OS_AIX
|
||||
#define NO_VFORK
|
||||
@@ -219,7 +216,7 @@
|
||||
#define OSMINOR "OS=QNX"
|
||||
#define OS_QNX
|
||||
#define NO_VFORK
|
||||
#define MAXLINE 996
|
||||
#define MAXLINE 996 /* max chars per command line */
|
||||
#endif
|
||||
#endif
|
||||
#ifdef NeXT
|
||||
@@ -397,7 +394,7 @@
|
||||
*/
|
||||
|
||||
#ifndef MAXLINE
|
||||
#define MAXLINE 102400 /* longest 'together' actions' */
|
||||
#define MAXLINE 102400 /* max chars per command line */
|
||||
#endif
|
||||
|
||||
#ifndef EXITOK
|
||||
|
||||
@@ -1045,7 +1045,11 @@ static CMD * make1cmds( TARGET * t )
|
||||
do
|
||||
{
|
||||
CMD * cmd;
|
||||
int line_too_long = 0;
|
||||
int cmd_check_result;
|
||||
int cmd_error_length;
|
||||
int cmd_error_max_length;
|
||||
int retry = 0;
|
||||
int accept_command = 0;
|
||||
|
||||
/* Build cmd: cmd_new() takes ownership of its lists. */
|
||||
if ( list_empty( cmd_targets ) ) cmd_targets = list_copy( nt );
|
||||
@@ -1053,31 +1057,49 @@ static CMD * make1cmds( TARGET * t )
|
||||
cmd = cmd_new( rule, cmd_targets, list_sublist( ns, start,
|
||||
chunk ), cmd_shell );
|
||||
|
||||
/* Check for too long command string lines. */
|
||||
if ( !is_raw_command_request( cmd->shell ) )
|
||||
cmd_check_result = exec_check( cmd->buf, &cmd->shell,
|
||||
&cmd_error_length, &cmd_error_max_length );
|
||||
|
||||
if ( cmd_check_result == EXEC_CHECK_OK )
|
||||
{
|
||||
char * s = cmd->buf->value;
|
||||
while ( *s )
|
||||
{
|
||||
size_t const l = strcspn( s, "\n" );
|
||||
if ( l > MAXLINE )
|
||||
{
|
||||
line_too_long = 1;
|
||||
break;
|
||||
}
|
||||
s += l;
|
||||
if ( *s )
|
||||
++s;
|
||||
}
|
||||
accept_command = 1;
|
||||
}
|
||||
else if ( ( actions->flags & RULE_PIECEMEAL ) && ( chunk > 1 ) )
|
||||
{
|
||||
/* Too long but splittable. Reduce chunk size slowly and
|
||||
* retry.
|
||||
*/
|
||||
assert( cmd_check_result == EXEC_CHECK_TOO_LONG ||
|
||||
cmd_check_result == EXEC_CHECK_LINE_TOO_LONG );
|
||||
chunk = chunk * 9 / 10;
|
||||
retry = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Too long and not splittable. */
|
||||
char const * const error_message = cmd_check_result ==
|
||||
EXEC_CHECK_TOO_LONG
|
||||
? "is too long"
|
||||
: "contains a line that is too long";
|
||||
assert( cmd_check_result == EXEC_CHECK_TOO_LONG ||
|
||||
cmd_check_result == EXEC_CHECK_LINE_TOO_LONG );
|
||||
printf( "%s action %s (%d, max %d):\n", object_str(
|
||||
rule->name ), error_message, cmd_error_length,
|
||||
cmd_error_max_length );
|
||||
|
||||
/* Tell the user what did not fit. */
|
||||
fputs( cmd->buf->value, stdout );
|
||||
exit( EXITBAD );
|
||||
}
|
||||
|
||||
if ( !line_too_long )
|
||||
assert( !retry || !accept_command );
|
||||
|
||||
if ( accept_command )
|
||||
{
|
||||
/* Chain it up. */
|
||||
if ( !cmds ) cmds = cmd;
|
||||
else cmds->tail->next = cmd;
|
||||
cmds->tail = cmd;
|
||||
start += chunk;
|
||||
|
||||
/* Mark lists we need recreated for the next command since
|
||||
* they got consumed by the cmd object.
|
||||
@@ -1087,28 +1109,15 @@ static CMD * make1cmds( TARGET * t )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( actions->flags & RULE_PIECEMEAL ) && ( chunk > 1 ) )
|
||||
{
|
||||
/* Reduce chunk size slowly. */
|
||||
chunk = chunk * 9 / 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Too long and not splittable. */
|
||||
printf( "%s action is too long (max %d):\n", object_str(
|
||||
rule->name ), MAXLINE );
|
||||
|
||||
/* Tell the user what did not fit. */
|
||||
fputs( cmd->buf->value, stdout );
|
||||
exit( EXITBAD );
|
||||
}
|
||||
|
||||
/* We can reuse targets & shell lists for the next command.
|
||||
/* We can reuse targets & shell lists for the next command
|
||||
* if we do not let them die with this cmd object.
|
||||
*/
|
||||
cmd_release_targets_and_shell( cmd );
|
||||
cmd_free( cmd );
|
||||
}
|
||||
|
||||
if ( !retry )
|
||||
start += chunk;
|
||||
}
|
||||
while ( start < length );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user