📄 execnt.c
字号:
}
static FILETIME negate_FILETIME(FILETIME t)
{
/* 2s complement negation */
return add_64(~t.dwHighDateTime, ~t.dwLowDateTime, 0, 1);
}
/* COnvert a FILETIME to a number of seconds */
static double filetime_seconds(FILETIME t)
{
return t.dwHighDateTime * (double)(1UL << 31) * 2 + t.dwLowDateTime * 1.0e-7;
}
static void
record_times(int pid, timing_info* time)
{
FILETIME creation, exit, kernel, user;
if (GetProcessTimes((HANDLE)pid, &creation, &exit, &kernel, &user))
{
/* Compute the elapsed time */
#if 0 /* We don't know how to get this number this on Unix */
time->elapsed = filetime_seconds(
add_FILETIME( exit, negate_FILETIME(creation) )
);
#endif
time->system = filetime_seconds(kernel);
time->user = filetime_seconds(user);
}
CloseHandle((HANDLE)pid);
}
/*
* execcmd() - launch an async command execution
*/
void
execcmd(
char *string,
void (*func)( void *closure, int status, timing_info* ),
void *closure,
LIST *shell )
{
int pid;
int slot;
int raw_cmd = 0 ;
char *argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
char **argv = argv_static;
char *p;
/* 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 ( shell && !strcmp(shell->string,"%") && !list_next(shell) )
{
raw_cmd = 1;
shell = 0;
}
if ( !is_win95_defined )
set_is_win95();
/* Find a slot in the running commands table for this one. */
if ( is_win95 )
{
/* only synchronous spans are supported on Windows 95/98 */
slot = 0;
}
else
{
for( slot = 0; slot < MAXJOBS; slot++ )
if( !cmdtab[ slot ].pid )
break;
}
if( slot == MAXJOBS )
{
printf( "no slots for child!\n" );
exit( EXITBAD );
}
if( !cmdtab[ slot ].tempfile )
{
const char *tempdir;
DWORD procID;
tempdir = getTempDir();
/* SVA - allocate 64 other just to be safe */
cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 64 );
procID = GetCurrentProcessId();
sprintf( cmdtab[ slot ].tempfile, "%s\\jam%d-%02d.bat",
tempdir, procID, slot );
}
/* Trim leading, ending white space */
while( isspace( *string ) )
++string;
/* Write to .BAT file unless the line would be too long and it
* meets the other spawnability criteria.
*/
if( raw_cmd && can_spawn( string ) >= MAXLINE )
{
if( DEBUG_EXECCMD )
printf("Executing raw command directly\n");
}
else
{
FILE *f;
raw_cmd = 0;
/* Write command to bat file. */
f = fopen( cmdtab[ slot ].tempfile, "w" );
if (!f)
{
printf( "failed to write command file!\n" );
exit( EXITBAD );
}
fputs( string, f );
fclose( f );
string = cmdtab[ slot ].tempfile;
if( DEBUG_EXECCMD )
{
if (shell)
printf("using user-specified shell: %s", shell->string);
else
printf("Executing through .bat file\n");
}
}
/* Forumulate argv */
/* If shell was defined, be prepared for % and ! subs. */
/* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
if( shell )
{
int i;
char jobno[4];
int gotpercent = 0;
sprintf( jobno, "%d", slot + 1 );
for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
{
switch( shell->string[0] )
{
case '%': argv[i] = string; gotpercent++; break;
case '!': argv[i] = jobno; break;
default: argv[i] = shell->string;
}
if( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[i] );
}
if( !gotpercent )
argv[i++] = string;
argv[i] = 0;
}
else if (raw_cmd)
{
argv = string_to_args(string);
}
else
{
/* don't worry, this is ignored on Win95/98, see later.. */
argv[0] = "cmd.exe";
argv[1] = "/Q/C"; /* anything more is non-portable */
argv[2] = string;
argv[3] = 0;
}
/* Catch interrupts whenever commands are running. */
if( !cmdsrunning++ )
istat = signal( SIGINT, onintr );
/* Start the command */
/* on Win95, we only do a synchronous call */
if ( is_win95 )
{
static const char* hard_coded[] =
{
"del", "erase", "copy", "mkdir", "rmdir", "cls", "dir",
"ren", "rename", "move", 0
};
const char** keyword;
int len, spawn = 1;
int result;
timing_info time = {0,0};
for ( keyword = hard_coded; keyword[0]; keyword++ )
{
len = strlen( keyword[0] );
if ( strnicmp( string, keyword[0], len ) == 0 &&
!isalnum(string[len]) )
{
/* this is one of the hard coded symbols, use 'system' to run */
/* them.. except for "del"/"erase" */
if ( keyword - hard_coded < 2 )
result = process_del( string );
else
result = system( string );
spawn = 0;
break;
}
}
if (spawn)
{
char** args;
/* convert the string into an array of arguments */
/* we need to take care of double quotes !! */
args = string_to_args( string );
if ( args )
{
#if 0
char** arg;
fprintf( stderr, "%s: ", args[0] );
arg = args+1;
while ( arg[0] )
{
fprintf( stderr, " {%s}", arg[0] );
arg++;
}
fprintf( stderr, "\n" );
#endif
result = spawnvp( P_WAIT, args[0], args );
record_times(result, &time);
free_argv( args );
}
else
result = 1;
}
func( closure, result ? EXEC_CMD_FAIL : EXEC_CMD_OK, &time );
return;
}
if( DEBUG_EXECCMD )
{
char **argp = argv;
printf("Executing command");
while(*argp != 0)
{
printf(" [%s]", *argp);
argp++;
}
printf("\n");
}
/* the rest is for Windows NT only */
/* spawn doesn't like quotes around the command name */
if ( argv[0][0] == '"')
{
int l = strlen(argv[0]);
/* Clobber any closing quote, shortening the string by one
* element */
if (argv[0][l-1] == '"')
argv[0][l-1] = '\0';
/* Move everything *including* the original terminating zero
* back one place in memory, covering up the opening quote */
memmove(argv[0],argv[0]+1,l);
}
if( ( pid = spawnvp( P_NOWAIT, argv[0], argv ) ) == -1 )
{
perror( "spawn" );
exit( EXITBAD );
}
/* Save the operation for execwait() to find. */
cmdtab[ slot ].pid = pid;
cmdtab[ slot ].func = func;
cmdtab[ slot ].closure = closure;
/* Wait until we're under the limit of concurrent commands. */
/* Don't trust globs.jobs alone. */
while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
if( !execwait() )
break;
if (argv != argv_static)
{
free_argv(argv);
}
}
/*
* execwait() - wait and drive at most one execution completion
*/
int
execwait()
{
int i;
int status, w;
int rstat;
timing_info time;
/* Handle naive make1() which doesn't know if cmds are running. */
if( !cmdsrunning )
return 0;
if ( is_win95 )
return 0;
/* Pick up process pid and status */
while( ( w = wait( &status ) ) == -1 && errno == EINTR )
;
if( w == -1 )
{
printf( "child process(es) lost!\n" );
perror("wait");
exit( EXITBAD );
}
/* Find the process in the cmdtab. */
for( i = 0; i < MAXJOBS; i++ )
if( w == cmdtab[ i ].pid )
break;
if( i == MAXJOBS )
{
printf( "waif child found!\n" );
exit( EXITBAD );
}
record_times(cmdtab[i].pid, &time);
/* Clear the temp file */
if ( cmdtab[i].tempfile )
unlink( cmdtab[ i ].tempfile );
/* Drive the completion */
if( !--cmdsrunning )
signal( SIGINT, istat );
if( intr )
rstat = EXEC_CMD_INTR;
else if( w == -1 || status != 0 )
rstat = EXEC_CMD_FAIL;
else
rstat = EXEC_CMD_OK;
cmdtab[ i ].pid = 0;
/* SVA don't leak temp files */
if(cmdtab[i].tempfile != NULL)
{
free(cmdtab[i].tempfile);
cmdtab[i].tempfile = NULL;
}
(*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time );
return 1;
}
# if !defined( __BORLANDC__ )
/* The possible result codes from check_process_exit, below */
typedef enum { process_error, process_active, process_finished } process_state;
/* Helper for my_wait() below. Checks to see whether the process has
* exited and if so, records timing information.
*/
static process_state
check_process_exit(
HANDLE process /* The process we're looking at */
, int* status /* Storage for the finished process' exit
* code. If the process is still active
* this location is left untouched. */
, HANDLE* active_handles /* Storage for the process handle if it is
* found to be still active, or NULL. The
* process is treated as though it is
* complete. */
, int* num_active /* The current length of active_handles */
)
{
DWORD exitcode;
process_state result;
/* Try to get the process exit code */
if (!GetExitCodeProcess(process, &exitcode))
{
result = process_error; /* signal an error */
}
else if (
exitcode == STILL_ACTIVE /* If the process is still active */
&& active_handles != 0 /* and we've been passed a place to buffer it */
)
{
active_handles[(*num_active)++] = process; /* push it onto the active stack */
result = process_active;
}
else
{
*status = (int)((exitcode & 0xff) << 8);
result = process_finished;
}
return result;
}
static int
my_wait( int *status )
{
int i, num_active = 0;
DWORD exitcode, waitcode;
HANDLE active_handles[MAXJOBS];
/* first see if any non-waited-for processes are dead,
* and return if so.
*/
for ( i = 0; i < globs.jobs; i++ )
{
int pid = cmdtab[i].pid;
if ( pid )
{
process_state state
= check_process_exit((HANDLE)pid, status, active_handles, &num_active);
if ( state == process_error )
goto FAILED;
else if ( state == process_finished )
return pid;
}
}
/* if a child exists, wait for it to die */
if ( !num_active )
{
errno = ECHILD;
return -1;
}
waitcode = WaitForMultipleObjects( num_active,
active_handles,
FALSE,
INFINITE );
if ( waitcode != WAIT_FAILED )
{
if ( waitcode >= WAIT_ABANDONED_0
&& waitcode < WAIT_ABANDONED_0 + num_active )
i = waitcode - WAIT_ABANDONED_0;
else
i = waitcode - WAIT_OBJECT_0;
if ( check_process_exit(active_handles[i], status, 0, 0) == process_finished )
return (int)active_handles[i];
}
FAILED:
errno = GetLastError();
return -1;
}
# endif /* !__BORLANDC__ */
# endif /* USE_EXECNT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -