Esempio n. 1
0
/// Implementation of the builtin count command, used to count the number of arguments sent to it.
static int builtin_count(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    UNUSED(parser);
    int argc = 0;

    // Count the newlines coming in via stdin like `wc -l`.
    if (streams.stdin_is_directly_redirected) {
        char buf[COUNT_CHUNK_SIZE];
        while (true) {
            long n = read_blocked(streams.stdin_fd, buf, COUNT_CHUNK_SIZE);
            // Ignore all errors for now.
            if (n <= 0) break;
            for (int i = 0; i < n; i++) {
                if (buf[i] == L'\n') {
                    argc++;
                }
            }
        }
    }

    // Always add the size of argv.
    // That means if you call `something | count a b c`, you'll get the count of something _plus 3_.
    argc += builtin_count_args(argv) - 1;
    streams.out.append_format(L"%d\n", argc);
    return argc == 0 ? STATUS_CMD_ERROR : STATUS_CMD_OK;
}
Esempio n. 2
0
/// Read from descriptors until they are empty.
///
/// \param j the job to test
static void read_try(job_t *j) {
    io_buffer_t *buff = NULL;

    // Find the last buffer, which is the one we want to read from.
    const io_chain_t chain = j->all_io_redirections();
    for (size_t idx = 0; idx < chain.size(); idx++) {
        io_data_t *d = chain.at(idx).get();
        if (d->io_mode == IO_BUFFER) {
            buff = static_cast<io_buffer_t *>(d);
        }
    }

    if (buff) {
        debug(3, L"proc::read_try('%ls')", j->command_wcstr());
        while (1) {
            char b[BUFFER_SIZE];
            long l;

            l = read_blocked(buff->pipe_fd[0], b, BUFFER_SIZE);
            if (l == 0) {
                break;
            } else if (l < 0) {
                if (errno != EAGAIN) {
                    debug(1, _(L"An error occured while reading output from code block"));
                    wperror(L"read_try");
                }
                break;
            } else {
                buff->out_buffer_append(b, l);
            }
        }
    }
}
Esempio n. 3
0
static const wchar_t *string_get_arg_stdin(wcstring *storage, const io_streams_t &streams) {
    std::string arg;
    for (;;) {
        char ch = '\0';
        long rc = read_blocked(streams.stdin_fd, &ch, 1);

        if (rc < 0) {  // failure
            return 0;
        }

        if (rc == 0) {  // EOF
            if (arg.empty()) {
                return 0;
            }
            break;
        }

        if (ch == '\n') {
            break;
        }

        arg += ch;
    }

    *storage = str2wcstring(arg);
    return storage->c_str();
}
Esempio n. 4
0
void io_buffer_t::read() {
    exec_close(pipe_fd[1]);

    if (io_mode == IO_BUFFER) {
        debug(4, L"io_buffer_t::read: blocking read on fd %d", pipe_fd[0]);
        while (1) {
            char b[4096];
            long len = read_blocked(pipe_fd[0], b, 4096);
            if (len == 0) {
                break;
            } else if (len < 0) {
                // exec_read_io_buffer is only called on jobs that have exited, and will therefore
                // never block. But a broken pipe seems to cause some flags to reset, causing the
                // EOF flag to not be set. Therefore, EAGAIN is ignored and we exit anyway.
                if (errno != EAGAIN) {
                    const wchar_t *fmt =
                        _(L"An error occured while reading output from code block on fd %d");
                    debug(1, fmt, pipe_fd[0]);
                    wperror(L"io_buffer_t::read");
                }

                break;
            } else {
                buffer_.append(&b[0], &b[len]);
            }
        }
    }
}
Esempio n. 5
0
void io_buffer_t::read() {
    exec_close(pipe_fd[1]);

    if (io_mode == IO_BUFFER) {
#if 0
        if (fcntl( pipe_fd[0], F_SETFL, 0)) {
            wperror( L"fcntl" );
            return;
        }
#endif
        debug(4, L"io_buffer_t::read: blocking read on fd %d", pipe_fd[0]);
        while (1) {
            char b[4096];
            long l;
            l = read_blocked(pipe_fd[0], b, 4096);
            if (l == 0) {
                break;
            } else if (l < 0) {
                // exec_read_io_buffer is only called on jobs that have exited, and will therefore
                // never block. But a broken pipe seems to cause some flags to reset, causing the
                // EOF flag to not be set. Therefore, EAGAIN is ignored and we exit anyway.
                if (errno != EAGAIN) {
                    debug(1, _(L"An error occured while reading output from code block on file "
                               L"descriptor %d"),
                          pipe_fd[0]);
                    wperror(L"io_buffer_t::read");
                }

                break;
            } else {
                out_buffer_append(b, l);
            }
        }
    }
}
Esempio n. 6
0
/**
   Read from descriptors until they are empty. 

   \param j the job to test
*/
static void read_try( job_t *j )
{
	io_data_t *d, *buff=0;

	/*
	  Find the last buffer, which is the one we want to read from
	*/
	for( d = j->io; d; d=d->next )
	{
		
		if( d->io_mode == IO_BUFFER )
		{
			buff=d;
		}
	}
	
	if( buff )
	{
		debug( 3, L"proc::read_try('%ls')\n", j->command_wcstr() );
		while(1)
		{
			char b[BUFFER_SIZE];
			int l;
			
			l=read_blocked( buff->param1.pipe_fd[0],
					b, BUFFER_SIZE );
			if( l==0 )
			{
				break;
			}
			else if( l<0 )
			{
				if( errno != EAGAIN )
				{
					debug( 1, 
						   _( L"An error occured while reading output from code block" ) );
					wperror( L"read_try" );			
				}				
				break;
			}
			else
			{
                buff->out_buffer_append(b, l);
			}			
		}
	}
}
Esempio n. 7
0
/**
   Internal function used by input_common_readch to read one byte from fd 1. This function should only be called by
   input_common_readch().
*/
static wint_t readb()
{
	unsigned char arr[1];
	int do_loop = 0;
	
	do
	{
		fd_set fd;	
		int fd_max=1;
		int res;
		
		FD_ZERO( &fd );
		FD_SET( 0, &fd );
		if( env_universal_server.fd > 0 )
		{
			FD_SET( env_universal_server.fd, &fd );
			fd_max = env_universal_server.fd+1;
		}
		
		do_loop = 0;			
		
		res = select( fd_max, &fd, 0, 0, 0 );
		if( res==-1 )
		{
			switch( errno )
			{
				case EINTR:
				case EAGAIN:
				{
					if( interrupt_handler )
					{
						int res = interrupt_handler();
						if( res )
						{
							return res;
						}
						if( lookahead_count )
						{
							return lookahead_arr[--lookahead_count];
						}
						
					}
					
					
					do_loop = 1;
					break;
				}
				default:
				{
					/*
					  The terminal has been closed. Save and exit.
					*/
					return R_EOF;
				}
			}	
		}
		else
		{
			if( env_universal_server.fd > 0 )
			{
				if( FD_ISSET( env_universal_server.fd, &fd ) )
				{
					debug( 3, L"Wake up on universal variable event" );					
					env_universal_read_all();
					do_loop = 1;

					if( lookahead_count )
					{
						return lookahead_arr[--lookahead_count];
					}
				}				
			}
			if( FD_ISSET( 0, &fd ) )
			{
				if( read_blocked( 0, arr, 1 ) != 1 )
				{
					/*
					  The teminal has been closed. Save and exit.
					*/
					return R_EOF;
				}
				do_loop = 0;
			}				
		}
	}
	while( do_loop );
	
	return arr[0];
}
Esempio n. 8
0
/// Internal function used by input_common_readch to read one byte from fd 0. This function should
/// only be called by input_common_readch().
static char_event_t readb() {
    // do_loop must be set on every path through the loop; leaving it uninitialized allows the
    // static analyzer to assist in catching mistakes.
    unsigned char arr[1];
    bool do_loop;

    do {
        // Flush callbacks.
        input_flush_callbacks();

        fd_set fdset;
        int fd_max = 0;
        int ioport = iothread_port();
        int res;

        FD_ZERO(&fdset);
        FD_SET(0, &fdset);
        if (ioport > 0) {
            FD_SET(ioport, &fdset);
            fd_max = std::max(fd_max, ioport);
        }

        // Get our uvar notifier.
        universal_notifier_t &notifier = universal_notifier_t::default_notifier();

        // Get the notification fd (possibly none).
        int notifier_fd = notifier.notification_fd();
        if (notifier_fd > 0) {
            FD_SET(notifier_fd, &fdset);
            fd_max = std::max(fd_max, notifier_fd);
        }

        // Get its suggested delay (possibly none).
        struct timeval tv = {};
        const unsigned long usecs_delay = notifier.usec_delay_between_polls();
        if (usecs_delay > 0) {
            unsigned long usecs_per_sec = 1000000;
            tv.tv_sec = (int)(usecs_delay / usecs_per_sec);
            tv.tv_usec = (int)(usecs_delay % usecs_per_sec);
        }

        res = select(fd_max + 1, &fdset, 0, 0, usecs_delay > 0 ? &tv : NULL);
        if (res == -1) {
            if (errno == EINTR || errno == EAGAIN) {
                if (interrupt_handler) {
                    if (auto interrupt_evt = interrupt_handler()) {
                        return *interrupt_evt;
                    } else if (auto mc = lookahead_pop_evt()) {
                        return *mc;
                    }
                }

                do_loop = true;
            } else {
                // The terminal has been closed.
                return char_event_type_t::eof;
            }
        } else {
            // Assume we loop unless we see a character in stdin.
            do_loop = true;

            // Check to see if we want a universal variable barrier.
            bool barrier_from_poll = notifier.poll();
            bool barrier_from_readability = false;
            if (notifier_fd > 0 && FD_ISSET(notifier_fd, &fdset)) {
                barrier_from_readability = notifier.notification_fd_became_readable(notifier_fd);
            }
            if (barrier_from_poll || barrier_from_readability) {
                env_universal_barrier();
            }

            if (ioport > 0 && FD_ISSET(ioport, &fdset)) {
                iothread_service_completion();
                if (auto mc = lookahead_pop_evt()) {
                    return *mc;
                }
            }

            if (FD_ISSET(STDIN_FILENO, &fdset)) {
                if (read_blocked(0, arr, 1) != 1) {
                    // The teminal has been closed.
                    return char_event_type_t::eof;
                }

                // We read from stdin, so don't loop.
                do_loop = false;
            }
        }
    } while (do_loop);

    return arr[0];
}
Esempio n. 9
0
/**
   Internal function used by input_common_readch to read one byte from fd 0. This function should only be called by
   input_common_readch().
*/
static wint_t readb()
{
    /* do_loop must be set on every path through the loop; leaving it uninitialized allows the static analyzer to assist in catching mistakes. */
    unsigned char arr[1];
    bool do_loop;

    do
    {
        /* Flush callbacks */
        input_flush_callbacks();

        fd_set fdset;
        int fd_max = 0;
        int ioport = iothread_port();
        int res;

        FD_ZERO(&fdset);
        FD_SET(0, &fdset);
        if (ioport > 0)
        {
            FD_SET(ioport, &fdset);
            fd_max = maxi(fd_max, ioport);
        }
        
        /* Get our uvar notifier */
        universal_notifier_t &notifier = universal_notifier_t::default_notifier();
        
        /* Get the notification fd (possibly none) */
        int notifier_fd = notifier.notification_fd();
        if (notifier_fd > 0)
        {
            FD_SET(notifier_fd, &fdset);
            fd_max = maxi(fd_max, notifier_fd);
        }
        
        /* Get its suggested delay (possibly none) */
        struct timeval tv = {};
        const unsigned long usecs_delay = notifier.usec_delay_between_polls();
        if (usecs_delay > 0)
        {
            unsigned long usecs_per_sec = 1000000;
            tv.tv_sec = (int)(usecs_delay / usecs_per_sec);
            tv.tv_usec = (int)(usecs_delay % usecs_per_sec);
        }
        
        res = select(fd_max + 1, &fdset, 0, 0, usecs_delay > 0 ? &tv : NULL);
        if (res==-1)
        {
            switch (errno)
            {
                case EINTR:
                case EAGAIN:
                {
                    if (interrupt_handler)
                    {
                        int res = interrupt_handler();
                        if (res)
                        {
                            return res;
                        }
                        if (has_lookahead())
                        {
                            return lookahead_pop();
                        }

                    }


                    do_loop = true;
                    break;
                }
                default:
                {
                    /*
                      The terminal has been closed. Save and exit.
                    */
                    return R_EOF;
                }
            }
        }
        else
        {
            /* Assume we loop unless we see a character in stdin */
            do_loop = true;

            /* Check to see if we want a universal variable barrier */
            bool barrier_from_poll = notifier.poll();
            bool barrier_from_readability = false;
            if (notifier_fd > 0 && FD_ISSET(notifier_fd, &fdset))
            {
                barrier_from_readability = notifier.notification_fd_became_readable(notifier_fd);
            }
            if (barrier_from_poll || barrier_from_readability)
            {
                env_universal_barrier();
            }

            if (ioport > 0 && FD_ISSET(ioport, &fdset))
            {
                iothread_service_completion();
                if (has_lookahead())
                {
                    return lookahead_pop();
                }
            }

            if (FD_ISSET(STDIN_FILENO, &fdset))
            {
                if (read_blocked(0, arr, 1) != 1)
                {
                    /* The teminal has been closed. Save and exit. */
                    return R_EOF;
                }

                /* We read from stdin, so don't loop */
                do_loop = false;
            }
        }
    }
    while (do_loop);

    return arr[0];
}