Move io redirection functions to their own library

darcs-hash:20051008112051-ac50b-113caa4cba470a739e4bfbed9f479e2fed357be7.gz
This commit is contained in:
axel 2005-10-08 21:20:51 +10:00
parent 93eed7bc35
commit 9ae7fa5831
9 changed files with 347 additions and 299 deletions

View file

@ -52,7 +52,7 @@ COMMON_OBJS := function.o builtin.o common.o complete.o env.o exec.o \
expand.o highlight.o history.o kill.o parser.o proc.o reader.o \ expand.o highlight.o history.o kill.o parser.o proc.o reader.o \
sanity.o tokenizer.o util.o wildcard.o wgetopt.o wutil.o input.o \ sanity.o tokenizer.o util.o wildcard.o wgetopt.o wutil.o input.o \
output.o intern.o env_universal.o env_universal_common.o \ output.o intern.o env_universal.o env_universal_common.o \
input_common.o event.o signal.o input_common.o event.o signal.o io.o
# builtin_help.h exists, but builtin_help.c is autogenerated # builtin_help.h exists, but builtin_help.c is autogenerated
COMMON_OBJS_WITH_HEADER := builtin_help.o COMMON_OBJS_WITH_HEADER := builtin_help.o

View file

@ -58,6 +58,7 @@
#include "input.h" #include "input.h"
#include "intern.h" #include "intern.h"
#include "event.h" #include "event.h"
#include "signal.h"
/** /**
The default prompt for the read command The default prompt for the read command
@ -2500,8 +2501,6 @@ static int builtin_end( wchar_t **argv )
case FUNCTION_DEF: case FUNCTION_DEF:
{ {
int i;
/** /**
Copy the text from the beginning of the function Copy the text from the beginning of the function
until the end command and use as the new definition until the end command and use as the new definition

172
exec.c
View file

@ -34,6 +34,7 @@
#include "wildcard.h" #include "wildcard.h"
#include "sanity.h" #include "sanity.h"
#include "expand.h" #include "expand.h"
#include "signal.h"
#include "env_universal.h" #include "env_universal.h"
/** /**
@ -52,10 +53,6 @@ pid_t getpgid( pid_t pid );
file redirection error message file redirection error message
*/ */
#define FILE_ERROR L"An error occurred while redirecting file '%ls'" #define FILE_ERROR L"An error occurred while redirecting file '%ls'"
/**
pipe redirection error message
*/
#define PIPE_ERROR L"An error occurred while setting up pipe"
/** /**
fork error message fork error message
*/ */
@ -68,11 +65,7 @@ pid_t getpgid( pid_t pid );
*/ */
array_list_t *open_fds=0; array_list_t *open_fds=0;
/** void exec_close( int fd )
Loops over close until thesyscall was run without beeing
interrupted. Thenremoves the fd from the open_fds list.
*/
static void close_loop( int fd )
{ {
int i; int i;
@ -105,13 +98,19 @@ static void close_loop( int fd )
} }
/** int exec_pipe( int fd[2])
Call pipe(), and add resulting fds to open_fds, the list of opend
file descriptors for pipes.
*/
static int internal_pipe( int fd[2])
{ {
int res = pipe( fd ); int res;
while( ( res=pipe( fd ) ) )
{
if( errno != EINTR )
{
wperror(L"pipe");
return res;
}
}
if( open_fds == 0 ) if( open_fds == 0 )
{ {
open_fds = malloc( sizeof( array_list_t ) ); open_fds = malloc( sizeof( array_list_t ) );
@ -172,7 +171,7 @@ static void close_unused_internal_pipes( io_data_t *io )
if( !use_fd_in_pipe( n, io) ) if( !use_fd_in_pipe( n, io) )
{ {
debug( 4, L"Close fd %d, used in other context", n ); debug( 4, L"Close fd %d, used in other context", n );
close_loop( n ); exec_close( n );
i--; i--;
} }
} }
@ -237,7 +236,7 @@ static void handle_child_io( io_data_t *io )
close_unused_internal_pipes( io ); close_unused_internal_pipes( io );
if( env_universal_server.fd >= 0 ) if( env_universal_server.fd >= 0 )
close_loop( env_universal_server.fd ); exec_close( env_universal_server.fd );
for( ; io; io=io->next ) for( ; io; io=io->next )
{ {
@ -296,7 +295,7 @@ static void handle_child_io( io_data_t *io )
wperror( L"dup2" ); wperror( L"dup2" );
exit(1); exit(1);
} }
close_loop( tmp ); exec_close( tmp );
} }
break; break;
case IO_FD: case IO_FD:
@ -337,11 +336,11 @@ static void handle_child_io( io_data_t *io )
if( fd_to_dup != 0 ) if( fd_to_dup != 0 )
{ {
close_loop( io->pipe_fd[0]); exec_close( io->pipe_fd[0]);
close_loop( io->pipe_fd[1]); exec_close( io->pipe_fd[1]);
} }
else else
close_loop( io->pipe_fd[0] ); exec_close( io->pipe_fd[0] );
/* /*
if( close( io[i].pipe_fd[ io->fd ] ) == -1 ) if( close( io[i].pipe_fd[ io->fd ] ) == -1 )
@ -438,109 +437,6 @@ static int has_fd( io_data_t *d, int fd )
} }
/**
Read from descriptors until they are empty.
*/
void exec_read_io_buffer( io_data_t *d )
{
close_loop(d->pipe_fd[1] );
if( d->io_mode == IO_BUFFER )
{
if( fcntl( d->pipe_fd[0], F_SETFL, 0 ) )
{
wperror( L"fcntl" );
return;
}
debug( 4, L"exec_read_io_buffer: blocking read on fd %d", d->pipe_fd[0] );
while(1)
{
char b[4096];
int l;
l=read_blocked( d->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 fd %d",
d->pipe_fd[0] );
wperror( L"exec_read_io_buffer" );
}
break;
}
else
{
b_append( d->out_buffer, b, l );
}
}
}
}
io_data_t *exec_make_io_buffer()
{
io_data_t *buffer_redirect = malloc( sizeof( io_data_t ));
buffer_redirect->io_mode=IO_BUFFER;
buffer_redirect->next=0;
buffer_redirect->out_buffer= malloc( sizeof(buffer_t));
b_init( buffer_redirect->out_buffer );
buffer_redirect->fd=1;
if( internal_pipe( buffer_redirect->pipe_fd ) == -1 )
{
debug( 1, PIPE_ERROR );
wperror (L"pipe");
free( buffer_redirect->out_buffer );
free( buffer_redirect );
return 0;
}
else if( fcntl( buffer_redirect->pipe_fd[0],
F_SETFL,
O_NONBLOCK ) )
{
debug( 1, PIPE_ERROR );
wperror( L"fcntl" );
free( buffer_redirect->out_buffer );
free( buffer_redirect );
return 0;
}
return buffer_redirect;
}
void exec_free_io_buffer( io_data_t *io_buffer )
{
close_loop( io_buffer->pipe_fd[0] );
/*
Dont free fd for writing. This should already be free'd before
calling exec_read_io_buffer on the buffer
*/
b_destroy( io_buffer->out_buffer );
free( io_buffer->out_buffer );
free( io_buffer );
}
/** /**
Make a copy of the specified io redirection chain, but change file redirection into fd redirection. Make a copy of the specified io redirection chain, but change file redirection into fd redirection.
*/ */
@ -612,7 +508,7 @@ static void io_untransmogrify( io_data_t * in, io_data_t *out )
switch( in->io_mode ) switch( in->io_mode )
{ {
case IO_FILE: case IO_FILE:
close_loop( out->old_fd ); exec_close( out->old_fd );
break; break;
} }
free(out); free(out);
@ -846,7 +742,7 @@ void exec( job_t *j )
if (p->next) if (p->next)
{ {
if (internal_pipe( mypipe ) == -1) if (exec_pipe( mypipe ) == -1)
{ {
debug( 1, PIPE_ERROR ); debug( 1, PIPE_ERROR );
wperror (L"pipe"); wperror (L"pipe");
@ -911,7 +807,7 @@ void exec( job_t *j )
if( p->next ) if( p->next )
{ {
// fwprintf( stderr, L"Function %ls\n", def ); // fwprintf( stderr, L"Function %ls\n", def );
io_buffer = exec_make_io_buffer(); io_buffer = io_buffer_create();
j->io = io_add( j->io, io_buffer ); j->io = io_add( j->io, io_buffer );
} }
@ -928,7 +824,7 @@ void exec( job_t *j )
if( p->next ) if( p->next )
{ {
// fwprintf( stderr, L"Block %ls\n", p->argv[0] ); // fwprintf( stderr, L"Block %ls\n", p->argv[0] );
io_buffer = exec_make_io_buffer(); io_buffer = io_buffer_create();
j->io = io_add( j->io, io_buffer ); j->io = io_add( j->io, io_buffer );
} }
@ -1034,7 +930,7 @@ void exec( job_t *j )
if( close_stdin ) if( close_stdin )
{ {
// fwprintf( stderr, L"Close builtin_stdin\n" ); // fwprintf( stderr, L"Close builtin_stdin\n" );
close_loop( builtin_stdin ); exec_close( builtin_stdin );
} }
break; break;
} }
@ -1062,9 +958,7 @@ void exec( job_t *j )
j->io = io_remove( j->io, io_buffer ); j->io = io_remove( j->io, io_buffer );
debug( 3, L"exec_read_io_buffer on block '%ls'", p->argv[0] ); io_buffer_read( io_buffer );
exec_read_io_buffer( io_buffer );
if( io_buffer->out_buffer->used != 0 ) if( io_buffer->out_buffer->used != 0 )
{ {
@ -1105,7 +999,7 @@ void exec( job_t *j )
} }
exec_free_io_buffer( io_buffer ); io_buffer_destroy( io_buffer );
io_buffer=0; io_buffer=0;
break; break;
@ -1256,7 +1150,7 @@ void exec( job_t *j )
Close the pipe the current process uses to read from the previous process_t Close the pipe the current process uses to read from the previous process_t
*/ */
if( pipe_read.pipe_fd[0] >= 0 ) if( pipe_read.pipe_fd[0] >= 0 )
close_loop( pipe_read.pipe_fd[0] ); exec_close( pipe_read.pipe_fd[0] );
/* /*
Set up the pipe the next process uses to read from the current process_t Set up the pipe the next process uses to read from the current process_t
*/ */
@ -1269,7 +1163,7 @@ void exec( job_t *j )
*/ */
if( p->next ) if( p->next )
{ {
close_loop(mypipe[1]); exec_close(mypipe[1]);
} }
} }
@ -1309,14 +1203,14 @@ int exec_subshell( const wchar_t *cmd,
} }
is_subshell=1; is_subshell=1;
io_buffer= exec_make_io_buffer(); io_buffer= io_buffer_create();
prev_status = proc_get_last_status(); prev_status = proc_get_last_status();
eval( cmd, io_buffer, SUBST ); eval( cmd, io_buffer, SUBST );
debug( 4, L"exec_read_io_buffer on cmdsub '%ls'", cmd ); debug( 4, L"exec_read_io_buffer on cmdsub '%ls'", cmd );
exec_read_io_buffer( io_buffer ); io_buffer_read( io_buffer );
status = proc_get_last_status(); status = proc_get_last_status();
proc_set_last_status( prev_status ); proc_set_last_status( prev_status );
@ -1341,7 +1235,7 @@ int exec_subshell( const wchar_t *cmd,
if( el ) if( el )
al_push( l, el ); al_push( l, el );
} }
exec_free_io_buffer( io_buffer ); io_buffer_destroy( io_buffer );
return status; return status;
@ -1359,6 +1253,6 @@ int exec_subshell( const wchar_t *cmd,
} }
} }
exec_free_io_buffer( io_buffer ); io_buffer_destroy( io_buffer );
return status; return status;
} }

