Beispiel #1
0
int read_descriptor( int i, int s )
{
    int  ret;
    int  len;
    char buffer[BUFSIZ];

    while ( 0 < ( ret = fread( buffer, sizeof(char),  BUFSIZ-1, cmdtab[ i ].stream[ s ] ) ) )
    {
        buffer[ret] = 0;
        if  ( !cmdtab[ i ].buffer[ s ] )
        {
            /* Never been allocated. */
            cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( ret + 1 );
            memcpy( cmdtab[ i ].buffer[ s ], buffer, ret + 1 );
        }
        else
        {
            /* Previously allocated. */
            char * tmp = cmdtab[ i ].buffer[ s ];
            len = strlen( tmp );
            cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( len + ret + 1 );
            memcpy( cmdtab[ i ].buffer[ s ], tmp, len );
            memcpy( cmdtab[ i ].buffer[ s ] + len, buffer, ret + 1 );
            BJAM_FREE( tmp );
        }
    }

    return feof(cmdtab[ i ].stream[ s ]);
}
Beispiel #2
0
static int read_descriptor( int i, int s )
{
    int ret;
    char buffer[ BUFSIZ ];

    while ( 0 < ( ret = fread( buffer, sizeof( char ), BUFSIZ - 1,
        cmdtab[ i ].stream[ s ] ) ) )
    {
        buffer[ ret ] = 0;

        /* Copy it to our output if appropriate */
        if ( ! ( cmdtab[ i ].flags & EXEC_CMD_QUIET ) )
        {
            if ( s == OUT && ( globs.pipe_action != 2 ) )
                out_data( buffer );
            else if ( s == ERR && ( globs.pipe_action & 2 ) )
                err_data( buffer );
        }

        if ( !cmdtab[ i ].buffer[ s ] )
        {
            /* Never been allocated. */
            if ( globs.max_buf && ret > globs.max_buf )
            {
                ret = globs.max_buf;
                buffer[ ret ] = 0;
            }
            cmdtab[ i ].buf_size[ s ] = ret + 1;
            cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( ret + 1 );
            memcpy( cmdtab[ i ].buffer[ s ], buffer, ret + 1 );
        }
        else
        {
            /* Previously allocated. */
            if ( cmdtab[ i ].buf_size[ s ] < globs.max_buf || !globs.max_buf )
            {
                char * tmp = cmdtab[ i ].buffer[ s ];
                int const old_len = cmdtab[ i ].buf_size[ s ] - 1;
                int const new_len = old_len + ret + 1;
                cmdtab[ i ].buf_size[ s ] = new_len;
                cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( new_len );
                memcpy( cmdtab[ i ].buffer[ s ], tmp, old_len );
                memcpy( cmdtab[ i ].buffer[ s ] + old_len, buffer, ret + 1 );
                BJAM_FREE( tmp );
            }
        }
    }

    /* If buffer full, ensure last buffer char is newline so that jam log
     * contains the command status at beginning of it own line instead of
     * appended to end of the previous output.
     */
    if ( globs.max_buf && globs.max_buf <= cmdtab[ i ].buf_size[ s ] )
        cmdtab[ i ].buffer[ s ][ cmdtab[ i ].buf_size[ s ] - 2 ] = '\n';

    return feof( cmdtab[ i ].stream[ s ] );
}
Beispiel #3
0
int read_descriptor( int i, int s )
{
    int  ret = 1, len, err;
    char buffer[BUFSIZ];

    while ( 0 < ( ret = fread( buffer, sizeof(char),  BUFSIZ-1, cmdtab[ i ].stream[ s ] ) ) ) {

        /* only copy action data until hit buffer limit, then ignore rest of data */
        if (cmdtab[i].msgsize[s] < globs.maxbuf) {
            cmdtab[i].msgsize[s] += ret;
            buffer[ret] = 0;
            if  ( !cmdtab[ i ].buffer[ s ] )
            {
                /* Never been allocated. */
                cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( ret + 1 );
                memcpy( cmdtab[ i ].buffer[ s ], buffer, ret + 1 );
            }
            else
            {
                /* Previously allocated. */
                char * tmp = cmdtab[ i ].buffer[ s ];
                len = strlen( tmp );
                cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( len + ret + 1 );
                memcpy( cmdtab[ i ].buffer[ s ], tmp, len );
                memcpy( cmdtab[ i ].buffer[ s ] + len, buffer, ret + 1 );
                BJAM_FREE( tmp );
            }

            /* buffer was truncated, append newline to ensure pjl can find line end */
            if (globs.maxbuf <= cmdtab[i].msgsize[s]) {
                cmdtab[i].buffer[s][cmdtab[i].msgsize[s]-1] = '\n';
            }
        }
    }

    return feof(cmdtab[ i ].stream[ s ]);
}
Beispiel #4
0
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[] = {
            { "", 0 },
            { "  ", 0 },
            { "x", 1 },
            { "\nx", 1 },
            { "x\n", 1 },
            { "\nx\n", 1 },
            { "\nx \n", 2 },
            { "\nx \n ", 2 },
            { " \n\t\t\v\r\r\n \t  x  \v \t\t\r\n\n\n   \n\n\v\t", 8 },
            { "x\ny", -1 },
            { "x\n\n y", -1 },
            { "echo x > foo.bar", -1 },
            { "echo x < foo.bar", -1 },
            { "echo x | foo.bar", -1 },
            { "echo x \">\" foo.bar", 18 },
            { "echo x '<' foo.bar", 18 },
            { "echo x \"|\" foo.bar", 18 },
            { "echo x \\\">\\\" foo.bar", -1 },
            { "echo x \\\"<\\\" foo.bar", -1 },
            { "echo x \\\"|\\\" foo.bar", -1 },
            { "\"echo x > foo.bar\"", 18 },
            { "echo x \"'\"<' foo.bar", -1 },
            { "echo x \\\\\"<\\\\\" foo.bar", 22 },
            { "echo x \\x\\\"<\\\\\" foo.bar", -1 },
            { 0 } };
        test const * t;
        for ( t = tests; t->command; ++t )
            assert( raw_command_length( t->command ) == t->result );
    }

    {
        int const length = maxline() + 9;
        char * const cmd = (char *)BJAM_MALLOC_ATOMIC( length + 1 );
        memset( cmd, 'x', length );
        cmd[ length ] = 0;
        assert( raw_command_length( cmd ) == length );
        BJAM_FREE( cmd );
    }
#endif
}
Beispiel #5
0
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
}
Beispiel #6
0
static void string_reserve_internal( string * self, size_t capacity )
{
    if ( self->value == self->opt )
    {
        self->value = (char *)BJAM_MALLOC_ATOMIC( capacity +
            JAM_STRING_MAGIC_SIZE );
        self->value[ 0 ] = 0;
        strncat( self->value, self->opt, sizeof(self->opt) );
        assert( strlen( self->value ) <= self->capacity && "Regression test" );
    }
    else
    {
        self->value = (char *)BJAM_REALLOC( self->value, capacity +
            JAM_STRING_MAGIC_SIZE );
    }
#ifndef NDEBUG
    memcpy( self->value + capacity, self->magic, JAM_STRING_MAGIC_SIZE );
#endif
    self->capacity = capacity;
}
Beispiel #7
0
void
file_archscan(
    const char * archive,
    scanback func,
    void * closure )
{
# ifndef NO_AR
    struct ar_hdr ar_hdr;
    char buf[ MAXJPATH ];
    long offset;
    char    *string_table = 0;
    int fd;

    if ( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
        return;

    if ( read( fd, buf, SARMAG ) != SARMAG ||
        strncmp( ARMAG, buf, SARMAG ) )
    {
        close( fd );
        return;
    }

    offset = SARMAG;

    if ( DEBUG_BINDSCAN )
        printf( "scan archive %s\n", archive );

    while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR )
           && !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
#ifdef ARFZMAG
              /* OSF also has a compressed format */
              && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
#endif
          ) )
    {
        char   lar_name_[257];
        char * lar_name = lar_name_ + 1;
        long   lar_date;
        long   lar_size;
        long   lar_offset;
        char * c;
        char * src;
        char * dest;
        OBJECT * member;

        strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );

        sscanf( ar_hdr.ar_date, "%ld", &lar_date );
        sscanf( ar_hdr.ar_size, "%ld", &lar_size );

        if (ar_hdr.ar_name[0] == '/')
        {
        if (ar_hdr.ar_name[1] == '/')
        {
            /* this is the "string table" entry of the symbol table,
            ** which holds strings of filenames that are longer than
            ** 15 characters (ie. don't fit into a ar_name
            */

            string_table = (char *)BJAM_MALLOC_ATOMIC(lar_size);
            lseek(fd, offset + SARHDR, 0);
            if (read(fd, string_table, lar_size) != lar_size)
            printf("error reading string table\n");
        }
        else if (string_table && ar_hdr.ar_name[1] != ' ')
        {
            /* Long filenames are recognized by "/nnnn" where nnnn is
            ** the offset of the string in the string table represented
            ** in ASCII decimals.
            */
            dest = lar_name;
            lar_offset = atoi(lar_name + 1);
            src = &string_table[lar_offset];
            while (*src != '/')
            *dest++ = *src++;
            *dest = '/';
        }
        }

        c = lar_name - 1;
        while ( ( *++c != ' ' ) && ( *c != '/' ) ) ;
        *c = '\0';

        if ( DEBUG_BINDSCAN )
        printf( "archive name %s found\n", lar_name );

        sprintf( buf, "%s(%s)", archive, lar_name );

        member = object_new( buf );
        (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
        object_free( member );

        offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
        lseek( fd, offset, 0 );
    }

    if ( string_table )
        BJAM_FREE( string_table );

    close( fd );

