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 \
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 \
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
COMMON_OBJS_WITH_HEADER := builtin_help.o

View file

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

172
exec.c
View file

@ -34,6 +34,7 @@
#include "wildcard.h"
#include "sanity.h"
#include "expand.h"
#include "signal.h"
#include "env_universal.h"
/**
@ -52,10 +53,6 @@ pid_t getpgid( pid_t pid );
file redirection error message
*/
#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
*/
@ -68,11 +65,7 @@ pid_t getpgid( pid_t pid );
*/
array_list_t *open_fds=0;
/**
Loops over close until thesyscall was run without beeing
interrupted. Thenremoves the fd from the open_fds list.
*/
static void close_loop( int fd )
void exec_close( int fd )
{
int i;
@ -105,13 +98,19 @@ static void close_loop( int fd )
}
/**
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 exec_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 )
{
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) )
{
debug( 4, L"Close fd %d, used in other context", n );
close_loop( n );
exec_close( n );
i--;
}
}
@ -237,7 +236,7 @@ static void handle_child_io( io_data_t *io )
close_unused_internal_pipes( io );
if( env_universal_server.fd >= 0 )
close_loop( env_universal_server.fd );
exec_close( env_universal_server.fd );
for( ; io; io=io->next )
{
@ -296,7 +295,7 @@ static void handle_child_io( io_data_t *io )
wperror( L"dup2" );
exit(1);
}
close_loop( tmp );
exec_close( tmp );
}
break;
case IO_FD:
@ -337,11 +336,11 @@ static void handle_child_io( io_data_t *io )
if( fd_to_dup != 0 )
{
close_loop( io->pipe_fd[0]);
close_loop( io->pipe_fd[1]);
exec_close( io->pipe_fd[0]);
exec_close( io->pipe_fd[1]);
}
else
close_loop( io->pipe_fd[0] );
exec_close( io->pipe_fd[0] );
/*
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.
*/
@ -612,7 +508,7 @@ static void io_untransmogrify( io_data_t * in, io_data_t *out )
switch( in->io_mode )
{
case IO_FILE:
close_loop( out->old_fd );
exec_close( out->old_fd );
break;
}
free(out);
@ -846,7 +742,7 @@ void exec( job_t *j )
if (p->next)
{
if (internal_pipe( mypipe ) == -1)
if (exec_pipe( mypipe ) == -1)
{
debug( 1, PIPE_ERROR );
wperror (L"pipe");
@ -911,7 +807,7 @@ void exec( job_t *j )
if( p->next )
{
// 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 );
}
@ -928,7 +824,7 @@ void exec( job_t *j )
if( p->next )
{
// 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 );
}
@ -1034,7 +930,7 @@ void exec( job_t *j )
if( close_stdin )
{
// fwprintf( stderr, L"Close builtin_stdin\n" );
close_loop( builtin_stdin );
exec_close( builtin_stdin );
}
break;
}
@ -1062,9 +958,7 @@ void exec( job_t *j )
j->io = io_remove( j->io, io_buffer );
debug( 3, L"exec_read_io_buffer on block '%ls'", p->argv[0] );
exec_read_io_buffer( io_buffer );
io_buffer_read( io_buffer );
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;
break;
@ -1256,7 +1150,7 @@ void exec( job_t *j )
Close the pipe the current process uses to read from the previous process_t
*/
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
*/
@ -1269,7 +1163,7 @@ void exec( job_t *j )
*/
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;
io_buffer= exec_make_io_buffer();
io_buffer= io_buffer_create();
prev_status = proc_get_last_status();
eval( cmd, io_buffer, SUBST );
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();
proc_set_last_status( prev_status );
@ -1341,7 +1235,7 @@ int exec_subshell( const wchar_t *cmd,
if( el )
al_push( l, el );
}
exec_free_io_buffer( io_buffer );
io_buffer_destroy( io_buffer );
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;
}

19
exec.h
View file

@ -10,6 +10,11 @@
#include "proc.h"
#include "util.h"
/**
pipe redirection error message
*/
#define PIPE_ERROR L"An error occurred while setting up pipe"
/**
Initialize the exec library
*/
@ -57,19 +62,17 @@ void exec( job_t *j );
int exec_subshell( const wchar_t *cmd,
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

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;
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
@ -368,7 +297,6 @@ static void mark_process_status( job_t *j,
else
{
p->completed = 1;
// fwprintf( stderr, L"Proc %d (%ls) exited\n", p->pid, p->actual_cmd );
if (( !WIFEXITED( status ) ) &&
(! WIFSIGNALED( status )) )
@ -743,15 +671,6 @@ static int select_try( job_t *j )
int maxfd=-1;
io_data_t *d;
/* if( j->stop_reading )
{
sleep(1);
return;
}
*/
FD_ZERO(&fds);
for( d = j->io; d; d=d->next )

67
proc.h
View file

@ -16,15 +16,8 @@
#include <unistd.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
@ -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.
*/
typedef struct process{
@ -177,26 +134,6 @@ extern int proc_had_barrier;
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
*/

View file

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