19
exec.h
View file

@ -10,6 +10,11 @@
#include "proc.h" #include "proc.h"
#include "util.h" #include "util.h"
/**
pipe redirection error message
*/
#define PIPE_ERROR L"An error occurred while setting up pipe"
/** /**
Initialize the exec library Initialize the exec library
*/ */
@ -57,19 +62,17 @@ void exec( job_t *j );
int exec_subshell( const wchar_t *cmd, int exec_subshell( const wchar_t *cmd,
array_list_t *l ); array_list_t *l );
/**
Free all resources used by a IO_BUFFER type io redirection.
*/
void exec_free_io_buffer( io_data_t *io_buffer );
/** /**
Create a IO_BUFFER type io redirection. Loops over close until thesyscall was run without beeing
interrupted. Thenremoves the fd from the open_fds list.
*/ */
io_data_t *exec_make_io_buffer(); void exec_close( int fd );
/** /**
Close writing end of IO_BUFFER type io redirection, and fully read the reading end. Call pipe(), and add resulting fds to open_fds, the list of opend
file descriptors for pipes.
*/ */
void exec_read_io_buffer( io_data_t *d ); int exec_pipe( int fd[2]);
#endif #endif

209
io.c Normal file
View file

@ -0,0 +1,209 @@
/** \file io.c
Utilities for io redirection.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#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
#include <term.h>
#include "util.h"
#include "wutil.h"
#include "exec.h"
#include "common.h"
#include "io.h"
void io_buffer_read( io_data_t *d )
{
exec_close(d->pipe_fd[1] );
if( d->io_mode == IO_BUFFER )
{
if( fcntl( d->pipe_fd[0], F_SETFL, 0 ) )
{
wperror( L"fcntl" );
return;
}
debug( 4, L"exec_read_io_buffer: blocking read on fd %d", d->pipe_fd[0] );
while(1)
{
char b[4096];
int l;
l=read_blocked( d->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 fd %d",
d->pipe_fd[0] );
wperror( L"exec_read_io_buffer" );
}
break;
}
else
{
b_append( d->out_buffer, b, l );
}
}
}
}
io_data_t *io_buffer_create()
{
io_data_t *buffer_redirect = malloc( sizeof( io_data_t ));
buffer_redirect->io_mode=IO_BUFFER;
buffer_redirect->next=0;
buffer_redirect->out_buffer= malloc( sizeof(buffer_t));
b_init( buffer_redirect->out_buffer );
buffer_redirect->fd=1;
if( exec_pipe( buffer_redirect->pipe_fd ) == -1 )
{
debug( 1, PIPE_ERROR );
wperror (L"pipe");
free( buffer_redirect->out_buffer );
free( buffer_redirect );
return 0;
}
else if( fcntl( buffer_redirect->pipe_fd[0],
F_SETFL,
O_NONBLOCK ) )
{
debug( 1, PIPE_ERROR );
wperror( L"fcntl" );
free( buffer_redirect->out_buffer );
free( buffer_redirect );
return 0;
}
return buffer_redirect;
}
void io_buffer_destroy( io_data_t *io_buffer )
{
exec_close( io_buffer->pipe_fd[0] );
/*
Dont free fd for writing. This should already be free'd before
calling exec_read_io_buffer on the buffer
*/
b_destroy( io_buffer->out_buffer );
free( io_buffer->out_buffer );
free( io_buffer );
}
io_data_t *io_add( io_data_t *list, io_data_t *element )
{
io_data_t *curr = list;
if( curr == 0 )
return element;
while( curr->next != 0 )
curr = curr->next;
curr->next = element;
return list;
}
io_data_t *io_remove( io_data_t *list, io_data_t *element )
{
io_data_t *curr, *prev=0;
for( curr=list; curr; curr = curr->next )
{
if( element == curr )
{
if( prev == 0 )
{
io_data_t *tmp = element->next;
element->next = 0;
return tmp;
}
else
{
prev->next = element->next;
element->next = 0;
return list;
}
}
prev = curr;
}
return list;
}
io_data_t *io_duplicate( io_data_t *l )
{
io_data_t *res;
if( l == 0 )
return 0;
res = malloc( sizeof( io_data_t) );
if( !res )
{
die_mem();
}
memcpy( res, l, sizeof(io_data_t ));
res->next=io_duplicate( l->next );
return res;
}
io_data_t *io_get( io_data_t *io, int fd )
{
if( io == 0 )
return 0;
io_data_t *res = io_get( io->next, fd );
if( res )
return res;
if( io->fd == fd )
return io;
return 0;
}