# endif /* NO_AR */

}
Beispiel #8
0
void
file_archscan(
    char *archive,
    scanback func,
    void *closure )
{
    struct ar_hdr ar_hdr;
    char *string_table = 0;
    char buf[ MAXJPATH ];
    long offset;
    int fd;

    if ( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
        return;

    if ( read( fd, buf, SARMAG ) != SARMAG ||
        strncmp( ARMAG, buf, SARMAG ) )
    {
        close( fd );
        return;
    }

    offset = SARMAG;

    if ( DEBUG_BINDSCAN )
        printf( "scan archive %s\n", archive );

    while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
           !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
    {
        long    lar_date;
        long    lar_size;
        char    *name = 0;
        char    *endname;
        char    *c;

        sscanf( ar_hdr.ar_date, "%ld", &lar_date );
        sscanf( ar_hdr.ar_size, "%ld", &lar_size );

        lar_size = ( lar_size + 1 ) & ~1;

        if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
        {
        /* this is the "string table" entry of the symbol table,
        ** which holds strings of filenames that are longer than
        ** 15 characters (ie. don't fit into a ar_name
        */

        string_table = BJAM_MALLOC_ATOMIC(lar_size+1);
        if (read(fd, string_table, lar_size) != lar_size)
            printf("error reading string table\n");
        string_table[lar_size] = '\0';
        offset += SARHDR + lar_size;
        continue;
        }
        else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
        {
            /* Long filenames are recognized by "/nnnn" where nnnn is
            ** the offset of the string in the string table represented
            ** in ASCII decimals.
            */

            name = string_table + atoi( ar_hdr.ar_name + 1 );
            for ( endname = name; *endname && *endname != '\n'; ++endname) {}
        }
        else
        {
            /* normal name */
            name = ar_hdr.ar_name;
            endname = name + sizeof( ar_hdr.ar_name );
        }

        /* strip trailing white-space, slashes, and backslashes */

        while ( endname-- > name )
            if ( !isspace(*endname) && ( *endname != '\\' ) && ( *endname != '/' ) )
                break;
        *++endname = 0;

        /* strip leading directory names, an NT specialty */

        if ( c = strrchr( name, '/' ) )
        name = c + 1;
        if ( c = strrchr( name, '\\' ) )
        name = c + 1;

        sprintf( buf, "%s(%.*s)", archive, endname - name, name );
        (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );

        offset += SARHDR + lar_size;
        lseek( fd, offset, 0 );
    }

    close( fd );
}
Beispiel #9
0
void exec_cmd
(
    char * string,
    void (*func)( void *closure, int status, timing_info*, char *, char * ),
    void * closure,
    LIST * shell,
    char * action,
    char * target
)
{
    static int initialized = 0;
    int    out[2];
    int    err[2];
    int    slot;
    int    len;
    char * argv[ MAXARGC + 1 ];  /* +1 for NULL */

    /* Find a slot in the running commands table for this one. */
    for ( slot = 0; slot < MAXJOBS; ++slot )
        if ( !cmdtab[ slot ].pid )
            break;

    if ( slot == MAXJOBS )
    {
        printf( "no slots for child!\n" );
        exit( EXITBAD );
    }

    /* 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
    {
        argv[ 0 ] = "/bin/sh";
        argv[ 1 ] = "-c";
        argv[ 2 ] = string;
        argv[ 3 ] = 0;
    }

    /* Increment jobs running. */
    ++cmdsrunning;

    /* Save off actual command string. */
    cmdtab[ slot ].command = BJAM_MALLOC_ATOMIC( strlen( string ) + 1 );
    strcpy( cmdtab[ slot ].command, string );

    /* Initialize only once. */
    if ( !initialized )
    {
        times( &old_time );
        initialized = 1;
    }

    /* Create pipes from child to parent. */
    {
        if ( pipe( out ) < 0 )
            exit( EXITBAD );
        fcntl( out[0], F_SETFL, O_NONBLOCK );
        fcntl( out[1], F_SETFL, O_NONBLOCK );

        if ( pipe( err ) < 0 )
            exit( EXITBAD );
        fcntl( err[0], F_SETFL, O_NONBLOCK );
        fcntl( err[1], F_SETFL, O_NONBLOCK );
    }

    /* Start the command */

    cmdtab[ slot ].start_dt = time(0);

    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 == 0 ) tps = sysconf( _SC_CLK_TCK );
    }

    if ( ( cmdtab[ slot ].pid = vfork() ) == 0 )
    {
        int pid = getpid();

        close( out[0] );
        close( err[0] );

        dup2( out[1], STDOUT_FILENO );

        if ( globs.pipe_action == 0 )
        {
            dup2( out[1], STDERR_FILENO );
            close( err[1] );
        }
        else
            dup2( err[1], STDERR_FILENO );

        /* 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 );
        }
        setpgid( pid,pid );
        execvp( argv[0], argv );
        perror( "execvp" );
        _exit( 127 );
    }
    else if ( cmdtab[ slot ].pid == -1 )
    {
        perror( "vfork" );
        exit( EXITBAD );
    }

    setpgid( cmdtab[ slot ].pid, cmdtab[ slot ].pid );

    /* close write end of pipes */
    close( out[1] );
    close( err[1] );

    /* child writes stdout to out[1], parent reads from out[0] */
    cmdtab[ slot ].fd[ OUT ] = out[0];
    cmdtab[ slot ].stream[ OUT ] = fdopen( cmdtab[ slot ].fd[ OUT ], "rb" );
    if ( cmdtab[ slot ].stream[ OUT ] == NULL )
    {
        perror( "fdopen" );
        exit( EXITBAD );
    }

    /* child writes stderr to err[1], parent reads from err[0] */
    if (globs.pipe_action == 0)
    {
      close(err[0]);
    }
    else
    {
        cmdtab[ slot ].fd[ ERR ] = err[0];
        cmdtab[ slot ].stream[ ERR ] = fdopen( cmdtab[ slot ].fd[ ERR ], "rb" );
        if ( cmdtab[ slot ].stream[ ERR ] == NULL )
        {
            perror( "fdopen" );
            exit( EXITBAD );
        }
    }

    /* Ensure enough room for rule and target name. */
    if ( action && target )
    {
        len = strlen( action ) + 1;
        if ( cmdtab[ slot ].action_length < len )
        {
            BJAM_FREE( cmdtab[ slot ].action );
            cmdtab[ slot ].action = BJAM_MALLOC_ATOMIC( len );
            cmdtab[ slot ].action_length = len;
        }
        strcpy( cmdtab[ slot ].action, action );
        len = strlen( target ) + 1;
        if ( cmdtab[ slot ].target_length < len )
        {
            BJAM_FREE( cmdtab[ slot ].target );
            cmdtab[ slot ].target = BJAM_MALLOC_ATOMIC( len );
            cmdtab[ slot ].target_length = len;
        }
        strcpy( cmdtab[ slot ].target, target );
    }
    else
    {
        BJAM_FREE( cmdtab[ slot ].action );
        BJAM_FREE( cmdtab[ slot ].target );
        cmdtab[ slot ].action = 0;
        cmdtab[ slot ].target = 0;
        cmdtab[ slot ].action_length = 0;
        cmdtab[ slot ].target_length = 0;
    }

    /* Save the operation for exec_wait() to find. */
    cmdtab[ slot ].func = func;
    cmdtab[ slot ].closure = closure;

    /* Wait until we are under the limit of concurrent commands. Do not trust
     * globs.jobs alone.
     */
    while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) )
        if ( !exec_wait() )
            break;
}
Beispiel #10
0
int file_collect_archive_content_( file_archive_info_t * const archive )
{
#ifndef NO_AR
    struct ar_hdr ar_hdr;
    char * string_table = 0;
    char buf[ MAXJPATH ];
    long offset;
    int fd;
    const char * path = object_str( archive->file->name );

    if ( ! filelist_empty( archive->members ) ) filelist_free( archive->members );

    if ( ( fd = open( path, O_RDONLY, 0 ) ) < 0 )
        return -1;

    if ( read( fd, buf, SARMAG ) != SARMAG ||
            strncmp( ARMAG, buf, SARMAG ) )
    {
        close( fd );
        return -1;
    }

    offset = SARMAG;

    if ( DEBUG_BINDSCAN )
        out_printf( "scan archive %s\n", path );

    while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
            !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
#ifdef ARFZMAG
               /* OSF also has a compressed format */
               && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
#endif
             ) )
    {
        char   lar_name_[ 257 ];
        char * lar_name = lar_name_ + 1;
        long   lar_date;
        long   lar_size;
        long   lar_offset;
        char * c;
        char * src;
        char * dest;

        strncpy( lar_name, ar_hdr.ar_name, sizeof( ar_hdr.ar_name ) );

        sscanf( ar_hdr.ar_date, "%ld", &lar_date );
        sscanf( ar_hdr.ar_size, "%ld", &lar_size );

        if ( ar_hdr.ar_name[ 0 ] == '/' )
        {
            if ( ar_hdr.ar_name[ 1 ] == '/' )
            {
                /* This is the "string table" entry of the symbol table, holding
                 * filename strings longer than 15 characters, i.e. those that
                 * do not fit into ar_name.
                 */
                string_table = (char *)BJAM_MALLOC_ATOMIC( lar_size );
                lseek( fd, offset + SARHDR, 0 );
                if ( read( fd, string_table, lar_size ) != lar_size )
                    out_printf("error reading string table\n");
            }
            else if ( string_table && ar_hdr.ar_name[ 1 ] != ' ' )
            {
                /* Long filenames are recognized by "/nnnn" where nnnn is the
                 * offset of the string in the string table represented in ASCII
                 * decimals.
                 */
                dest = lar_name;
                lar_offset = atoi( lar_name + 1 );
                src = &string_table[ lar_offset ];
                while ( *src != '/' )
                    *dest++ = *src++;
                *dest = '/';
            }
        }

        c = lar_name - 1;
        while ( ( *++c != ' ' ) && ( *c != '/' ) );
        *c = '\0';

        if ( DEBUG_BINDSCAN )
            out_printf( "archive name %s found\n", lar_name );

        sprintf( buf, "%s", lar_name );

        if ( strcmp( buf, "") != 0 )
        {
            file_info_t * member = 0;

            archive->members = filelist_push_back( archive->members, object_new( buf ) );
            member = filelist_back( archive->members );
            member->is_file = 1;
            member->is_dir = 0;
            member->exists = 0;
            timestamp_init( &member->time, (time_t)lar_date, 0 );
        }

        offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
        lseek( fd, offset, 0 );
    }

    if ( string_table )
        BJAM_FREE( string_table );

    close( fd );
