mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Fix for various redirection problems
darcs-hash:20050923131031-ac50b-b9e2897e7f20a087260f97d1342deaed65ad7d70.gz
This commit is contained in:
parent
f971e02256
commit
77c7a026ee
9 changed files with 232 additions and 230 deletions
|
@ -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
2
env.c
|
@ -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
|
||||||
|
|
|
@ -228,13 +228,15 @@ int env_universal_read_all()
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
debug( 2, L"Get new fishd connection" );
|
debug( 2, L"Get new fishd connection" );
|
||||||
|
|
||||||
init = 0;
|
init = 0;
|
||||||
env_universal_server.fd = get_socket(1);
|
env_universal_server.fd = get_socket(1);
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
137
exec.c
137
exec.c
|
@ -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,37 +324,44 @@ 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)
|
||||||
{
|
{
|
||||||
char b[4096];
|
char b[4096];
|
||||||
int l;
|
int l;
|
||||||
l=read_blocked( d->pipe_fd[0], b, 4096 );
|
l=read_blocked( d->pipe_fd[0], b, 4096 );
|
||||||
if( l==0 )
|
if( l==0 )
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if( l<0 )
|
else if( l<0 )
|
||||||
{
|
{
|
||||||
debug( 1,
|
/*
|
||||||
L"An error occured while reading output from code block on fd %d", d->pipe_fd[0] );
|
exec_read_io_buffer is only called on jobs that have
|
||||||
wperror( L"exec_read_io_buffer" );
|
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;
|
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)
|
|
||||||
{
|
close_loop( io_buffer->pipe_fd[0] );
|
||||||
debug( 1, PIPE_ERROR );
|
|
||||||
wperror( L"close" );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -664,10 +661,8 @@ void exec( job_t *j )
|
||||||
io_data_t *tmp;
|
io_data_t *tmp;
|
||||||
|
|
||||||
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)
|
||||||
|
@ -722,12 +704,10 @@ 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 )
|
||||||
{
|
{
|
||||||
|
|
143
fishd.c
143
fishd.c
|
@ -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;
|
||||||
|
|
2
parser.c
2
parser.c
|
@ -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" );
|
||||||
}
|
}
|
||||||
|
|
157
proc.c
157
proc.c
|
@ -606,12 +606,12 @@ static void handle_child_status( pid_t pid, int status )
|
||||||
{
|
{
|
||||||
block_t *c = current_block;
|
block_t *c = current_block;
|
||||||
|
|
||||||
snprintf( mess,
|
snprintf( mess,
|
||||||
MESS_SIZE,
|
MESS_SIZE,
|
||||||
"Process %ls from job %ls exited through signal, breaking loops\n",
|
"Process %ls from job %ls exited through signal, breaking loops\n",
|
||||||
p->actual_cmd,
|
p->actual_cmd,
|
||||||
j->command );
|
j->command );
|
||||||
write( 2, mess, strlen(mess ));
|
write( 2, mess, strlen(mess ));
|
||||||
|
|
||||||
while( c )
|
while( c )
|
||||||
{
|
{
|
||||||
|
@ -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 )
|
||||||
{
|
{
|
||||||
|
@ -964,8 +964,7 @@ static void read_try( job_t *j )
|
||||||
debug( 1,
|
debug( 1,
|
||||||
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,82 +1042,78 @@ void job_continue (job_t *j, int cont)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Send the job a continue signal, if necessary.
|
|
||||||
*/
|
|
||||||
if( cont )
|
|
||||||
{
|
|
||||||
process_t *p;
|
|
||||||
for( p=j->first_process; p; p=p->next )
|
|
||||||
p->stopped=0;
|
|
||||||
for( p=j->first_process; p; p=p->next )
|
|
||||||
{
|
|
||||||
if (kill ( p->pid, SIGCONT) < 0)
|
|
||||||
{
|
|
||||||
wperror (L"kill (SIGCONT)");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( j->fg )
|
|
||||||
{
|
|
||||||
int quit = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Wait for job to report. Looks a bit ugly because it has to
|
Send the job a continue signal, if necessary.
|
||||||
handle the possibility that a signal is dispatched while
|
|
||||||
running job_is_stopped().
|
|
||||||
*/
|
*/
|
||||||
/*
|
if( cont )
|
||||||
fwprintf( stderr, L"Wait for %ls (%d)\n", j->command, j->pgid );
|
|
||||||
*/
|
|
||||||
while( !quit )
|
|
||||||
{
|
{
|
||||||
do
|
process_t *p;
|
||||||
|
for( p=j->first_process; p; p=p->next )
|
||||||
|
p->stopped=0;
|
||||||
|
for( p=j->first_process; p; p=p->next )
|
||||||
{
|
{
|
||||||
got_signal = 0;
|
if (kill ( p->pid, SIGCONT) < 0)
|
||||||
quit = job_is_stopped( j ) || job_last_is_completed( j );
|
|
||||||
}
|
|
||||||
while( got_signal && !quit );
|
|
||||||
if( !quit )
|
|
||||||
{
|
|
||||||
|
|
||||||
debug( 3, L"select_try()" );
|
|
||||||
switch( select_try(j) )
|
|
||||||
{
|
{
|
||||||
case 1:
|
wperror (L"kill (SIGCONT)");
|
||||||
{
|
return;
|
||||||
debug( 3, L"1" );
|
}
|
||||||
read_try( j );
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
If there is no funky IO magic, we can use
|
|
||||||
waitpid instead of handling child deaths
|
|
||||||
through signals. This gives a rather large
|
|
||||||
speed boost (A factor 3 startup time
|
|
||||||
improvement on my 300 MHz machine) on
|
|
||||||
short-lived jobs.
|
|
||||||
*/
|
|
||||||
debug( 3, L"-1" );
|
|
||||||
int status;
|
|
||||||
pid_t pid = waitpid(-1, &status, WUNTRACED );
|
|
||||||
if( pid > 0 )
|
|
||||||
handle_child_status( pid, status );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if( j->fg )
|
||||||
|
{
|
||||||
|
int quit = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Wait for job to report. Looks a bit ugly because it has to
|
||||||
|
handle the possibility that a signal is dispatched while
|
||||||
|
running job_is_stopped().
|
||||||
|
*/
|
||||||
|
while( !quit )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
got_signal = 0;
|
||||||
|
quit = job_is_stopped( j ) || job_last_is_completed( j );
|
||||||
|
}
|
||||||
|
while( got_signal && !quit );
|
||||||
|
if( !quit )
|
||||||
|
{
|
||||||
|
|
||||||
|
debug( 3, L"select_try()" );
|
||||||
|
switch( select_try(j) )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
read_try( j );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If there is no funky IO magic, we can use
|
||||||
|
waitpid instead of handling child deaths
|
||||||
|
through signals. This gives a rather large
|
||||||
|
speed boost (A factor 3 startup time
|
||||||
|
improvement on my 300 MHz machine) on
|
||||||
|
short-lived jobs.
|
||||||
|
*/
|
||||||
|
int status;
|
||||||
|
pid_t pid = waitpid(-1, &status, WUNTRACED );
|
||||||
|
if( pid > 0 )
|
||||||
|
handle_child_status( pid, status );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if( j->fg )
|
if( j->fg )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1141,8 +1134,7 @@ void job_continue (job_t *j, int cont)
|
||||||
debug( 3, L"Set status of %ls to %d", j->command, WEXITSTATUS(p->status) );
|
debug( 3, L"Set status of %ls to %d", j->command, WEXITSTATUS(p->status) );
|
||||||
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()
|
||||||
|
|
7
reader.c
7
reader.c
|
@ -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 )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue