2005-10-08 21:20:51 +10:00
/** \file io.c
Utilities for io redirection .
2012-11-18 11:23:22 +01:00
2005-10-08 21:20:51 +10:00
*/
# include "config.h"
2006-02-28 23:17:16 +10:00
2005-10-08 21:20:51 +10:00
# include <stdlib.h>
# include <stdio.h>
# include <wchar.h>
# include <string.h>
# include <errno.h>
# include <sys/types.h>
2012-08-15 00:57:56 -07:00
# include <set>
# include <algorithm>
2006-08-10 08:53:38 +10:00
# ifdef HAVE_SYS_TERMIOS_H
# include <sys/termios.h>
# endif
# ifdef HAVE_SYS_IOCTL_H
2005-10-08 21:20:51 +10:00
# include <sys/ioctl.h>
2006-08-10 08:53:38 +10:00
# endif
2005-10-08 21:20:51 +10:00
# include <unistd.h>
# include <fcntl.h>
# if HAVE_NCURSES_H
# include <ncurses.h>
# else
# include <curses.h>
# endif
# if HAVE_TERMIO_H
# include <termio.h>
# endif
2006-01-19 22:22:07 +10:00
# if HAVE_TERM_H
2005-10-08 21:20:51 +10:00
# include <term.h>
2006-01-19 22:22:07 +10:00
# elif HAVE_NCURSES_TERM_H
# include <ncurses/term.h>
# endif
2005-10-08 21:20:51 +10:00
2006-02-28 23:17:16 +10:00
# include "fallback.h"
2005-10-08 21:20:51 +10:00
# include "util.h"
2006-02-28 23:17:16 +10:00
2005-10-08 21:20:51 +10:00
# include "wutil.h"
# include "exec.h"
# include "common.h"
# include "io.h"
2006-07-20 08:55:49 +10:00
2005-10-08 21:20:51 +10:00
2012-11-18 16:30:30 -08:00
void io_buffer_read ( io_data_t * d )
2005-10-08 21:20:51 +10:00
{
2012-11-18 16:30:30 -08:00
exec_close ( d - > param1 . pipe_fd [ 1 ] ) ;
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
if ( d - > io_mode = = IO_BUFFER )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
/* if( fcntl( d->param1.pipe_fd[0], F_SETFL, 0 ) )
{
wperror ( L " fcntl " ) ;
return ;
} */
debug ( 4 , L " io_buffer_read: blocking read on fd %d " , d - > param1 . pipe_fd [ 0 ] ) ;
while ( 1 )
2012-11-18 11:23:22 +01:00
{
2012-11-18 16:30:30 -08:00
char b [ 4096 ] ;
long l ;
l = read_blocked ( d - > param1 . 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 descriptor %d " ) ,
d - > param1 . pipe_fd [ 0 ] ) ;
wperror ( L " io_buffer_read " ) ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
break ;
}
else
{
d - > out_buffer_append ( b , l ) ;
}
}
2012-11-18 11:23:22 +01:00
}
2005-10-08 21:20:51 +10:00
}
2012-11-18 16:30:30 -08:00
io_data_t * io_buffer_create ( bool is_input )
2005-10-08 21:20:51 +10:00
{
2012-08-15 00:57:56 -07:00
bool success = true ;
2012-11-18 16:30:30 -08:00
io_data_t * buffer_redirect = new io_data_t ;
buffer_redirect - > out_buffer_create ( ) ;
buffer_redirect - > io_mode = IO_BUFFER ;
buffer_redirect - > is_input = is_input ? true : false ;
buffer_redirect - > fd = is_input ? 0 : 1 ;
if ( exec_pipe ( buffer_redirect - > param1 . pipe_fd ) = = - 1 )
{
debug ( 1 , PIPE_ERROR ) ;
wperror ( L " pipe " ) ;
success = false ;
}
else if ( fcntl ( buffer_redirect - > param1 . pipe_fd [ 0 ] ,
F_SETFL ,
O_NONBLOCK ) )
{
debug ( 1 , PIPE_ERROR ) ;
wperror ( L " fcntl " ) ;
success = false ;
}
2012-11-18 11:23:22 +01:00
2012-08-15 00:57:56 -07:00
if ( ! success )
{
delete buffer_redirect ;
buffer_redirect = NULL ;
}
2012-11-18 11:23:22 +01:00
2012-11-18 16:30:30 -08:00
return buffer_redirect ;
2005-10-08 21:20:51 +10:00
}
2012-12-31 23:54:17 +08:00
void io_buffer_destroy ( shared_ptr < io_data_t > io_buffer )
2005-10-08 21:20:51 +10:00
{
2006-11-12 22:16:13 +10:00
2012-11-18 16:30:30 -08:00
/**
If this is an input buffer , then io_read_buffer will not have
been called , and we need to close the output fd as well .
*/
if ( io_buffer - > is_input )
{
exec_close ( io_buffer - > param1 . pipe_fd [ 1 ] ) ;
}
exec_close ( io_buffer - > param1 . pipe_fd [ 0 ] ) ;
/*
Dont free fd for writing . This should already be free ' d before
calling exec_read_io_buffer on the buffer
*/
2005-10-08 21:20:51 +10:00
}
2012-12-31 23:54:17 +08:00
void io_chain_t : : remove ( shared_ptr < const io_data_t > element )
2012-08-15 00:57:56 -07:00
{
// See if you can guess why std::find doesn't work here
for ( io_chain_t : : iterator iter = this - > begin ( ) ; iter ! = this - > end ( ) ; + + iter )
{
if ( * iter = = element )
{
this - > erase ( iter ) ;
break ;
}
}
}
2005-10-08 21:20:51 +10:00
2012-08-15 00:57:56 -07:00
io_chain_t io_chain_t : : duplicate ( ) const
{
io_chain_t result ;
result . reserve ( this - > size ( ) ) ;
for ( io_chain_t : : const_iterator iter = this - > begin ( ) ; iter ! = this - > end ( ) ; iter + + )
{
2013-01-01 00:37:50 +08:00
result . push_back ( * iter ) ;
2012-08-15 00:57:56 -07:00
}
return result ;
}
2005-10-08 21:20:51 +10:00
2012-08-19 14:09:39 -07:00
void io_chain_t : : duplicate_prepend ( const io_chain_t & src )
2005-10-08 21:20:51 +10:00
{
2012-12-31 23:54:17 +08:00
/* Prepend a duplicate of src before this. Start by inserting a bunch of empty shared_ptr's (so we only have to reallocate once) and then replace them. */
this - > insert ( this - > begin ( ) , src . size ( ) , shared_ptr < io_data_t > ( ) ) ;
2012-08-15 00:57:56 -07:00
for ( size_t idx = 0 ; idx < src . size ( ) ; idx + + )
{
2013-01-01 00:37:50 +08:00
this - > at ( idx ) = src . at ( idx ) ;
2012-08-15 00:57:56 -07:00
}
2005-10-08 21:20:51 +10:00
}
2012-08-15 00:57:56 -07:00
void io_chain_t : : destroy ( )
2005-10-08 21:20:51 +10:00
{
2012-08-15 00:57:56 -07:00
for ( size_t idx = 0 ; idx < this - > size ( ) ; idx + + )
{
2012-12-31 23:54:17 +08:00
this - > at ( idx ) . reset ( ) ;
2012-08-15 00:57:56 -07:00
}
this - > clear ( ) ;
2005-10-08 21:20:51 +10:00
}
2012-12-31 23:54:17 +08:00
void io_remove ( io_chain_t & list , shared_ptr < const io_data_t > element )
2005-10-08 21:20:51 +10:00
{
2012-08-15 00:57:56 -07:00
list . remove ( element ) ;
}
2005-10-08 21:20:51 +10:00
2012-08-15 00:57:56 -07:00
io_chain_t io_duplicate ( const io_chain_t & chain )
{
return chain . duplicate ( ) ;
2005-10-08 21:20:51 +10:00
}
2012-08-15 00:57:56 -07:00
void io_print ( const io_chain_t & chain )
2005-10-08 21:20:51 +10:00
{
2012-08-15 00:57:56 -07:00
if ( chain . empty ( ) )
{
fprintf ( stderr , " Empty chain %p \n " , & chain ) ;
return ;
}
2012-11-18 11:23:22 +01:00
2012-08-15 00:57:56 -07:00
fprintf ( stderr , " Chain %p (%ld items): \n " , & chain , ( long ) chain . size ( ) ) ;
2012-11-18 16:30:30 -08:00
for ( size_t i = 0 ; i < chain . size ( ) ; i + + )
{
2012-12-31 23:54:17 +08:00
shared_ptr < const io_data_t > io = chain . at ( i ) ;
2012-08-15 00:57:56 -07:00
fprintf ( stderr , " \t %lu: fd:%d, input:%s, " , ( unsigned long ) i , io - > fd , io - > is_input ? " yes " : " no " ) ;
switch ( io - > io_mode )
{
2012-11-19 00:31:03 -08:00
case IO_FILE :
fprintf ( stderr , " file (%s) \n " , io - > filename_cstr ) ;
break ;
case IO_PIPE :
fprintf ( stderr , " pipe {%d, %d} \n " , io - > param1 . pipe_fd [ 0 ] , io - > param1 . pipe_fd [ 1 ] ) ;
break ;
case IO_FD :
fprintf ( stderr , " FD map %d -> %d \n " , io - > param1 . old_fd , io - > fd ) ;
break ;
case IO_BUFFER :
fprintf ( stderr , " buffer %p (size %lu) \n " , io - > out_buffer_ptr ( ) , io - > out_buffer_size ( ) ) ;
break ;
case IO_CLOSE :
fprintf ( stderr , " close %d \n " , io - > fd ) ;
break ;
2012-08-15 00:57:56 -07:00
}
}
}
2005-10-08 21:20:51 +10:00
2012-11-18 16:30:30 -08:00
void io_duplicate_prepend ( const io_chain_t & src , io_chain_t & dst )
2012-08-15 00:57:56 -07:00
{
2012-08-19 14:09:39 -07:00
return dst . duplicate_prepend ( src ) ;
2005-10-08 21:20:51 +10:00
}
2012-11-18 11:23:22 +01:00
void io_chain_destroy ( io_chain_t & chain )
2012-08-15 00:57:56 -07:00
{
chain . destroy ( ) ;
}
2006-05-15 08:29:05 +10:00
2012-08-15 00:57:56 -07:00
/* Return the last IO for the given fd */
2012-12-31 23:54:17 +08:00
shared_ptr < const io_data_t > io_chain_t : : get_io_for_fd ( int fd ) const
2005-10-09 21:48:16 +10:00
{
2012-08-15 00:57:56 -07:00
size_t idx = this - > size ( ) ;
while ( idx - - )
{
2012-12-31 23:54:17 +08:00
shared_ptr < const io_data_t > data = this - > at ( idx ) ;
2012-11-18 16:30:30 -08:00
if ( data - > fd = = fd )
{
2012-08-15 00:57:56 -07:00
return data ;
}
}
2012-12-31 23:54:17 +08:00
return shared_ptr < const io_data_t > ( ) ;
2012-08-15 00:57:56 -07:00
}
2005-10-09 21:48:16 +10:00
2012-12-31 23:54:17 +08:00
shared_ptr < io_data_t > io_chain_t : : get_io_for_fd ( int fd )
2012-08-15 00:57:56 -07:00
{
size_t idx = this - > size ( ) ;
while ( idx - - )
{
2012-12-31 23:54:17 +08:00
shared_ptr < io_data_t > data = this - > at ( idx ) ;
2012-11-18 16:30:30 -08:00
if ( data - > fd = = fd )
{
2012-08-15 00:57:56 -07:00
return data ;
}
}
2012-12-31 23:54:17 +08:00
return shared_ptr < io_data_t > ( ) ;
2012-08-15 00:57:56 -07:00
}
/* The old function returned the last match, so we mimic that. */
2012-12-31 23:54:17 +08:00
shared_ptr < const io_data_t > io_chain_get ( const io_chain_t & src , int fd )
2012-08-15 00:57:56 -07:00
{
return src . get_io_for_fd ( fd ) ;
}
2012-12-31 23:54:17 +08:00
shared_ptr < io_data_t > io_chain_get ( io_chain_t & src , int fd )
2012-08-15 00:57:56 -07:00
{
return src . get_io_for_fd ( fd ) ;
}
2012-12-31 23:54:17 +08:00
io_chain_t : : io_chain_t ( shared_ptr < io_data_t > data ) :
std : : vector < shared_ptr < io_data_t > > ( 1 , data )
2012-08-15 00:57:56 -07:00
{
}
2012-12-31 23:54:17 +08:00
io_chain_t : : io_chain_t ( ) : std : : vector < shared_ptr < io_data_t > > ( )
2012-08-15 00:57:56 -07:00
{
2005-10-09 21:48:16 +10:00
}