#endif  /* NO_AR */

    return 0;
}
Beispiel #11
0
void exec_cmd
(
    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 )
    {
        char const * tempdir = path_tmpdir();
        DWORD procID = GetCurrentProcessId();

        /* SVA - allocate 64 bytes extra 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 fail
         * 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 fixed 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 ];
        }

        /* Let the child inherit stdin, as some commands assume it's available. */
        si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);

        /* Save the operation for exec_wait() 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 command we run. */
        {
            char * * argp = argv;
            string_new( &cmd );
            string_copy( &cmd, *(argp++) );
            while ( *argp )
            {
                string_push_back( &cmd, ' ' );
                string_append( &cmd, *(argp++) );
            }
        }

        /* Create output buffers. */
        string_new( &cmdtab[ slot ].buffer_out );
        string_new( &cmdtab[ slot ].buffer_err );

        /* Run the command by creating a sub-process for it. */
        if (
            ! CreateProcess(
                NULL                    ,  /* application name               */
                cmd.value               ,  /* command line                   */
                NULL                    ,  /* process attributes             */
                NULL                    ,  /* thread attributes              */
                TRUE                    ,  /* inherit handles                */
                CREATE_NEW_PROCESS_GROUP,  /* create flags                   */
                NULL                    ,  /* env vars, null inherits env    */
                NULL                    ,  /* current dir, null is our       */
                                           /* current dir                    */
                &si                     ,  /* startup info                   */
                &cmdtab[ slot ].pi         /* child process info, if created */
                )
            )
        {
            perror( "CreateProcess" );
            exit( EXITBAD );
        }

        /* Clean up temporary stuff. */
        string_free( &cmd );
    }

    /* Wait until we are under the limit of concurrent commands. Do not trust
     * globs.jobs alone.
     */
    while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) )
        if ( !exec_wait() )
            break;

    if ( argv != argv_static )
        free_argv( argv );
}
Beispiel #12
0
LIST *
var_expand( 
	LIST	*l,
	char	*in,
	char	*end,
	LOL	*lol,
	int	cancopyin )
{
    char out_buf[ MAXSYM ];
    string buf[1];
    string out1[1]; /* Temporary buffer */
    size_t prefix_length;
    char *out;
    char *inp = in;
    char *ov;		/* for temp copy of variable in outbuf */
    int depth;

    if( DEBUG_VAREXP )
        printf( "expand '%.*s'\n", end - in, in );

    /* This gets alot of cases: $(<) and $(>) */

    if( in[0] == '$' && in[1] == '(' && in[3] == ')' && in[4] == '\0' )
    {
        switch( in[2] )
        {
        case '<':
            return list_copy( l, lol_get( lol, 0 ) );

        case '>':
            return list_copy( l, lol_get( lol, 1 ) );
        
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            return list_copy( l, lol_get( lol, in[2]-'1' ) );
        }
    }
    
    /* Expand @() files, to single item plus accompanying file. */
    
    if ( in[0] == '@' && in[1] == '(' && *(end-1) == ')' )
    {
        /* We try the expansion until it fits within the propspective output buffer. */
        char * at_buf = 0;
        int at_size = MAXJPATH;
        int at_len = 0;
        do
        {
            BJAM_FREE(at_buf);
            at_buf = (char*)BJAM_MALLOC_ATOMIC(at_size + 1);
            at_len = var_string( in, at_buf, at_size, lol );
            at_size *= 2;
        } while ( at_len < 0 && at_size < INT_MAX / 2 );
        /* Return the result as a single item list. */
        if ( at_len > 0 )
        {
            LIST * r;
            string_copy( buf, at_buf );
            r = list_new( l, newstr( buf->value) );
            string_free( buf );
            BJAM_FREE(at_buf);
            return r;
        }
        BJAM_FREE(at_buf);
    }

    /* Just try simple copy of in to out. */

    while( in < end )
        if( *in++ == '$' && *in == '(' ) 
            goto expand;

    /* No variables expanded - just add copy of input string to list. */

    /* Cancopyin is an optimization: if the input was already a list */
    /* item, we can use the copystr() to put it on the new list. */
    /* Otherwise, we use the slower newstr(). */

    if( cancopyin ) 
    {
        return list_new( l, copystr( inp ) );
    }
    else
    {
        LIST* r;
        string_new( buf );
        string_append_range( buf, inp, end );

        r = list_new( l, newstr( buf->value) );
        string_free( buf );
        return r;
    }

expand:
    string_new( buf );
    string_append_range( buf, inp, in - 1); /* copy the part before '$'. */
    /*
     * Input so far (ignore blanks):
     *
     *  stuff-in-outbuf $(variable) remainder
     *                   ^                   ^
     *                   in                  end
     * Output so far:
     *
     *  stuff-in-outbuf $
     *  ^                ^
     *  out_buf          out
     *
     *
     * We just copied the $ of $(...), so back up one on the output.
     * We now find the matching close paren, copying the variable and
     * modifiers between the $( and ) temporarily into out_buf, so that
     * we can replace :'s with MAGIC_COLON.  This is necessary to avoid
     * being confused by modifier values that are variables containing
     * :'s.  Ugly.
     */

    depth = 1;
    inp = ++in; /* skip over the '(' */

    while( in < end && depth )
    {
        switch( *in++ )
        {
        case '(': depth++; break;
        case ')': depth--; break;
        }
    }

    /*
     * Input so far (ignore blanks):
     *
     *  stuff-in-outbuf $(variable) remainder
     *                    ^        ^         ^
     *                    inp      in        end
     */
    prefix_length = buf->size;
    string_append_range( buf, inp, in - 1 );

    out = buf->value + prefix_length;
    for ( ov = out; ov < buf->value + buf->size; ++ov )
    {
        switch( *ov )
        {
        case ':': *ov = MAGIC_COLON; break;
        case '[': *ov = MAGIC_LEFT; break;
        case ']': *ov = MAGIC_RIGHT; break;
        }
    }

    /*
     * Input so far (ignore blanks):
     *
     *  stuff-in-outbuf $(variable) remainder
     *                              ^        ^
     *                              in       end
     * Output so far:
     *
     *  stuff-in-outbuf variable
     *  ^               ^       ^
     *  out_buf         out     ov
     *
     * Later we will overwrite 'variable' in out_buf, but we'll be
     * done with it by then.  'variable' may be a multi-element list, 
     * so may each value for '$(variable element)', and so may 'remainder'.
     * Thus we produce a product of three lists.
     */

    {
        LIST *variables = 0;
        LIST *remainder = 0;
        LIST *vars;

        /* Recursively expand variable name & rest of input */

        if( out < ov )
            variables = var_expand( L0, out, ov, lol, 0 );
        if( in < end )
            remainder = var_expand( L0, in, end, lol, 0 );

        /* Now produce the result chain */

        /* For each variable name */

        for( vars = variables; vars; vars = list_next( vars ) )
        {
            LIST *value, *evalue = 0;
            char *colon;
            char *bracket;
            string variable[1];
            char *varname;
            int sub1 = 0, sub2 = -1;
            VAR_EDITS edits;

            /* Look for a : modifier in the variable name */
            /* Must copy into varname so we can modify it */

            string_copy( variable, vars->string );
            varname = variable->value;

            if( colon = strchr( varname, MAGIC_COLON ) )
            {
                string_truncate( variable, colon - varname );
                var_edit_parse( colon + 1, &edits );
            }

            /* Look for [x-y] subscripting */
            /* sub1 and sub2 are x and y. */

            if ( bracket = strchr( varname, MAGIC_LEFT ) )
            {
                /*
                ** Make all syntax errors in [] subscripting
                ** result in the same behavior: silenty return an empty
                ** expansion (by setting sub2 = 0). Brute force parsing;
                ** May get moved into yacc someday.
                */

                char *s = bracket + 1;

                string_truncate( variable, bracket - varname );

                do  /* so we can use "break" */
                {
                    /* Allow negative indexes. */
                    if (! isdigit( *s ) && ! ( *s == '-') )
                    {
                        sub2 = 0;
                        break;
                    }
                    sub1 = atoi(s);

                    /* Skip over the first symbol, which is either a digit or dash. */
                    s++;
                    while ( isdigit( *s ) ) s++;

                    if ( *s == MAGIC_RIGHT )
                    {
                        sub2 = sub1;
                        break;
                    }

                    if ( *s != '-')
                    {
                        sub2 = 0;
                        break;
                    }

                    s++;

                    if ( *s == MAGIC_RIGHT )
                    {
                        sub2 = -1;
                        break;
                    }

                    if (! isdigit( *s ) && ! ( *s == '-') )
                    {
                        sub2 = 0;
                        break;
                    }

                    /* First, compute the index of the last element. */
                    sub2 = atoi(s);               
                    s++;
                    while ( isdigit( *s ) ) s++;

                    if ( *s != MAGIC_RIGHT)
                        sub2 = 0;

                } while (0);

                /*
                ** Anything but the end of the string, or the colon
                ** introducing a modifier is a syntax error.
                */

                s++;                
                if (*s && *s != MAGIC_COLON)
                    sub2 = 0;

                *bracket = '\0';
            }

            /* Get variable value, specially handling $(<), $(>), $(n) */
		
            if( varname[0] == '<' && !varname[1] )
                value = lol_get( lol, 0 );
            else if( varname[0] == '>' && !varname[1] )
                value = lol_get( lol, 1 );
            else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] )
                value = lol_get( lol, varname[0] - '1' );
            else 
                value = var_get( varname );

            /* Handle negitive indexes: part two. */
            {
                int length = list_length( value );

                if (sub1 < 0)
                    sub1 = length + sub1;
                else
                    sub1 -= 1;

                if (sub2 < 0)
                    sub2 = length + 1 + sub2 - sub1;
                else
                    sub2 -= sub1;
                /*
                ** The "sub2 < 0" test handles the semantic error
                ** of sub2 < sub1.
                */
                if ( sub2 < 0 )
                    sub2 = 0;
            }



            /* The fast path: $(x) - just copy the variable value. */
            /* This is only an optimization */

            if( out == out_buf && !bracket && !colon && in == end )
            {
                string_free( variable );
                l = list_copy( l, value );
                continue;
            }

            /* Handle start subscript */

            while( sub1 > 0 && value )
                --sub1, value = list_next( value );

            /* Empty w/ :E=default? */

            if( !value && colon && edits.empty.ptr )
                evalue = value = list_new( L0, newstr( edits.empty.ptr ) );

            /* For each variable value */

            string_new( out1 );
            for( ; value; value = list_next( value ) )
            {
                LIST *rem;
                size_t postfix_start;

                /* Handle end subscript (length actually) */

                if( sub2 >= 0 && --sub2 < 0 )
                    break;

                string_truncate( buf, prefix_length );

                /* Apply : mods, if present */

                if( colon && edits.filemods )
                    var_edit_file( value->string, out1, &edits );
                else
                    string_append( out1, value->string );

                if( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) )
                    var_edit_shift( out1, &edits );

                /* Handle :J=joinval */
                /* If we have more values for this var, just */
                /* keep appending them (with the join value) */
                /* rather than creating separate LIST elements. */

                if( colon && edits.join.ptr && 
                    ( list_next( value ) || list_next( vars ) ) )
                {
                    string_append( out1, edits.join.ptr );
                    continue;
                }

                string_append( buf, out1->value );
                string_free( out1 );
                string_new( out1 );

                /* If no remainder, append result to output chain. */

                if( in == end )
                {
                    l = list_new( l, newstr( buf->value ) );
                    continue;
                }

                /* For each remainder, append the complete string */
                /* to the output chain. */
                /* Remember the end of the variable expansion so */
                /* we can just tack on each instance of 'remainder' */

                postfix_start = buf->size;

                for( rem = remainder; rem; rem = list_next( rem ) )
                {
                    string_truncate( buf, postfix_start );
                    string_append( buf, rem->string );
                    l = list_new( l, newstr( buf->value ) );
                }
            }
            string_free( out1 );

            /* Toss used empty */

            if( evalue )
                list_free( evalue );

            string_free( variable );
        }

        /* variables & remainder were gifts from var_expand */
        /* and must be freed */

        if( variables )
            list_free( variables );
        if( remainder)
            list_free( remainder );

        if( DEBUG_VAREXP )
        {
            printf( "expanded to " );
            list_print( l );
            printf( "\n" );
        }

        string_free( buf );
        return l;
    }
}