Fix for various redirection problems

darcs-hash:20050923131031-ac50b-b9e2897e7f20a087260f97d1342deaed65ad7d70.gz
This commit is contained in:
axel 2005-09-23 23:10:31 +10:00
parent f971e02256
commit 77c7a026ee
9 changed files with 232 additions and 230 deletions

View file

@ -1,3 +1,8 @@
2005-09-22 Axel Liljencrantz <axel@liljencrantz.se>
* env_universal.c, env_universal_common.c, env.c, fishd.c, builtin_set.c, exec.c, init/fish_interactive.fish: Exportable universal variables
2005-09-20 Axel Liljencrantz <axel@liljencrantz.se> 2005-09-20 Axel Liljencrantz <axel@liljencrantz.se>
* exec.c, reader.c (exec_read_io_buffer, run_pager): Don't leak file descriptors when showing completion pager * exec.c, reader.c (exec_read_io_buffer, run_pager): Don't leak file descriptors when showing completion pager

2
env.c
View file

@ -42,7 +42,7 @@
/** /**
Command used to start fishd Command used to start fishd
*/ */
#define FISHD_CMD L"if which fishd >/dev/null ^/dev/null; fishd ^/tmp/fish.%s.log; end" #define FISHD_CMD L"fishd ^/tmp/fish.%s.log"
/** /**
At init, we read all the environment variables from this array At init, we read all the environment variables from this array

View file

@ -234,8 +234,10 @@ int env_universal_read_all()
init = 1; init = 1;
if( env_universal_server.fd >= 0 ) if( env_universal_server.fd >= 0 )
{
env_universal_barrier(); env_universal_barrier();
} }
}
if( env_universal_server.fd != -1 ) if( env_universal_server.fd != -1 )
{ {
@ -252,7 +254,6 @@ int env_universal_read_all()
wchar_t *env_universal_get( const wchar_t *name ) wchar_t *env_universal_get( const wchar_t *name )
{ {
debug( 3, L"env_universal_get( %ls )", name );
if( !init) if( !init)
return 0; return 0;

View file

@ -313,7 +313,7 @@ int try_send( message_t *msg,
default: default:
debug( 1, debug( 1,
L"Error while sending message to fd %d. Closing connection", L"Error while sending universal variable message to fd %d. Closing connection",
fd ); fd );
wperror( L"write" ); wperror( L"write" );
@ -348,8 +348,6 @@ void try_send_all( connection_t *c )
return; return;
case -1: case -1:
debug( 1,
L"Socket dead!!!" );
c->killme = 1; c->killme = 1;
return; return;
} }

125
exec.c
View file

@ -61,6 +61,20 @@ pid_t getpgid( pid_t pid );
*/ */
#define FORK_ERROR L"Could not create child process - exiting" #define FORK_ERROR L"Could not create child process - exiting"
static void close_loop( int fd )
{
while( close(fd) == -1 )
{
if( errno != EINTR )
{
debug( 1, FD_ERROR, fd );
wperror( L"close" );
}
}
}
/** /**
Make sure the fd used by this redirection is not used by i.e. a pipe. Make sure the fd used by this redirection is not used by i.e. a pipe.
*/ */
@ -102,7 +116,7 @@ static void handle_child_io( io_data_t *io )
{ {
if( env_universal_server.fd >= 0 ) if( env_universal_server.fd >= 0 )
close( env_universal_server.fd ); close_loop( env_universal_server.fd );
for( ; io; io=io->next ) for( ; io; io=io->next )
{ {
@ -122,8 +136,11 @@ static void handle_child_io( io_data_t *io )
} }
if( close(io->fd) == -1 ) while( close(io->fd) == -1 )
{ {
if( errno != EINTR )
break;
/* debug( 1, /* debug( 1,
FD_ERROR, FD_ERROR,
io->fd ); io->fd );
@ -155,14 +172,7 @@ static void handle_child_io( io_data_t *io )
wperror( L"dup2" ); wperror( L"dup2" );
exit(1); exit(1);
} }
if( close( tmp ) == -1 ) close_loop( tmp );
{
debug( 1,
FD_ERROR,
io->fd );
wperror( L"close" );
exit(1);
}
} }
break; break;
case IO_FD: case IO_FD:
@ -203,11 +213,11 @@ static void handle_child_io( io_data_t *io )
if( fd_to_dup ) if( fd_to_dup )
{ {
close( io->pipe_fd[0]); close_loop( io->pipe_fd[0]);
close( io->pipe_fd[1]); close_loop( io->pipe_fd[1]);
} }
else else
close( io->pipe_fd[fd_to_dup] ); close_loop( io->pipe_fd[fd_to_dup] );
/* /*
if( close( io[i].pipe_fd[ io->fd ] ) == -1 ) if( close( io[i].pipe_fd[ io->fd ] ) == -1 )
@ -314,21 +324,16 @@ static int has_fd( io_data_t *d, int fd )
void exec_read_io_buffer( io_data_t *d ) void exec_read_io_buffer( io_data_t *d )
{ {
if( close( d->pipe_fd[1] ) == -1 ) close_loop(d->pipe_fd[1] );
{
debug( 1, PIPE_ERROR );
wperror( L"close" );
}
if( d->io_mode == IO_BUFFER ) if( d->io_mode == IO_BUFFER )
{ {
/* if( fcntl( d->pipe_fd[0], F_SETFL, 0 ) )
if( fcntl( d->pipe_fd[0], F_SETFL, 0 ) )
{ {
wperror( L"fcntl" ); wperror( L"fcntl" );
return; return;
} }
*/
debug( 3, L"exec_read_io_buffer: blocking read on fd %d", d->pipe_fd[0] ); debug( 3, L"exec_read_io_buffer: blocking read on fd %d", d->pipe_fd[0] );
while(1) while(1)
@ -341,10 +346,22 @@ void exec_read_io_buffer( io_data_t *d )
break; break;
} }
else if( l<0 ) 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, debug( 1,
L"An error occured while reading output from code block on fd %d", d->pipe_fd[0] ); L"An error occured while reading output from code block on fd %d",
d->pipe_fd[0] );
wperror( L"exec_read_io_buffer" ); wperror( L"exec_read_io_buffer" );
}
break; break;
} }
else else
@ -375,7 +392,9 @@ io_data_t *exec_make_io_buffer()
free( buffer_redirect ); free( buffer_redirect );
return 0; return 0;
} }
else if( fcntl( buffer_redirect->pipe_fd[0], F_SETFL, O_NONBLOCK ) ) else if( fcntl( buffer_redirect->pipe_fd[0],
F_SETFL,
O_NONBLOCK ) )
{ {
debug( 1, PIPE_ERROR ); debug( 1, PIPE_ERROR );
wperror( L"fcntl" ); wperror( L"fcntl" );
@ -388,12 +407,8 @@ io_data_t *exec_make_io_buffer()
void exec_free_io_buffer( io_data_t *io_buffer ) void exec_free_io_buffer( io_data_t *io_buffer )
{ {
if( close( io_buffer->pipe_fd[0] ) == -1)
{
debug( 1, PIPE_ERROR );
wperror( L"close" );
} 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 Dont free fd for writing. This should already be free'd before calling exec_read_io_buffer on the buffer
@ -457,13 +472,6 @@ static io_data_t *io_transmogrify( io_data_t * in )
} }
out->old_fd = fd; out->old_fd = fd;
/*
fwprintf( stderr,
L"Replacing call to redirect %d to file '%ls' with call to redirect to fd %d\n",
in->fd,
in->filename,
fd );
*/
break; break;
} }
} }
@ -484,13 +492,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:
if( close( out->old_fd ) == -1 ) close_loop( out->old_fd );
{
debug( 1,
FILE_ERROR,
in->filename );
wperror( L"close" );
}
break; break;
} }
free(out); free(out);
@ -567,11 +569,6 @@ static void io_print( io_data_t *io )
static int handle_new_child( job_t *j, process_t *p ) static int handle_new_child( job_t *j, process_t *p )
{ {
/*
If we do not output to stdout, builtin IO will not appear.
I have no idea why...
*/
//fwprintf( stdout, L"" );
if(is_interactive && !is_subshell && !is_block) if(is_interactive && !is_subshell && !is_block)
{ {
@ -665,9 +662,7 @@ void exec( job_t *j )
io_data_t *io_buffer =0; io_data_t *io_buffer =0;
// if( j->job_id > 3 ) debug( 3, L"Exec job %ls with id %d", j->command, j->job_id );
debug( 2, L"Exec job %ls with id %d", j->command, j->job_id );
if( j->first_process->type==INTERNAL_EXEC ) if( j->first_process->type==INTERNAL_EXEC )
{ {
@ -694,25 +689,12 @@ void exec( job_t *j )
if( block_io ) if( block_io )
{ {
// fwprintf( stderr, L"Before\n" );
// io_print( j->io );
if( j->io ) if( j->io )
j->io = io_add( io_duplicate(block_io), j->io ); j->io = io_add( io_duplicate(block_io), j->io );
else else
j->io=io_duplicate(block_io); j->io=io_duplicate(block_io);
// fwprintf( stderr, L"After\n" );
// io_print( j->io );
} }
/*
if true;
read foo; read bar; read baz;
end <foo.txt
*/
j->io = io_add( j->io, &pipe_write ); j->io = io_add( j->io, &pipe_write );
for (p = j->first_process; p; p = p->next) for (p = j->first_process; p; p = p->next)
@ -723,11 +705,9 @@ void exec( job_t *j )
if( p->type == EXTERNAL ) if( p->type == EXTERNAL )
env_export_arr( 1 ); env_export_arr( 1 );
/* /*
Set up fd:s that will be used in the pipe Set up fd:s that will be used in the pipe
*/ */
// fwprintf( stderr, L"Create process %ls\n", p->actual_cmd );
if( p == j->first_process->next ) if( p == j->first_process->next )
{ {
@ -924,7 +904,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( builtin_stdin ); close_loop( builtin_stdin );
} }
break; break;
} }
@ -1146,7 +1126,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( pipe_read.pipe_fd[0] ); close_loop( 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
*/ */
@ -1159,15 +1139,11 @@ void exec( job_t *j )
*/ */
if( p->next ) if( p->next )
{ {
if( close(mypipe[1]) != 0 ) close_loop(mypipe[1]);
{
debug( 1, PIPE_ERROR );
wperror( L"close" );
}
} }
} }
// fwprintf( stderr, L"Job is constructedk\n" ); debug( 3, L"Job is constructed" );
j->io = io_remove( j->io, &pipe_read ); j->io = io_remove( j->io, &pipe_read );
j->io = io_remove( j->io, &pipe_write ); j->io = io_remove( j->io, &pipe_write );
@ -1175,10 +1151,7 @@ void exec( job_t *j )
for( tmp = block_io; tmp; tmp=tmp->next ) for( tmp = block_io; tmp; tmp=tmp->next )
j->io = io_remove( j->io, tmp ); j->io = io_remove( j->io, tmp );
// assert( !job_is_stopped(j));
j->constructed = 1; j->constructed = 1;
// ggg( j->command, j->io );
if( !j->fg ) if( !j->fg )
{ {

141
fishd.c
View file

@ -28,20 +28,42 @@ down and save.
#include "wutil.h" #include "wutil.h"
#include "env_universal_common.h" #include "env_universal_common.h"
/**
Maximum length of socket filename
*/
#ifndef UNIX_PATH_MAX #ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX 100 #define UNIX_PATH_MAX 100
#endif #endif
#define GREETING "#Fish universal variable daemon\n#Lines beginning with '#' are ignored\n#Syntax:\n#SET VARNAME:VALUE\n#or\n#ERASE VARNAME\n#Where VALUE is the escaped value of the variable\n#Backslash escapes and \\xxx hexadecimal style escapes are supported\n" /**
#define FILE ".fishd" Small greeting to show that fishd is running
*/
#define GREETING "#Fish universal variable daemon\n"
/**
The name of the save file. The hostname is appended to this.
*/
#define FILE ".fishd."
/**
Maximum length of hostname. Longer hostnames are truncated
*/
#define HOSTNAME_LEN 32
/**
The list of connections to clients
*/
static connection_t *conn; static connection_t *conn;
/**
The socket to accept new clients on
*/
static int sock; static int sock;
/**
int get_socket() Connects to the fish socket
*/
static int get_socket()
{ {
int s, len; int s, len;
struct sockaddr_un local; struct sockaddr_un local;
@ -107,7 +129,10 @@ int get_socket()
return s; return s;
} }
void broadcast( int type, const wchar_t *key, const wchar_t *val ) /**
Event handler. Broadcasts updates to all clients.
*/
static void broadcast( int type, const wchar_t *key, const wchar_t *val )
{ {
connection_t *c; connection_t *c;
message_t *msg; message_t *msg;
@ -136,7 +161,10 @@ void broadcast( int type, const wchar_t *key, const wchar_t *val )
} }
} }
void daemonize() /**
Make program into a creature of the night.
*/
static void daemonize()
{ {
/* /*
Fork, and let parent exit Fork, and let parent exit
@ -178,77 +206,75 @@ void daemonize()
} }
/**
void load() Load or save all variables
*/
void load_or_save( int save)
{ {
struct passwd *pw; struct passwd *pw;
char *name; char *name;
char *dir = getenv( "HOME" ); char *dir = getenv( "HOME" );
char hostname[HOSTNAME_LEN];
connection_t c;
if( !dir ) if( !dir )
{ {
pw = getpwuid( getuid() ); pw = getpwuid( getuid() );
dir = pw->pw_dir; dir = pw->pw_dir;
} }
name = malloc( strlen(dir)+ strlen(FILE)+ 2 ); gethostname( hostname, HOSTNAME_LEN );
name = malloc( strlen(dir)+ strlen(FILE)+ strlen(hostname) + 2 );
strcpy( name, dir ); strcpy( name, dir );
strcat( name, "/" ); strcat( name, "/" );
strcat( name, FILE ); strcat( name, FILE );
strcat( name, hostname );
debug( 1, L"Open file for loading: '%s'", name ); debug( 1, L"Open file for %s: '%s'",
save?"saving":"loading",
connection_t load; name );
load.fd = open( name, O_RDONLY);
c.fd = open( name, save?(O_CREAT | O_TRUNC | O_WRONLY):O_RDONLY, 0600);
free( name ); free( name );
if( load.fd == -1 ) if( c.fd == -1 )
{ {
debug( 0, L"Could not open save file. No previous saves?" ); debug( 1, L"Could not open load/save file. No previous saves?" );
}
debug( 1, L"Load input file on fd %d", load.fd );
sb_init( &load.input );
memset (&load.wstate, '\0', sizeof (mbstate_t));
read_message( &load );
sb_destroy( &load.input );
close( load.fd );
}
void save()
{
struct passwd *pw;
char *name;
char *dir = getenv( "HOME" );
if( !dir )
{
pw = getpwuid( getuid() );
dir = pw->pw_dir;
}
name = malloc( strlen(dir)+ strlen(FILE)+ 2 );
strcpy( name, dir );
strcat( name, "/" );
strcat( name, FILE );
debug( 1, L"Open file for saving: '%s'", name );
connection_t save;
save.fd = open( name, O_CREAT | O_TRUNC | O_WRONLY);
free( name );
if( save.fd == -1 )
{
debug( 0, L"Could not open save file" );
wperror( L"open" ); wperror( L"open" );
exit(1);
} }
debug( 1, L"File open on fd %d'", save.fd ); debug( 1, L"File open on fd %d", c.fd );
q_init( &save.unsent );
enqueue_all( &save ); sb_init( &c.input );
close( save.fd ); memset (&c.wstate, '\0', sizeof (mbstate_t));
q_destroy( &save.unsent ); q_init( &c.unsent );
if( save )
enqueue_all( &c );
else
read_message( &c );
q_destroy( &c.unsent );
sb_destroy( &c.input );
close( c.fd );
} }
static void load()
{
load_or_save(0);
}
static void save()
{
load_or_save(1);
}
/**
Do all sorts of boring initialization.
*/
static void init() static void init()
{ {
program_name=L"fishd"; program_name=L"fishd";
@ -268,6 +294,7 @@ static void init()
load(); load();
} }
int main( int argc, char ** argv ) int main( int argc, char ** argv )
{ {
int child_socket, t; int child_socket, t;
@ -362,7 +389,7 @@ int main( int argc, char ** argv )
won't lose everything on a system crash won't lose everything on a system crash
*/ */
update_count++; update_count++;
if( update_count >= 8 ) if( update_count >= 64 )
{ {
save(); save();
update_count = 0; update_count = 0;

View file

@ -1762,7 +1762,7 @@ static void eval_job( tokenizer *tok )
} }
} }
if( is_subshell ) if( is_subshell || is_block )
job_do_notification(); job_do_notification();
// debug( 2, L"end eval_job()\n" ); // debug( 2, L"end eval_job()\n" );
} }

17
proc.c
View file

@ -946,12 +946,12 @@ static void read_try( job_t *j )
if( buff ) if( buff )
{ {
// fwprintf( stderr, L"proc::read_try('%ls')\n", j->command ); debug( 3, L"proc::read_try('%ls')\n", j->command );
while(1) while(1)
{ {
char b[BUFFER_SIZE]; char b[BUFFER_SIZE];
int l; int l;
//fwprintf( stderr, L"read...\n");
l=read_blocked( buff->pipe_fd[0], b, BUFFER_SIZE ); l=read_blocked( buff->pipe_fd[0], b, BUFFER_SIZE );
if( l==0 ) if( l==0 )
{ {
@ -965,7 +965,6 @@ static void read_try( job_t *j )
L"An error occured while reading output from code block" ); L"An error occured while reading output from code block" );
wperror( L"read_try" ); wperror( L"read_try" );
} }
break; break;
} }
else else
@ -987,7 +986,6 @@ void job_continue (job_t *j, int cont)
first_job = j; first_job = j;
j->notified = 0; j->notified = 0;
// if( is_interactive )
debug( 3, debug( 3,
L"Continue on job %d (%ls), %ls, %ls", L"Continue on job %d (%ls), %ls, %ls",
j->job_id, j->job_id,
@ -1023,7 +1021,6 @@ void job_continue (job_t *j, int cont)
if( cont ) if( cont )
{ {
// fwprintf( stderr, L"tcsetattr\n" );
while( 1 ) while( 1 )
{ {
if( tcsetattr (0, TCSADRAIN, &j->tmodes)) if( tcsetattr (0, TCSADRAIN, &j->tmodes))
@ -1045,7 +1042,6 @@ void job_continue (job_t *j, int cont)
} }
} }
} }
}
/* /*
Send the job a continue signal, if necessary. Send the job a continue signal, if necessary.
@ -1074,9 +1070,6 @@ void job_continue (job_t *j, int cont)
handle the possibility that a signal is dispatched while handle the possibility that a signal is dispatched while
running job_is_stopped(). running job_is_stopped().
*/ */
/*
fwprintf( stderr, L"Wait for %ls (%d)\n", j->command, j->pgid );
*/
while( !quit ) while( !quit )
{ {
do do
@ -1093,7 +1086,6 @@ void job_continue (job_t *j, int cont)
{ {
case 1: case 1:
{ {
debug( 3, L"1" );
read_try( j ); read_try( j );
break; break;
} }
@ -1108,7 +1100,6 @@ void job_continue (job_t *j, int cont)
improvement on my 300 MHz machine) on improvement on my 300 MHz machine) on
short-lived jobs. short-lived jobs.
*/ */
debug( 3, L"-1" );
int status; int status;
pid_t pid = waitpid(-1, &status, WUNTRACED ); pid_t pid = waitpid(-1, &status, WUNTRACED );
if( pid > 0 ) if( pid > 0 )
@ -1121,6 +1112,8 @@ void job_continue (job_t *j, int cont)
} }
} }
}
if( j->fg ) if( j->fg )
{ {
@ -1142,7 +1135,6 @@ void job_continue (job_t *j, int cont)
proc_set_last_status( j->negate?(WEXITSTATUS(p->status)?0:1):WEXITSTATUS(p->status) ); proc_set_last_status( j->negate?(WEXITSTATUS(p->status)?0:1):WEXITSTATUS(p->status) );
} }
} }
} }
/* /*
Put the shell back in the foreground. Put the shell back in the foreground.
@ -1202,7 +1194,6 @@ void job_continue (job_t *j, int cont)
} }
} }
} }
// fwprintf( stderr, L"Job_continue end\n" );
} }
void proc_sanity_check() void proc_sanity_check()

View file

@ -1483,6 +1483,13 @@ static void set_signal_handlers()
sigaction( SIGTTOU, &act, 0); sigaction( SIGTTOU, &act, 0);
sigaction( SIGCHLD, &act, 0); sigaction( SIGCHLD, &act, 0);
/*
Ignore sigpipe, it is generated if fishd dies, but we can
recover.
*/
act.sa_handler=SIG_IGN;
sigaction( SIGPIPE, &act, 0);
if( is_interactive ) if( is_interactive )
{ {