87
io.h Normal file
View file

@ -0,0 +1,87 @@
#ifndef FISH_IO_H
#define FISH_IO_H
/**
Describes what type of IO operation an io_data_t represents
*/
enum io_mode
{
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
}
;
/** Represents an FD redirection */
typedef struct io_data
{
/** Type of redirect */
int io_mode;
/** FD to redirect */
int fd;
/** parameter for redirection */
union
{
/** Fds for IO_PIPE and for IO_BUFFER */
int pipe_fd[2];
/** Filename IO_FILE */
wchar_t *filename;
/** fd to redirect specified fd to, for IO_FD*/
int old_fd;
}
;
union
{
/** file creation flags to send to open for IO_FILE */
int flags;
/** buffer to save output in for IO_BUFFER */
buffer_t *out_buffer;
/** Whether to close old_fd for IO_FD */
int close_old;
}
;
/** Pointer to the next IO redirection */
struct io_data *next;
}
io_data_t;
/**
Join two chains of io redirections
*/
io_data_t *io_add( io_data_t *first_chain, io_data_t *decond_chain );
/**
Remove the specified io redirection from the chain
*/
io_data_t *io_remove( io_data_t *list, io_data_t *element );
/**
Make a copy of the specified chain of redirections
*/
io_data_t *io_duplicate( io_data_t *l );
/**
Return the last io redirection in ht e chain for the specified file descriptor.
*/
io_data_t *io_get( io_data_t *io, int fd );
/**
Free all resources used by a IO_BUFFER type io redirection.
*/
void io_buffer_destroy( io_data_t *io_buffer );
/**
Create a IO_BUFFER type io redirection, complete with a pipe and a
buffer_t for output.
*/
io_data_t *io_buffer_create();
/**
Close output pipe, and read from input pipe until eof.
*/
void io_buffer_read( io_data_t *d );
#endif

