⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 execnt.c

📁 Boost provides free peer-reviewed portable C++ source libraries. We emphasize libraries that work
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright 1993, 1995 Christopher Seiwald. * * This file is part of Jam - see jam.c for Copyright information. *//*  This file is ALSO: *  Copyright 2001-2004 David Abrahams. *  Copyright 2007 Rene Rivera. *  Distributed under the Boost Software License, Version 1.0. *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) */# include "jam.h"# include "lists.h"# include "execcmd.h"# include "pathsys.h"# include "string.h"# include "output.h"# include <errno.h># include <assert.h># include <ctype.h># include <time.h># include <math.h># ifdef USE_EXECNT# define WIN32_LEAN_AND_MEAN# include <windows.h># include <process.h># include <tlhelp32.h>/* * execnt.c - execute a shell command on Windows NT * * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp(). * The default is: * *  /bin/sh -c %        [ on UNIX/AmigaOS ] *  cmd.exe /c %        [ on Windows NT ] * * Each word must be an individual element in a jam variable value. * * In $(JAMSHELL), % expands to the command string and ! expands to  * the slot number (starting at 1) for multiprocess (-j) invocations. * If $(JAMSHELL) doesn't include a %, it is tacked on as the last * argument. * * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work! * * External routines: *  execcmd() - launch an async command execution *  execwait() - wait and drive at most one execution completion * * Internal routines: *  onintr() - bump intr to note command interruption * * 04/08/94 (seiwald) - Coherent/386 support added. * 05/04/94 (seiwald) - async multiprocess interface * 01/22/95 (seiwald) - $(JAMSHELL) support * 06/02/97 (gsar)    - full async multiprocess support for Win32 *//* get the maximum command line length according to the OS */int maxline();/* delete and argv list */static void free_argv(char**);/* Convert a command string into arguments for spawnvp. */static char** string_to_args(const char*);/* bump intr to note command interruption */static void onintr(int);/* If the command is suitable for execution via spawnvp */long can_spawn(char*);/* Add two 64-bit unsigned numbers, h1l1 and h2l2 */static FILETIME add_64(    unsigned long h1, unsigned long l1,    unsigned long h2, unsigned long l2);static FILETIME add_FILETIME(FILETIME t1, FILETIME t2);static FILETIME negate_FILETIME(FILETIME t);/* Convert a FILETIME to a number of seconds */static double filetime_seconds(FILETIME t);/* record the timing info for the process */static void record_times(HANDLE, timing_info*);/* calc the current running time of an *active* process */static double running_time(HANDLE);/* */DWORD get_process_id(HANDLE);/* terminate the given process, after terminating all its children */static void kill_process_tree(DWORD, HANDLE);/* waits for a command to complete or for the given timeout, whichever is first */static int try_wait(int timeoutMillis);/* reads any pending output for running commands */static void read_output();/* checks if a command ran out of time, and kills it */static int try_kill_one();/* */static double creation_time(HANDLE);/* Recursive check if first process is parent (directly or indirectly) of the second one. */static int is_parent_child(DWORD, DWORD);/* */static void close_alert(HANDLE);/* close any alerts hanging around */static void close_alerts();/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */static int intr = 0;static int cmdsrunning = 0;static void (*istat)( int );/* the list of commands we run */static struct{    /* buffer to hold action */    string action;    /* buffer to hold target */    string target;    /* buffer to hold command being invoked */    string command;    /* the temporary batch file of the action, when needed */    char *tempfile_bat;    /* the pipes for the child process, parent reads from (0),       child writes to (1) */    HANDLE pipe_out[2];    HANDLE pipe_err[2];    /* buffers to hold stdout and stderr, if any */    string buffer_out;    string buffer_err;    /* running process info */    PROCESS_INFORMATION pi;    /* when comand completes, the result value */    DWORD exitcode;    /* function called when the command completes */    void (*func)( void *closure, int status, timing_info*, char *, char * );    void *closure;    /* when command completes, the reason it completed */    int exit_reason;} cmdtab[ MAXJOBS ] = {{0}};/* execution unit tests */void execnt_unit_test(){#if !defined(NDEBUG)            /* vc6 preprocessor is broken, so assert with these strings gets     * confused. Use a table instead.     */    typedef struct test { char* command; int result; } test;    test tests[] = {        { "x", 0 },        { "x\n ", 0 },        { "x\ny", 1 },        { "x\n\n y", 1 },        { "echo x > foo.bar", 1 },        { "echo x < foo.bar", 1 },        { "echo x \">\" foo.bar", 0 },        { "echo x \"<\" foo.bar", 0 },        { "echo x \\\">\\\" foo.bar", 1 },        { "echo x \\\"<\\\" foo.bar", 1 }    };    int i;    for ( i = 0; i < sizeof(tests)/sizeof(*tests); ++i)    {        assert( !can_spawn( tests[i].command ) == tests[i].result );    }    {        char* long_command = BJAM_MALLOC_ATOMIC(MAXLINE + 10);        assert( long_command != 0 );        memset( long_command, 'x', MAXLINE + 9 );        long_command[MAXLINE + 9] = 0;        assert( can_spawn( long_command ) == MAXLINE + 9);        BJAM_FREE( long_command );    }    {        /* Work around vc6 bug; it doesn't like escaped string         * literals inside assert         */        char** argv = string_to_args("\"g++\" -c -I\"Foobar\"");        char const expected[] = "-c -I\"Foobar\"";                 assert(!strcmp(argv[0], "g++"));        assert(!strcmp(argv[1], expected));        free_argv(argv);    }#endif }/* execcmd() - launch an async command execution */void execcmd(     char *command,    void (*func)( void *closure, int status, timing_info*, char *invoked_command, char *command_output),    void *closure,    LIST *shell,    char *action,    char *target ){    int slot;    int raw_cmd = 0 ;    char *argv_static[ MAXARGC + 1 ]; /* +1 for NULL */    char **argv = argv_static;    char *p;    char* command_orig = command;        /* 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;    }    /* Find a slot in the running commands table for this one. */    for( slot = 0; slot < MAXJOBS; slot++ )        if( !cmdtab[ slot ].pi.hProcess )            break;    if( slot == MAXJOBS )    {        printf( "no slots for child!\n" );        exit( EXITBAD );    }    /* compute the name of a temp batch file, for possible use */    if( !cmdtab[ slot ].tempfile_bat )    {        const char *tempdir = path_tmpdir();        DWORD procID = GetCurrentProcessId();          /* SVA - allocate 64 other just to be safe */        cmdtab[ slot ].tempfile_bat = BJAM_MALLOC_ATOMIC( strlen( tempdir ) + 64 );          sprintf(            cmdtab[ slot ].tempfile_bat, "%s\\jam%d-%02d.bat",             tempdir, procID, slot );    }    /* Trim leading, -ending- white space */    while( *(command+1) && isspace( *command ) )        ++command;    /* Write to .BAT file unless the line would be too long and it     * meets the other spawnability criteria.     */    if( raw_cmd && can_spawn( command ) >= MAXLINE )    {        if( DEBUG_EXECCMD )            printf("Executing raw command directly\n");            }    else    {        FILE *f = 0;        int tries = 0;        raw_cmd = 0;                /* Write command to bat file. For some reason this open can           fails intermitently. But doing some retries works. Most likely           this is due to a previously existing file of the same name that           happens to be opened by an active virus scanner. Pointed out,           and fix by Bronek Kozicki. */        for (; !f && tries < 4; ++tries)        {            f = fopen( cmdtab[ slot ].tempfile_bat, "w" );            if ( !f && tries < 4 ) Sleep( 250 );        }        if (!f)        {            printf( "failed to write command file!\n" );            exit( EXITBAD );        }        fputs( command, f );        fclose( f );        command = cmdtab[ slot ].tempfile_bat;                if( DEBUG_EXECCMD )        {            if (shell)                printf("using user-specified shell: %s", shell->string);            else                printf("Executing through .bat file\n");        }    }    /* Formulate argv; If shell was defined, be prepared for % and ! subs. */    /* Otherwise, use stock cmd.exe. */    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] = command; 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++] = command;        argv[i] = 0;    }    else if (raw_cmd)    {        argv = string_to_args(command);    }    else    {        argv[0] = "cmd.exe";        argv[1] = "/Q/C"; /* anything more is non-portable */        argv[2] = command;        argv[3] = 0;    }    /* Catch interrupts whenever commands are running. */    if( !cmdsrunning++ )        istat = signal( SIGINT, onintr );        /* Start the command */    {        SECURITY_ATTRIBUTES sa            = { sizeof(SECURITY_ATTRIBUTES), 0, 0 };        SECURITY_DESCRIPTOR sd;        STARTUPINFO si            = { sizeof(STARTUPINFO), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };        string cmd;        /* init the security data */        InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION );        SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE );        sa.lpSecurityDescriptor = &sd;        sa.bInheritHandle = TRUE;        /* create the stdout, which is also the merged out+err, pipe */        if ( ! CreatePipe( &cmdtab[ slot ].pipe_out[0], &cmdtab[ slot ].pipe_out[1], &sa, 0 ) )        {            perror( "CreatePipe" );            exit( EXITBAD );        }        /* create the stdout, which is also the merged out+err, pipe */        if ( globs.pipe_action == 2 )        {            if ( ! CreatePipe( &cmdtab[ slot ].pipe_err[0], &cmdtab[ slot ].pipe_err[1], &sa, 0 ) )            {                perror( "CreatePipe" );                exit( EXITBAD );            }        }        /* set handle inheritance off for the pipe ends the parent reads from */        SetHandleInformation( cmdtab[ slot ].pipe_out[0], HANDLE_FLAG_INHERIT, 0 );        if ( globs.pipe_action == 2 )        {            SetHandleInformation( cmdtab[ slot ].pipe_err[0], HANDLE_FLAG_INHERIT, 0 );        }        /* hide the child window, if any */        si.dwFlags |= STARTF_USESHOWWINDOW;        si.wShowWindow = SW_HIDE;        /* set the child outputs to the pipes */        si.dwFlags |= STARTF_USESTDHANDLES;        si.hStdOutput = cmdtab[ slot ].pipe_out[1];        if ( globs.pipe_action == 2 )        {            /* pipe stderr to the action error output */            si.hStdError = cmdtab[ slot ].pipe_err[1];        }        else if ( globs.pipe_action == 1 )        {            /* pipe stderr to the console error output */            si.hStdError = GetStdHandle(STD_ERROR_HANDLE);        }        else        {            /* pipe stderr to the action merged output */            si.hStdError = cmdtab[ slot ].pipe_out[1];        }        /* Save the operation for execwait() to find. */        cmdtab[ slot ].func = func;        cmdtab[ slot ].closure = closure;        if (action && target)        {            string_copy( &cmdtab[ slot ].action, action );            string_copy( &cmdtab[ slot ].target, target );        }        else        {            string_free( &cmdtab[ slot ].action );            string_new( &cmdtab[ slot ].action );            string_free( &cmdtab[ slot ].target );            string_new( &cmdtab[ slot ].target );        }        string_copy( &cmdtab[ slot ].command, command_orig );                /* put together the comman we run */        {            char ** argp = argv;            string_new(&cmd);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -