コード例 #1
0
ファイル: execnt.c プロジェクト: TuZZiX/ROS_IDE_inc
void exec_cmd
(
    string const * cmd_orig,
    ExecCmdCallback func,
    void * closure,
    LIST * shell
)
{
    int const slot = get_free_cmdtab_slot();
    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. */
    static LIST * default_shell;
    if ( !default_shell )
        default_shell = list_new( object_new( "cmd.exe /Q/C" ) );

    /* Specifying no shell means requesting the default shell. */
    if ( list_empty( shell ) )
        shell = default_shell;

    if ( DEBUG_EXECCMD )
        if ( is_raw_cmd )
            out_printf( "Executing raw command directly\n" );
        else
        {
            out_printf( "Executing using a command file and the shell: " );
            list_print( shell );
            out_printf( "\n" );
        }

    /* If we are running a raw command directly - trim its leading whitespaces
     * as well as any trailing all-whitespace lines but keep any trailing
     * whitespace in the final/only line containing something other than
     * whitespace).
     */
    if ( is_raw_cmd )
    {
        char const * start = cmd_orig->value;
        char const * p = cmd_orig->value + cmd_orig->size;
        char const * end = p;
        while ( isspace( *start ) ) ++start;
        while ( p > start && isspace( p[ -1 ] ) )
            if ( *--p == '\n' )
                end = p;
        string_new( cmd_local );
        string_append_range( cmd_local, start, end );
        assert( cmd_local->size == raw_command_length( cmd_orig->value ) );
    }
    /* If we are not running a raw command directly, prepare a command file to
     * be executed using an external shell and the actual command string using
     * that command file.
     */
    else
    {
        char const * const cmd_file = prepare_command_file( cmd_orig, slot );
        char const * argv[ MAXARGC + 1 ];  /* +1 for NULL */
        argv_from_shell( argv, shell, cmd_file, slot );
        string_new_from_argv( cmd_local, argv );
    }

    /* Catch interrupts whenever commands are running. */
    if ( !intr_installed )
    {
        intr_installed = 1;
        signal( SIGINT, onintr );
    }

    /* Save input data into the selected running commands table slot. */
    cmdtab[ slot ].func = func;
    cmdtab[ slot ].closure = closure;

    /* Invoke the actual external process using the constructed command line. */
    invoke_cmd( cmd_local->value, slot );

    /* Free our local command string copy. */
    string_free( cmd_local );
}
コード例 #2
0
ファイル: execunix.c プロジェクト: DanielaE/boost.build
void exec_cmd
(
    string const * command,
    int flags,
    ExecCmdCallback func,
    void * closure,
    LIST * shell
)
{
    struct sigaction ignore, saveintr, savequit;
    sigset_t chldmask, savemask;

    int const slot = get_free_cmdtab_slot();
    int out[ 2 ];
    int err[ 2 ];
    int len;
    char const * argv[ MAXARGC + 1 ];  /* +1 for NULL */

    /* Initialize default shell. */
    static LIST * default_shell;
    if ( !default_shell )
        default_shell = list_push_back( list_new(
            object_new( "/bin/sh" ) ),
            object_new( "-c" ) );

    if ( list_empty( shell ) )
        shell = default_shell;

    /* Forumulate argv. If shell was defined, be prepared for % and ! subs.
     * Otherwise, use stock /bin/sh.
     */
    argv_from_shell( argv, shell, command->value, slot );

    if ( DEBUG_EXECCMD )
    {
        int i;
        out_printf( "Using shell: " );
        list_print( shell );
        out_printf( "\n" );
        for ( i = 0; argv[ i ]; ++i )
            out_printf( "    argv[%d] = '%s'\n", i, argv[ i ] );
    }

    /* Create pipes for collecting child output. */
    if ( pipe( out ) < 0 || ( globs.pipe_action && pipe( err ) < 0 ) )
    {
        perror( "pipe" );
        exit( EXITBAD );
    }

    /* Start the command */

    timestamp_current( &cmdtab[ slot ].start_dt );

    if ( 0 < globs.timeout )
    {
        /* Handle hung processes by manually tracking elapsed time and signal
         * process when time limit expires.
         */
        struct tms buf;
        cmdtab[ slot ].start_time = times( &buf );

        /* Make a global, only do this once. */
        if ( !tps ) tps = sysconf( _SC_CLK_TCK );
    }

    /* Child does not need the read pipe ends used by the parent. */
    fcntl( out[ EXECCMD_PIPE_READ ], F_SETFD, FD_CLOEXEC );
    if ( globs.pipe_action )
        fcntl( err[ EXECCMD_PIPE_READ ], F_SETFD, FD_CLOEXEC );

    /* ignore SIGINT and SIGQUIT */
    ignore.sa_handler = SIG_IGN;
    sigemptyset(&ignore.sa_mask);
    ignore.sa_flags = 0;
    if (sigaction(SIGINT, &ignore, &saveintr) < 0)
        return;
    if (sigaction(SIGQUIT, &ignore, &savequit) < 0)
        return;

    /* block SIGCHLD */
    sigemptyset(&chldmask);
    sigaddset(&chldmask, SIGCHLD);
    if (sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)
        return;

    if ( ( cmdtab[ slot ].pid = vfork() ) == -1 )
    {
        perror( "vfork" );
        exit( EXITBAD );
    }

    if ( cmdtab[ slot ].pid == 0 )
    {
        /*****************/
        /* Child process */
        /*****************/
        int const pid = getpid();

        /* restore previous signals */
        sigaction(SIGINT, &saveintr, NULL);
        sigaction(SIGQUIT, &savequit, NULL);
        sigprocmask(SIG_SETMASK, &savemask, NULL);

        /* Redirect stdout and stderr to pipes inherited from the parent. */
        dup2( out[ EXECCMD_PIPE_WRITE ], STDOUT_FILENO );
        dup2( globs.pipe_action ? err[ EXECCMD_PIPE_WRITE ] :
            out[ EXECCMD_PIPE_WRITE ], STDERR_FILENO );
        close( out[ EXECCMD_PIPE_WRITE ] );
        if ( globs.pipe_action )
            close( err[ EXECCMD_PIPE_WRITE ] );

        /* Make this process a process group leader so that when we kill it, all
         * child processes of this process are terminated as well. We use
         * killpg( pid, SIGKILL ) to kill the process group leader and all its
         * children.
         */
        if ( 0 < globs.timeout )
        {
            struct rlimit r_limit;
            r_limit.rlim_cur = globs.timeout;
            r_limit.rlim_max = globs.timeout;
            setrlimit( RLIMIT_CPU, &r_limit );
        }
        if (0 != setpgid( pid, pid )) {
            perror("setpgid(child)");
            /* exit( EXITBAD ); */
        }
        execvp( argv[ 0 ], (char * *)argv );
        perror( "execvp" );
        _exit( 127 );
    }

    /******************/
    /* Parent process */
    /******************/

    /* redundant call, ignore return value */
    setpgid(cmdtab[ slot ].pid, cmdtab[ slot ].pid);

    /* Parent not need the write pipe ends used by the child. */
    close( out[ EXECCMD_PIPE_WRITE ] );
    if ( globs.pipe_action )
        close( err[ EXECCMD_PIPE_WRITE ] );

    /* Set both pipe read file descriptors to non-blocking. */
    fcntl( out[ EXECCMD_PIPE_READ ], F_SETFL, O_NONBLOCK );
    if ( globs.pipe_action )
        fcntl( err[ EXECCMD_PIPE_READ ], F_SETFL, O_NONBLOCK );

    /* Parent reads from out[ EXECCMD_PIPE_READ ]. */
    cmdtab[ slot ].fd[ OUT ] = out[ EXECCMD_PIPE_READ ];
    cmdtab[ slot ].stream[ OUT ] = fdopen( cmdtab[ slot ].fd[ OUT ], "rb" );
    if ( !cmdtab[ slot ].stream[ OUT ] )
    {
        perror( "fdopen" );
        exit( EXITBAD );
    }

    /* Parent reads from err[ EXECCMD_PIPE_READ ]. */
    if ( globs.pipe_action )
    {
        cmdtab[ slot ].fd[ ERR ] = err[ EXECCMD_PIPE_READ ];
        cmdtab[ slot ].stream[ ERR ] = fdopen( cmdtab[ slot ].fd[ ERR ], "rb" );
        if ( !cmdtab[ slot ].stream[ ERR ] )
        {
            perror( "fdopen" );
            exit( EXITBAD );
        }
    }

    GET_WAIT_FD( slot )[ OUT ].fd = out[ EXECCMD_PIPE_READ ];
    if ( globs.pipe_action )
        GET_WAIT_FD( slot )[ ERR ].fd = err[ EXECCMD_PIPE_READ ];

    cmdtab[ slot ].flags = flags;

    /* Save input data into the selected running commands table slot. */
    cmdtab[ slot ].func = func;
    cmdtab[ slot ].closure = closure;

    /* restore previous signals */
    sigaction(SIGINT, &saveintr, NULL);
    sigaction(SIGQUIT, &savequit, NULL);
    sigprocmask(SIG_SETMASK, &savemask, NULL);
}