81
proc.c
View file

@ -74,77 +74,6 @@ int is_event=0;
int proc_had_barrier; int proc_had_barrier;
pid_t proc_last_bg_pid = 0; pid_t proc_last_bg_pid = 0;
io_data_t *io_add( io_data_t *list, io_data_t *element )
{
io_data_t *curr = list;
if( curr == 0 )
return element;
while( curr->next != 0 )
curr = curr->next;
curr->next = element;
return list;
}
io_data_t *io_remove( io_data_t *list, io_data_t *element )
{
io_data_t *curr, *prev=0;
for( curr=list; curr; curr = curr->next )
{
if( element == curr )
{
if( prev == 0 )
{
io_data_t *tmp = element->next;
element->next = 0;
return tmp;
}
else
{
prev->next = element->next;
element->next = 0;
return list;
}
}
prev = curr;
}
return list;
}
io_data_t *io_duplicate( io_data_t *l )
{
io_data_t *res;
if( l == 0 )
return 0;
res = malloc( sizeof( io_data_t) );
if( !res )
{
die_mem();
}
memcpy( res, l, sizeof(io_data_t ));
res->next=io_duplicate( l->next );
return res;
}
io_data_t *io_get( io_data_t *io, int fd )
{
if( io == 0 )
return 0;
io_data_t *res = io_get( io->next, fd );
if( res )
return res;
if( io->fd == fd )
return io;
return 0;
}
/** /**
Recursively free a process and those following it Recursively free a process and those following it
@ -368,7 +297,6 @@ static void mark_process_status( job_t *j,
else else
{ {
p->completed = 1; p->completed = 1;
// fwprintf( stderr, L"Proc %d (%ls) exited\n", p->pid, p->actual_cmd );
if (( !WIFEXITED( status ) ) && if (( !WIFEXITED( status ) ) &&
(! WIFSIGNALED( status )) ) (! WIFSIGNALED( status )) )
@ -743,15 +671,6 @@ static int select_try( job_t *j )
int maxfd=-1; int maxfd=-1;
io_data_t *d; io_data_t *d;
/* if( j->stop_reading )
{
sleep(1);
return;
}
*/
FD_ZERO(&fds); FD_ZERO(&fds);
for( d = j->io; d; d=d->next ) for( d = j->io; d; d=d->next )

67
proc.h
View file

@ -16,15 +16,8 @@
#include <unistd.h> #include <unistd.h>
#include "util.h" #include "util.h"
#include "io.h"
/**
Describes what type of IO operation an io_data_t represents
*/
enum io_mode
{
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
}
;
/** /**
Types of internal processes Types of internal processes
@ -40,44 +33,8 @@ enum
; ;
/** Represents an FD redirection */
typedef struct io_data
{
/** Type of redirect */
int io_mode;
/** FD to redirect */
int fd;
/** parameter for redirection */
union
{
/** Fds for IO_PIPE and for IO_BUFFER */
int pipe_fd[2];
/** Filename IO_FILE */
wchar_t *filename;
/** fd to redirect specified fd to, for IO_FD*/
int old_fd;
}
;
union
{
/** file creation flags to send to open for IO_FILE */
int flags;
/** buffer to save output in for IO_BUFFER */
buffer_t *out_buffer;
/** Whether to close old_fd for IO_FD */
int close_old;
}
;
/** Pointer to the next IO redirection */
struct io_data *next;
}
io_data_t;
/** /**
A structore representing a single process. Contains variables for A structure representing a single process. Contains variables for
tracking process state and the process argument list. tracking process state and the process argument list.
*/ */
typedef struct process{ typedef struct process{
@ -177,26 +134,6 @@ extern int proc_had_barrier;
extern pid_t proc_last_bg_pid; extern pid_t proc_last_bg_pid;
/**
Join two chains of io redirections
*/
io_data_t *io_add( io_data_t *first_chain, io_data_t *decond_chain );
/**
Remove the specified io redirection from the chain
*/
io_data_t *io_remove( io_data_t *list, io_data_t *element );
/**
Make a copy of the specified chain of redirections
*/
io_data_t *io_duplicate( io_data_t *l );
/**
Return the last io redirection in ht e chain for the specified file descriptor.
*/
io_data_t *io_get( io_data_t *io, int fd );
/** /**
Sets the status of the last process to exit Sets the status of the last process to exit
*/ */

View file

@ -1260,12 +1260,12 @@ static void run_pager( wchar_t *prefix, int is_quoted, array_list_t *comp )
term_donate(); term_donate();
io_data_t *out = exec_make_io_buffer(); io_data_t *out = io_buffer_create();
eval( (wchar_t *)cmd.buff, out, TOP); eval( (wchar_t *)cmd.buff, out, TOP);
term_steal(); term_steal();
exec_read_io_buffer( out ); io_buffer_read( out );
sb_destroy( &cmd ); sb_destroy( &cmd );
@ -1285,7 +1285,7 @@ static void run_pager( wchar_t *prefix, int is_quoted, array_list_t *comp )
free( str ); free( str );
} }
exec_free_io_buffer( out); io_buffer_destroy( out);
} }