mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-10 23:24:39 +00:00
A bunch of changes working towards eliminating all memory allocation after fork()
This commit is contained in:
parent
ce859c9e92
commit
d173bb6e0a
15 changed files with 251 additions and 129 deletions
12
builtin.cpp
12
builtin.cpp
|
@ -2964,7 +2964,7 @@ static int builtin_fg( parser_t &parser, wchar_t **argv )
|
||||||
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
|
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
|
||||||
argv[0],
|
argv[0],
|
||||||
pid,
|
pid,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
builtin_print_help( parser, argv[0], stderr_buffer );
|
builtin_print_help( parser, argv[0], stderr_buffer );
|
||||||
j=0;
|
j=0;
|
||||||
}
|
}
|
||||||
|
@ -2978,7 +2978,7 @@ static int builtin_fg( parser_t &parser, wchar_t **argv )
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
FG_MSG,
|
FG_MSG,
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2990,10 +2990,10 @@ static int builtin_fg( parser_t &parser, wchar_t **argv )
|
||||||
fwprintf( stderr,
|
fwprintf( stderr,
|
||||||
FG_MSG,
|
FG_MSG,
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
}
|
}
|
||||||
|
|
||||||
wchar_t *ft = tok_first( j->command_cstr() );
|
wchar_t *ft = tok_first( j->command_wcstr() );
|
||||||
if( ft != 0 )
|
if( ft != 0 )
|
||||||
env_set( L"_", ft, ENV_EXPORT );
|
env_set( L"_", ft, ENV_EXPORT );
|
||||||
free(ft);
|
free(ft);
|
||||||
|
@ -3027,7 +3027,7 @@ static int send_to_bg( parser_t &parser, job_t *j, const wchar_t *name )
|
||||||
_( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ),
|
_( L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n" ),
|
||||||
L"bg",
|
L"bg",
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
builtin_print_help( parser, L"bg", stderr_buffer );
|
builtin_print_help( parser, L"bg", stderr_buffer );
|
||||||
return STATUS_BUILTIN_ERROR;
|
return STATUS_BUILTIN_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -3036,7 +3036,7 @@ static int send_to_bg( parser_t &parser, job_t *j, const wchar_t *name )
|
||||||
append_format(stderr_buffer,
|
append_format(stderr_buffer,
|
||||||
_(L"Send job %d '%ls' to background\n"),
|
_(L"Send job %d '%ls' to background\n"),
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
}
|
}
|
||||||
make_first( j );
|
make_first( j );
|
||||||
job_set_flag( j, JOB_FOREGROUND, 0 );
|
job_set_flag( j, JOB_FOREGROUND, 0 );
|
||||||
|
|
|
@ -98,7 +98,7 @@ static void builtin_jobs_print( const job_t *j, int mode, int header )
|
||||||
#endif
|
#endif
|
||||||
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
|
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
|
||||||
stdout_buffer.append(L"\t");
|
stdout_buffer.append(L"\t");
|
||||||
stdout_buffer.append(j->command_cstr());
|
stdout_buffer.append(j->command_wcstr());
|
||||||
stdout_buffer.append(L"\t");
|
stdout_buffer.append(L"\t");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
44
common.cpp
44
common.cpp
|
@ -299,14 +299,31 @@ wchar_t *str2wcs_internal( const char *in, wchar_t *out )
|
||||||
|
|
||||||
char *wcs2str( const wchar_t *in )
|
char *wcs2str( const wchar_t *in )
|
||||||
{
|
{
|
||||||
char *out;
|
if (! in)
|
||||||
|
return NULL;
|
||||||
out = (char *)malloc( MAX_UTF8_BYTES*wcslen(in)+1 );
|
char *out;
|
||||||
|
size_t desired_size = MAX_UTF8_BYTES*wcslen(in)+1;
|
||||||
if( !out )
|
char local_buff[512];
|
||||||
{
|
if (desired_size <= sizeof local_buff / sizeof *local_buff) {
|
||||||
DIE_MEM();
|
// convert into local buff, then use strdup() so we don't waste malloc'd space
|
||||||
}
|
char *result = wcs2str_internal(in, local_buff);
|
||||||
|
if (result) {
|
||||||
|
// It converted into the local buffer, so copy it
|
||||||
|
result = strdup(result);
|
||||||
|
if (! result) {
|
||||||
|
DIE_MEM();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// here we fall into the bad case of allocating a buffer probably much larger than necessary
|
||||||
|
out = (char *)malloc( MAX_UTF8_BYTES*wcslen(in)+1 );
|
||||||
|
if (!out) {
|
||||||
|
DIE_MEM();
|
||||||
|
}
|
||||||
|
return wcs2str_internal( in, out );
|
||||||
|
}
|
||||||
|
|
||||||
return wcs2str_internal( in, out );
|
return wcs2str_internal( in, out );
|
||||||
}
|
}
|
||||||
|
@ -727,8 +744,9 @@ void debug( int level, const wchar_t *msg, ... )
|
||||||
errno = errno_old;
|
errno = errno_old;
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug_safe(int level, const char *msg, const char *param1, const char *param2, const char *param3)
|
void debug_safe(int level, const char *msg, const char *param1, const char *param2, const char *param3, const char *param4, const char *param5, const char *param6, const char *param7, const char *param8, const char *param9, const char *param10, const char *param11, const char *param12)
|
||||||
{
|
{
|
||||||
|
const char * const params[] = {param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12};
|
||||||
if (! msg)
|
if (! msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -748,12 +766,8 @@ void debug_safe(int level, const char *msg, const char *param1, const char *para
|
||||||
|
|
||||||
if (end[0] == '%' && end[1] == 's') {
|
if (end[0] == '%' && end[1] == 's') {
|
||||||
/* Handle a format string */
|
/* Handle a format string */
|
||||||
const char *format = NULL;
|
assert(param_idx < sizeof params / sizeof *params);
|
||||||
switch (param_idx++) {
|
const char *format = params[param_idx++];
|
||||||
case 0: format = param1; break;
|
|
||||||
case 1: format = param2; break;
|
|
||||||
case 2: format = param3; break;
|
|
||||||
}
|
|
||||||
if (! format)
|
if (! format)
|
||||||
format = "(null)";
|
format = "(null)";
|
||||||
write(STDERR_FILENO, format, strlen(format));
|
write(STDERR_FILENO, format, strlen(format));
|
||||||
|
|
24
common.h
24
common.h
|
@ -288,7 +288,7 @@ wcstring format_size(long long sz);
|
||||||
void format_size_safe(char buff[128], unsigned long long sz);
|
void format_size_safe(char buff[128], unsigned long long sz);
|
||||||
|
|
||||||
/** Our crappier versions of debug which is guaranteed to not allocate any memory, or do anything other than call write(). This is useful after a call to fork() with threads. */
|
/** Our crappier versions of debug which is guaranteed to not allocate any memory, or do anything other than call write(). This is useful after a call to fork() with threads. */
|
||||||
void debug_safe(int level, const char *msg, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL);
|
void debug_safe(int level, const char *msg, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL, const char *param5 = NULL, const char *param6 = NULL, const char *param7 = NULL, const char *param8 = NULL, const char *param9 = NULL, const char *param10 = NULL, const char *param11 = NULL, const char *param12 = NULL);
|
||||||
|
|
||||||
/** Writes out a long safely */
|
/** Writes out a long safely */
|
||||||
void format_long_safe(char buff[128], long val);
|
void format_long_safe(char buff[128], long val);
|
||||||
|
@ -446,6 +446,28 @@ class null_terminated_array_t {
|
||||||
/* Helper function to convert from a null_terminated_array_t<wchar_t> to a null_terminated_array_t<char_t> */
|
/* Helper function to convert from a null_terminated_array_t<wchar_t> to a null_terminated_array_t<char_t> */
|
||||||
null_terminated_array_t<char> convert_wide_array_to_narrow(const null_terminated_array_t<wchar_t> &arr);
|
null_terminated_array_t<char> convert_wide_array_to_narrow(const null_terminated_array_t<wchar_t> &arr);
|
||||||
|
|
||||||
|
/* Helper class to cache a narrow version of a wcstring in a malloc'd buffer, so that we can read it after fork() */
|
||||||
|
class narrow_string_rep_t {
|
||||||
|
private:
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
public:
|
||||||
|
~narrow_string_rep_t() {
|
||||||
|
free((void *)str);
|
||||||
|
}
|
||||||
|
|
||||||
|
narrow_string_rep_t() : str(NULL) {}
|
||||||
|
|
||||||
|
void set(const wcstring &s) {
|
||||||
|
free((void *)str);
|
||||||
|
str = wcs2str(s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get() const {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
bool is_forked_child();
|
bool is_forked_child();
|
||||||
|
|
||||||
/* Basic scoped lock class */
|
/* Basic scoped lock class */
|
||||||
|
|
|
@ -192,7 +192,7 @@ wcstring event_get_desc( const event_t *e )
|
||||||
{
|
{
|
||||||
job_t *j = job_get_from_pid( -e->param1.pid );
|
job_t *j = job_get_from_pid( -e->param1.pid );
|
||||||
if( j )
|
if( j )
|
||||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_cstr() );
|
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
|
||||||
else
|
else
|
||||||
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid );
|
result = format_string(_(L"exit handler for job with process group %d"), -e->param1.pid );
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ wcstring event_get_desc( const event_t *e )
|
||||||
{
|
{
|
||||||
job_t *j = job_get( e->param1.job_id );
|
job_t *j = job_get( e->param1.job_id );
|
||||||
if( j )
|
if( j )
|
||||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_cstr() );
|
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id, j->command_wcstr() );
|
||||||
else
|
else
|
||||||
result = format_string(_(L"exit handler for job with job id %d"), j->job_id );
|
result = format_string(_(L"exit handler for job with job id %d"), j->job_id );
|
||||||
|
|
||||||
|
|
37
exec.cpp
37
exec.cpp
|
@ -65,7 +65,7 @@
|
||||||
/**
|
/**
|
||||||
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 '%s'" )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Base open mode to pass to calls to open
|
Base open mode to pass to calls to open
|
||||||
|
@ -448,11 +448,11 @@ static io_data_t *io_transmogrify( io_data_t * in )
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if( (fd=wopen( in->filename, in->param2.flags, OPEN_MASK ) )==-1 )
|
if( (fd=open( in->filename_cstr, in->param2.flags, OPEN_MASK ) )==-1 )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug( 1,
|
||||||
FILE_ERROR,
|
FILE_ERROR,
|
||||||
in->filename.c_str() );
|
in->filename_cstr );
|
||||||
|
|
||||||
wperror( L"open" );
|
wperror( L"open" );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -574,7 +574,7 @@ void exec( parser_t &parser, job_t *j )
|
||||||
sigemptyset( &chldset );
|
sigemptyset( &chldset );
|
||||||
sigaddset( &chldset, SIGCHLD );
|
sigaddset( &chldset, SIGCHLD );
|
||||||
|
|
||||||
debug( 4, L"Exec job '%ls' with id %d", j->command_cstr(), j->job_id );
|
debug( 4, L"Exec job '%ls' with id %d", j->command_wcstr(), j->job_id );
|
||||||
|
|
||||||
if( parser.block_io )
|
if( parser.block_io )
|
||||||
{
|
{
|
||||||
|
@ -689,6 +689,9 @@ void exec( parser_t &parser, job_t *j )
|
||||||
if( needs_keepalive )
|
if( needs_keepalive )
|
||||||
{
|
{
|
||||||
/* Call fork. No need to wait for threads since our use is confined and simple. */
|
/* Call fork. No need to wait for threads since our use is confined and simple. */
|
||||||
|
if (g_log_forks) {
|
||||||
|
printf("Executing keepalive fork for '%ls'\n", j->command_wcstr());
|
||||||
|
}
|
||||||
keepalive.pid = execute_fork(false);
|
keepalive.pid = execute_fork(false);
|
||||||
if( keepalive.pid == 0 )
|
if( keepalive.pid == 0 )
|
||||||
{
|
{
|
||||||
|
@ -880,13 +883,13 @@ void exec( parser_t &parser, job_t *j )
|
||||||
case IO_FILE:
|
case IO_FILE:
|
||||||
{
|
{
|
||||||
/* Do not set CLO_EXEC because child needs access */
|
/* Do not set CLO_EXEC because child needs access */
|
||||||
builtin_stdin=wopen( in->filename,
|
builtin_stdin=open( in->filename_cstr,
|
||||||
in->param2.flags, OPEN_MASK );
|
in->param2.flags, OPEN_MASK );
|
||||||
if( builtin_stdin == -1 )
|
if( builtin_stdin == -1 )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug( 1,
|
||||||
FILE_ERROR,
|
FILE_ERROR,
|
||||||
in->filename.c_str() );
|
in->filename_cstr );
|
||||||
wperror( L"open" );
|
wperror( L"open" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1045,6 +1048,9 @@ void exec( parser_t &parser, job_t *j )
|
||||||
if( io_buffer->out_buffer_size() > 0 )
|
if( io_buffer->out_buffer_size() > 0 )
|
||||||
{
|
{
|
||||||
/* We don't have to drain threads here because our child process is simple */
|
/* We don't have to drain threads here because our child process is simple */
|
||||||
|
if (g_log_forks) {
|
||||||
|
printf("Executing fork for internal block or function for '%ls'\n", p->argv0());
|
||||||
|
}
|
||||||
pid = execute_fork(false);
|
pid = execute_fork(false);
|
||||||
if( pid == 0 )
|
if( pid == 0 )
|
||||||
{
|
{
|
||||||
|
@ -1093,6 +1099,10 @@ void exec( parser_t &parser, job_t *j )
|
||||||
const char *buffer = input_redirect->out_buffer_ptr();
|
const char *buffer = input_redirect->out_buffer_ptr();
|
||||||
size_t count = input_redirect->out_buffer_size();
|
size_t count = input_redirect->out_buffer_size();
|
||||||
|
|
||||||
|
/* We don't have to drain threads here because our child process is simple */
|
||||||
|
if (g_log_forks) {
|
||||||
|
printf("Executing fork for internal buffer for '%ls'\n", p->argv0() ? p->argv0() : L"(null)");
|
||||||
|
}
|
||||||
pid = execute_fork(false);
|
pid = execute_fork(false);
|
||||||
if( pid == 0 )
|
if( pid == 0 )
|
||||||
{
|
{
|
||||||
|
@ -1148,7 +1158,7 @@ void exec( parser_t &parser, job_t *j )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
io_data_t *io = io_get( j->io, 1 );
|
io_data_t *io = io_get( j->io, 1 );
|
||||||
int buffer_stdout = io && io->io_mode == IO_BUFFER;
|
bool buffer_stdout = io && io->io_mode == IO_BUFFER;
|
||||||
|
|
||||||
if( ( get_stderr_buffer().empty() ) &&
|
if( ( get_stderr_buffer().empty() ) &&
|
||||||
( !p->next ) &&
|
( !p->next ) &&
|
||||||
|
@ -1160,9 +1170,9 @@ void exec( parser_t &parser, job_t *j )
|
||||||
skip_fork = 1;
|
skip_fork = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( io = j->io; io; io=io->next )
|
for( io_data_t *tmp_io = j->io; tmp_io != NULL; tmp_io=tmp_io->next )
|
||||||
{
|
{
|
||||||
if( io->io_mode == IO_FILE && io->filename != L"/dev/null")
|
if( tmp_io->io_mode == IO_FILE && strcmp(tmp_io->filename_cstr, "/dev/null") != 0)
|
||||||
{
|
{
|
||||||
skip_fork = 0;
|
skip_fork = 0;
|
||||||
}
|
}
|
||||||
|
@ -1173,7 +1183,7 @@ void exec( parser_t &parser, job_t *j )
|
||||||
p->completed=1;
|
p->completed=1;
|
||||||
if( p->next == 0 )
|
if( p->next == 0 )
|
||||||
{
|
{
|
||||||
debug( 3, L"Set status of %ls to %d using short circut", j->command_cstr(), p->status );
|
debug( 3, L"Set status of %ls to %d using short circut", j->command_wcstr(), p->status );
|
||||||
|
|
||||||
int status = p->status;
|
int status = p->status;
|
||||||
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status );
|
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status );
|
||||||
|
@ -1189,6 +1199,10 @@ void exec( parser_t &parser, job_t *j )
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
|
if (g_log_forks) {
|
||||||
|
printf("Executing fork for internal builtin for '%ls' (io is %p)\n", p->argv0(), io);
|
||||||
|
io_print(io);
|
||||||
|
}
|
||||||
pid = execute_fork(false);
|
pid = execute_fork(false);
|
||||||
if( pid == 0 )
|
if( pid == 0 )
|
||||||
{
|
{
|
||||||
|
@ -1240,9 +1254,6 @@ void exec( parser_t &parser, job_t *j )
|
||||||
const wchar_t *reader_current_filename();
|
const wchar_t *reader_current_filename();
|
||||||
if (g_log_forks) {
|
if (g_log_forks) {
|
||||||
printf("forking for '%s' in '%ls'\n", actual_cmd, reader_current_filename());
|
printf("forking for '%s' in '%ls'\n", actual_cmd, reader_current_filename());
|
||||||
if (std::string(actual_cmd) == "/usr/bin/getopt") {
|
|
||||||
puts("wat");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pid = execute_fork(true /* must drain threads */);
|
pid = execute_fork(true /* must drain threads */);
|
||||||
if( pid == 0 )
|
if( pid == 0 )
|
||||||
|
|
4
exec.h
4
exec.h
|
@ -59,8 +59,8 @@ __warn_unused int exec_subshell(const wcstring &cmd );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Loops over close until thesyscall was run without beeing
|
Loops over close until the syscall was run without being
|
||||||
interrupted. Thenremoves the fd from the open_fds list.
|
interrupted. Then removes the fd from the open_fds list.
|
||||||
*/
|
*/
|
||||||
void exec_close( int fd );
|
void exec_close( int fd );
|
||||||
|
|
||||||
|
|
14
expand.cpp
14
expand.cpp
|
@ -348,14 +348,14 @@ static int find_process( const wchar_t *proc,
|
||||||
while ((j = jobs.next()))
|
while ((j = jobs.next()))
|
||||||
{
|
{
|
||||||
wchar_t jid[16];
|
wchar_t jid[16];
|
||||||
if( j->command.size() == 0 )
|
if( j->command_is_empty() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
swprintf( jid, 16, L"%d", j->job_id );
|
swprintf( jid, 16, L"%d", j->job_id );
|
||||||
|
|
||||||
if( wcsncmp( proc, jid, wcslen(proc ) )==0 )
|
if( wcsncmp( proc, jid, wcslen(proc ) )==0 )
|
||||||
{
|
{
|
||||||
wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_cstr());
|
wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_wcstr());
|
||||||
completion_allocate( out,
|
completion_allocate( out,
|
||||||
jid+wcslen(proc),
|
jid+wcslen(proc),
|
||||||
desc_buff,
|
desc_buff,
|
||||||
|
@ -375,7 +375,7 @@ static int find_process( const wchar_t *proc,
|
||||||
if( jid > 0 && !errno && !*end )
|
if( jid > 0 && !errno && !*end )
|
||||||
{
|
{
|
||||||
j = job_get( jid );
|
j = job_get( jid );
|
||||||
if( (j != 0) && (j->command_cstr() != 0 ) )
|
if( (j != 0) && (j->command_wcstr() != 0 ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -395,15 +395,15 @@ static int find_process( const wchar_t *proc,
|
||||||
{
|
{
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if( j->command_cstr() == 0 )
|
if( j->command_wcstr() == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( match_pid( j->command_cstr(), proc, flags, &offset ) )
|
if( match_pid( j->command_wcstr(), proc, flags, &offset ) )
|
||||||
{
|
{
|
||||||
if( flags & ACCEPT_INCOMPLETE )
|
if( flags & ACCEPT_INCOMPLETE )
|
||||||
{
|
{
|
||||||
completion_allocate( out,
|
completion_allocate( out,
|
||||||
j->command_cstr() + offset + wcslen(proc),
|
j->command_wcstr() + offset + wcslen(proc),
|
||||||
COMPLETE_JOB_DESC,
|
COMPLETE_JOB_DESC,
|
||||||
0 );
|
0 );
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ static int find_process( const wchar_t *proc,
|
||||||
while ((j = jobs.next()))
|
while ((j = jobs.next()))
|
||||||
{
|
{
|
||||||
process_t *p;
|
process_t *p;
|
||||||
if( j->command.size() == 0 )
|
if( j->command_is_empty() )
|
||||||
continue;
|
continue;
|
||||||
for( p=j->first_process; p; p=p->next )
|
for( p=j->first_process; p; p=p->next )
|
||||||
{
|
{
|
||||||
|
|
2
io.cpp
2
io.cpp
|
@ -197,7 +197,7 @@ io_data_t *io_duplicate( io_data_t *l )
|
||||||
|
|
||||||
io_data_t *io_get( io_data_t *io, int fd )
|
io_data_t *io_get( io_data_t *io, int fd )
|
||||||
{
|
{
|
||||||
if( io == 0 )
|
if( io == NULL )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
io_data_t *res = io_get( io->next, fd );
|
io_data_t *res = io_get( io->next, fd );
|
||||||
|
|
32
io.h
32
io.h
|
@ -40,8 +40,6 @@ public:
|
||||||
int old_fd;
|
int old_fd;
|
||||||
} param1;
|
} param1;
|
||||||
|
|
||||||
/** Filename IO_FILE */
|
|
||||||
wcstring filename;
|
|
||||||
|
|
||||||
/** Second type-specific paramter for redirection */
|
/** Second type-specific paramter for redirection */
|
||||||
union
|
union
|
||||||
|
@ -52,6 +50,15 @@ public:
|
||||||
int close_old;
|
int close_old;
|
||||||
} param2;
|
} param2;
|
||||||
|
|
||||||
|
/** Filename IO_FILE. malloc'd. This needs to be used after fork, so don't use wcstring here. */
|
||||||
|
const char *filename_cstr;
|
||||||
|
|
||||||
|
/** Convenience to set filename_cstr via wcstring */
|
||||||
|
void set_filename(const wcstring &str) {
|
||||||
|
free((void *)filename_cstr);
|
||||||
|
filename_cstr = wcs2str(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
/** Function to create the output buffer */
|
/** Function to create the output buffer */
|
||||||
void out_buffer_create() {
|
void out_buffer_create() {
|
||||||
out_buffer.reset(new std::vector<char>);
|
out_buffer.reset(new std::vector<char>);
|
||||||
|
@ -81,11 +88,26 @@ public:
|
||||||
/** Pointer to the next IO redirection */
|
/** Pointer to the next IO redirection */
|
||||||
io_data_t *next;
|
io_data_t *next;
|
||||||
|
|
||||||
io_data_t() : next(NULL)
|
io_data_t() : filename_cstr(NULL), next(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: we have a default copy constructor */
|
io_data_t(const io_data_t &rhs) :
|
||||||
|
out_buffer(rhs.out_buffer),
|
||||||
|
io_mode(rhs.io_mode),
|
||||||
|
fd(rhs.fd),
|
||||||
|
param1(rhs.param1),
|
||||||
|
param2(rhs.param2),
|
||||||
|
filename_cstr(rhs.filename_cstr ? strdup(rhs.filename_cstr) : NULL),
|
||||||
|
is_input(rhs.is_input),
|
||||||
|
next(rhs.next)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
~io_data_t() {
|
||||||
|
free((void *)filename_cstr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,7 +140,7 @@ void io_buffer_destroy( io_data_t *io_buffer );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a IO_BUFFER type io redirection, complete with a pipe and a
|
Create a IO_BUFFER type io redirection, complete with a pipe and a
|
||||||
buffer_t for output. The default file descriptor used is 1 for
|
vector<char> for output. The default file descriptor used is 1 for
|
||||||
output buffering and 0 for input buffering.
|
output buffering and 0 for input buffering.
|
||||||
|
|
||||||
\param is_input set this parameter to zero if the buffer should be
|
\param is_input set this parameter to zero if the buffer should be
|
||||||
|
|
14
parser.cpp
14
parser.cpp
|
@ -1538,25 +1538,25 @@ void parser_t::parse_job_argument_list( process_t *p,
|
||||||
case TOK_REDIRECT_APPEND:
|
case TOK_REDIRECT_APPEND:
|
||||||
new_io->io_mode = IO_FILE;
|
new_io->io_mode = IO_FILE;
|
||||||
new_io->param2.flags = O_CREAT | O_APPEND | O_WRONLY;
|
new_io->param2.flags = O_CREAT | O_APPEND | O_WRONLY;
|
||||||
new_io->filename = target;
|
new_io->set_filename(target);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_OUT:
|
case TOK_REDIRECT_OUT:
|
||||||
new_io->io_mode = IO_FILE;
|
new_io->io_mode = IO_FILE;
|
||||||
new_io->param2.flags = O_CREAT | O_WRONLY | O_TRUNC;
|
new_io->param2.flags = O_CREAT | O_WRONLY | O_TRUNC;
|
||||||
new_io->filename = target;
|
new_io->set_filename(target);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_NOCLOB:
|
case TOK_REDIRECT_NOCLOB:
|
||||||
new_io->io_mode = IO_FILE;
|
new_io->io_mode = IO_FILE;
|
||||||
new_io->param2.flags = O_CREAT | O_EXCL | O_WRONLY;
|
new_io->param2.flags = O_CREAT | O_EXCL | O_WRONLY;
|
||||||
new_io->filename = target;
|
new_io->set_filename(target);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_IN:
|
case TOK_REDIRECT_IN:
|
||||||
new_io->io_mode = IO_FILE;
|
new_io->io_mode = IO_FILE;
|
||||||
new_io->param2.flags = O_RDONLY;
|
new_io->param2.flags = O_RDONLY;
|
||||||
new_io->filename = target;
|
new_io->set_filename(target);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_FD:
|
case TOK_REDIRECT_FD:
|
||||||
|
@ -2311,15 +2311,15 @@ void parser_t::eval_job( tokenizer *tok )
|
||||||
if( newline )
|
if( newline )
|
||||||
stop_pos = mini( stop_pos, newline - tok_string(tok) );
|
stop_pos = mini( stop_pos, newline - tok_string(tok) );
|
||||||
|
|
||||||
j->command = wcstring(tok_string(tok)+start_pos, stop_pos-start_pos);
|
j->set_command(wcstring(tok_string(tok)+start_pos, stop_pos-start_pos));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
j->command = L"";
|
j->set_command(L"");
|
||||||
|
|
||||||
if( profile )
|
if( profile )
|
||||||
{
|
{
|
||||||
t2 = get_time();
|
t2 = get_time();
|
||||||
profile_item->cmd = wcsdup( j->command_cstr() );
|
profile_item->cmd = wcsdup( j->command_wcstr() );
|
||||||
profile_item->skipped=current_block->skip;
|
profile_item->skipped=current_block->skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
97
postfork.cpp
97
postfork.cpp
|
@ -20,17 +20,27 @@
|
||||||
#define OPEN_MASK 0666
|
#define OPEN_MASK 0666
|
||||||
|
|
||||||
/** fork error message */
|
/** fork error message */
|
||||||
#define FORK_ERROR _( L"Could not create child process - exiting" )
|
#define FORK_ERROR "Could not create child process - exiting"
|
||||||
|
|
||||||
/** file redirection clobbering error message */
|
/** file redirection clobbering error message */
|
||||||
#define NOCLOB_ERROR _( L"The file '%ls' already exists" )
|
#define NOCLOB_ERROR "The file '%s' already exists"
|
||||||
|
|
||||||
/** file redirection error message */
|
/** file redirection error message */
|
||||||
#define FILE_ERROR _( L"An error occurred while redirecting file '%ls'" )
|
#define FILE_ERROR "An error occurred while redirecting file '%s'"
|
||||||
|
|
||||||
/** file descriptor redirection error message */
|
/** file descriptor redirection error message */
|
||||||
#define FD_ERROR _( L"An error occurred while redirecting file descriptor %d" )
|
#define FD_ERROR "An error occurred while redirecting file descriptor %s"
|
||||||
|
|
||||||
|
/** pipe error */
|
||||||
|
#define LOCAL_PIPE_ERROR "An error occurred while setting up pipe"
|
||||||
|
|
||||||
|
/* Cover for debug_safe that can take an int. The format string should expect a %s */
|
||||||
|
static void debug_safe_int(int level, const char *format, int val)
|
||||||
|
{
|
||||||
|
char buff[128];
|
||||||
|
format_long_safe(buff, val);
|
||||||
|
debug_safe(level, format, buff);
|
||||||
|
}
|
||||||
|
|
||||||
// PCA These calls to debug are rather sketchy because they may allocate memory. Fortunately they only occur if an error occurs.
|
// PCA These calls to debug are rather sketchy because they may allocate memory. Fortunately they only occur if an error occurs.
|
||||||
int set_child_group( job_t *j, process_t *p, int print_errors )
|
int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||||
|
@ -48,15 +58,25 @@ int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||||
{
|
{
|
||||||
if( getpgid( p->pid) != j->pgid && print_errors )
|
if( getpgid( p->pid) != j->pgid && print_errors )
|
||||||
{
|
{
|
||||||
|
char pid_buff[128];
|
||||||
|
char job_id_buff[128];
|
||||||
|
char getpgid_buff[128];
|
||||||
|
char job_pgid_buff[128];
|
||||||
|
|
||||||
|
format_long_safe(pid_buff, p->pid);
|
||||||
|
format_long_safe(job_id_buff, j->job_id);
|
||||||
|
format_long_safe(getpgid_buff, getpgid( p->pid));
|
||||||
|
format_long_safe(job_pgid_buff, j->pgid);
|
||||||
|
|
||||||
// PCA FIXME This is sketchy to do in a forked child because it may allocate memory. This needs to call only safe functions.
|
// PCA FIXME This is sketchy to do in a forked child because it may allocate memory. This needs to call only safe functions.
|
||||||
debug( 1,
|
debug_safe( 1,
|
||||||
_( L"Could not send process %d, '%ls' in job %d, '%ls' from group %d to group %d" ),
|
"Could not send process %s, '%s' in job %s, '%s' from group %s to group %s",
|
||||||
p->pid,
|
pid_buff,
|
||||||
p->argv0(),
|
p->argv0_cstr(),
|
||||||
j->job_id,
|
job_id_buff,
|
||||||
j->command_cstr(),
|
j->command_cstr(),
|
||||||
getpgid( p->pid),
|
getpgid_buff,
|
||||||
j->pgid );
|
job_pgid_buff );
|
||||||
|
|
||||||
wperror( L"setpgid" );
|
wperror( L"setpgid" );
|
||||||
res = -1;
|
res = -1;
|
||||||
|
@ -72,9 +92,9 @@ int set_child_group( job_t *j, process_t *p, int print_errors )
|
||||||
{
|
{
|
||||||
if( tcsetpgrp (0, j->pgid) && print_errors )
|
if( tcsetpgrp (0, j->pgid) && print_errors )
|
||||||
{
|
{
|
||||||
debug( 1, _( L"Could not send job %d ('%ls') to foreground" ),
|
char job_id_buff[128];
|
||||||
j->job_id,
|
format_long_safe(job_id_buff, j->job_id);
|
||||||
j->command_cstr() );
|
debug_safe( 1, "Could not send job %s ('%s') to foreground", job_id_buff, j->command_cstr() );
|
||||||
wperror( L"tcsetpgrp" );
|
wperror( L"tcsetpgrp" );
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
@ -102,9 +122,7 @@ static void free_fd( io_data_t *io, int fd )
|
||||||
{
|
{
|
||||||
if( errno != EINTR )
|
if( errno != EINTR )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug_safe_int( 1, FD_ERROR, fd );
|
||||||
FD_ERROR,
|
|
||||||
fd );
|
|
||||||
wperror( L"dup" );
|
wperror( L"dup" );
|
||||||
FATAL_EXIT();
|
FATAL_EXIT();
|
||||||
}
|
}
|
||||||
|
@ -161,7 +179,7 @@ static int handle_child_io( io_data_t *io )
|
||||||
{
|
{
|
||||||
if( close(io->fd) )
|
if( close(io->fd) )
|
||||||
{
|
{
|
||||||
debug( 0, _(L"Failed to close file descriptor %d"), io->fd );
|
debug_safe_int( 0, "Failed to close file descriptor %s", io->fd );
|
||||||
wperror( L"close" );
|
wperror( L"close" );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -170,23 +188,18 @@ static int handle_child_io( io_data_t *io )
|
||||||
case IO_FILE:
|
case IO_FILE:
|
||||||
{
|
{
|
||||||
// Here we definitely do not want to set CLO_EXEC because our child needs access
|
// Here we definitely do not want to set CLO_EXEC because our child needs access
|
||||||
if( (tmp=wopen( io->filename,
|
if( (tmp=open( io->filename_cstr,
|
||||||
io->param2.flags, OPEN_MASK ) )==-1 )
|
io->param2.flags, OPEN_MASK ) )==-1 )
|
||||||
{
|
{
|
||||||
if( ( io->param2.flags & O_EXCL ) &&
|
if( ( io->param2.flags & O_EXCL ) &&
|
||||||
( errno ==EEXIST ) )
|
( errno ==EEXIST ) )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug_safe( 1, NOCLOB_ERROR, io->filename_cstr );
|
||||||
NOCLOB_ERROR,
|
|
||||||
io->filename.c_str() );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug_safe( 1, FILE_ERROR, io->filename_cstr );
|
||||||
FILE_ERROR,
|
perror( "open" );
|
||||||
io->filename.c_str() );
|
|
||||||
|
|
||||||
wperror( L"open" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -201,10 +214,8 @@ static int handle_child_io( io_data_t *io )
|
||||||
|
|
||||||
if(dup2( tmp, io->fd ) == -1 )
|
if(dup2( tmp, io->fd ) == -1 )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug_safe_int( 1, FD_ERROR, io->fd );
|
||||||
FD_ERROR,
|
perror( "dup2" );
|
||||||
io->fd );
|
|
||||||
wperror( L"dup2" );
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
exec_close( tmp );
|
exec_close( tmp );
|
||||||
|
@ -222,9 +233,7 @@ static int handle_child_io( io_data_t *io )
|
||||||
|
|
||||||
if( dup2( io->param1.old_fd, io->fd ) == -1 )
|
if( dup2( io->param1.old_fd, io->fd ) == -1 )
|
||||||
{
|
{
|
||||||
debug( 1,
|
debug_safe_int( 1, FD_ERROR, io->fd );
|
||||||
FD_ERROR,
|
|
||||||
io->fd );
|
|
||||||
wperror( L"dup2" );
|
wperror( L"dup2" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -248,8 +257,8 @@ static int handle_child_io( io_data_t *io )
|
||||||
*/
|
*/
|
||||||
if( dup2( io->param1.pipe_fd[write_pipe], io->fd ) != io->fd )
|
if( dup2( io->param1.pipe_fd[write_pipe], io->fd ) != io->fd )
|
||||||
{
|
{
|
||||||
debug( 1, PIPE_ERROR );
|
debug_safe( 1, LOCAL_PIPE_ERROR );
|
||||||
wperror( L"dup2" );
|
perror( "dup2" );
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,24 +284,24 @@ static int handle_child_io( io_data_t *io )
|
||||||
|
|
||||||
int setup_child_process( job_t *j, process_t *p )
|
int setup_child_process( job_t *j, process_t *p )
|
||||||
{
|
{
|
||||||
int res=0;
|
bool ok=true;
|
||||||
|
|
||||||
if( p )
|
if( p )
|
||||||
{
|
{
|
||||||
res = set_child_group( j, p, 1 );
|
ok = (0 == set_child_group( j, p, 1 ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !res )
|
if( ok )
|
||||||
{
|
{
|
||||||
res = handle_child_io( j->io );
|
ok = (0 == handle_child_io( j->io ));
|
||||||
if( p != 0 && res )
|
if( p != 0 && ! ok )
|
||||||
{
|
{
|
||||||
exit_without_destructors( 1 );
|
exit_without_destructors( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the handling for job control signals back to the default. */
|
/* Set the handling for job control signals back to the default. */
|
||||||
if( !res )
|
if( ok )
|
||||||
{
|
{
|
||||||
signal_reset_handlers();
|
signal_reset_handlers();
|
||||||
}
|
}
|
||||||
|
@ -300,7 +309,7 @@ int setup_child_process( job_t *j, process_t *p )
|
||||||
/* Remove all signal blocks */
|
/* Remove all signal blocks */
|
||||||
signal_unblock();
|
signal_unblock();
|
||||||
|
|
||||||
return res;
|
return ok ? 0 : -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +362,7 @@ pid_t execute_fork(bool wait_for_threads_to_die)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug( 0, FORK_ERROR );
|
debug_safe( 0, FORK_ERROR );
|
||||||
wperror (L"fork");
|
wperror (L"fork");
|
||||||
FATAL_EXIT();
|
FATAL_EXIT();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
24
proc.cpp
24
proc.cpp
|
@ -184,7 +184,7 @@ void proc_destroy()
|
||||||
while( ! jobs.empty() )
|
while( ! jobs.empty() )
|
||||||
{
|
{
|
||||||
job_t *job = jobs.front();
|
job_t *job = jobs.front();
|
||||||
debug( 2, L"freeing leaked job %ls", job->command_cstr() );
|
debug( 2, L"freeing leaked job %ls", job->command_wcstr() );
|
||||||
job_free( job );
|
job_free( job );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,7 +528,7 @@ void job_handle_signal ( int signal, siginfo_t *info, void *con )
|
||||||
static void format_job_info( const job_t *j, const wchar_t *status )
|
static void format_job_info( const job_t *j, const wchar_t *status )
|
||||||
{
|
{
|
||||||
fwprintf (stdout, L"\r" );
|
fwprintf (stdout, L"\r" );
|
||||||
fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command_cstr(), status);
|
fwprintf (stdout, _( L"Job %d, \'%ls\' has %ls" ), j->job_id, j->command_wcstr(), status);
|
||||||
fflush( stdout );
|
fflush( stdout );
|
||||||
tputs(clr_eol,1,&writeb);
|
tputs(clr_eol,1,&writeb);
|
||||||
fwprintf (stdout, L"\n" );
|
fwprintf (stdout, L"\n" );
|
||||||
|
@ -613,7 +613,7 @@ int job_reap( bool interactive )
|
||||||
_( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
|
_( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
|
||||||
program_name,
|
program_name,
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr(),
|
j->command_wcstr(),
|
||||||
sig2wcs(WTERMSIG(p->status)),
|
sig2wcs(WTERMSIG(p->status)),
|
||||||
signal_get_desc( WTERMSIG(p->status) ) );
|
signal_get_desc( WTERMSIG(p->status) ) );
|
||||||
else
|
else
|
||||||
|
@ -623,7 +623,7 @@ int job_reap( bool interactive )
|
||||||
p->pid,
|
p->pid,
|
||||||
p->argv0(),
|
p->argv0(),
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr(),
|
j->command_wcstr(),
|
||||||
sig2wcs(WTERMSIG(p->status)),
|
sig2wcs(WTERMSIG(p->status)),
|
||||||
signal_get_desc( WTERMSIG(p->status) ) );
|
signal_get_desc( WTERMSIG(p->status) ) );
|
||||||
tputs(clr_eol,1,&writeb);
|
tputs(clr_eol,1,&writeb);
|
||||||
|
@ -857,7 +857,7 @@ static void read_try( job_t *j )
|
||||||
|
|
||||||
if( buff )
|
if( buff )
|
||||||
{
|
{
|
||||||
debug( 3, L"proc::read_try('%ls')\n", j->command_cstr() );
|
debug( 3, L"proc::read_try('%ls')\n", j->command_wcstr() );
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
char b[BUFFER_SIZE];
|
char b[BUFFER_SIZE];
|
||||||
|
@ -905,7 +905,7 @@ static int terminal_give_to_job( job_t *j, int cont )
|
||||||
debug( 1,
|
debug( 1,
|
||||||
_( L"Could not send job %d ('%ls') to foreground" ),
|
_( L"Could not send job %d ('%ls') to foreground" ),
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
wperror( L"tcsetpgrp" );
|
wperror( L"tcsetpgrp" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -917,7 +917,7 @@ static int terminal_give_to_job( job_t *j, int cont )
|
||||||
debug( 1,
|
debug( 1,
|
||||||
_( L"Could not send job %d ('%ls') to foreground" ),
|
_( L"Could not send job %d ('%ls') to foreground" ),
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
wperror( L"tcsetattr" );
|
wperror( L"tcsetattr" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -977,7 +977,7 @@ void job_continue (job_t *j, int cont)
|
||||||
L"Continue job %d, gid %d (%ls), %ls, %ls",
|
L"Continue job %d, gid %d (%ls), %ls, %ls",
|
||||||
j->job_id,
|
j->job_id,
|
||||||
j->pgid,
|
j->pgid,
|
||||||
j->command_cstr(),
|
j->command_wcstr(),
|
||||||
job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
|
job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
|
||||||
is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
|
is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
|
||||||
|
|
||||||
|
@ -1188,8 +1188,8 @@ void proc_sanity_check()
|
||||||
{
|
{
|
||||||
debug( 0,
|
debug( 0,
|
||||||
_( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
|
_( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
|
||||||
fg_job->command_cstr(),
|
fg_job->command_wcstr(),
|
||||||
j->command_cstr() );
|
j->command_wcstr() );
|
||||||
sanity_lose();
|
sanity_lose();
|
||||||
}
|
}
|
||||||
fg_job = j;
|
fg_job = j;
|
||||||
|
@ -1207,7 +1207,7 @@ void proc_sanity_check()
|
||||||
{
|
{
|
||||||
debug( 0,
|
debug( 0,
|
||||||
_( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
|
_( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
|
||||||
j->command_cstr(),
|
j->command_wcstr(),
|
||||||
p->argv0(),
|
p->argv0(),
|
||||||
p->stopped );
|
p->stopped );
|
||||||
sanity_lose();
|
sanity_lose();
|
||||||
|
@ -1217,7 +1217,7 @@ void proc_sanity_check()
|
||||||
{
|
{
|
||||||
debug( 0,
|
debug( 0,
|
||||||
_( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
|
_( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
|
||||||
j->command_cstr(),
|
j->command_wcstr(),
|
||||||
p->argv0(),
|
p->argv0(),
|
||||||
p->completed );
|
p->completed );
|
||||||
sanity_lose();
|
sanity_lose();
|
||||||
|
|
68
proc.h
68
proc.h
|
@ -130,7 +130,15 @@ class process_t
|
||||||
private:
|
private:
|
||||||
|
|
||||||
null_terminated_array_t<wchar_t> argv_array;
|
null_terminated_array_t<wchar_t> argv_array;
|
||||||
|
|
||||||
|
/* narrow copy of argv0 so we don't have to convert after fork */
|
||||||
|
narrow_string_rep_t argv0_narrow;
|
||||||
|
|
||||||
|
|
||||||
|
/* No copying */
|
||||||
|
process_t(const process_t &rhs) { }
|
||||||
|
void operator=(const process_t &rhs) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
process_t() :
|
process_t() :
|
||||||
|
@ -168,17 +176,32 @@ class process_t
|
||||||
|
|
||||||
|
|
||||||
/** Sets argv */
|
/** Sets argv */
|
||||||
void set_argv(const wcstring_list_t &argv) { argv_array.set(argv); }
|
void set_argv(const wcstring_list_t &argv) {
|
||||||
|
argv_array.set(argv);
|
||||||
|
argv0_narrow.set(argv.empty() ? L"" : argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns argv */
|
/** Returns argv */
|
||||||
const wchar_t * const *get_argv(void) const { return argv_array.get(); }
|
const wchar_t * const *get_argv(void) const { return argv_array.get(); }
|
||||||
const null_terminated_array_t<wchar_t> &get_argv_array(void) const { return argv_array; }
|
const null_terminated_array_t<wchar_t> &get_argv_array(void) const { return argv_array; }
|
||||||
|
|
||||||
/** Returns argv[0] */
|
|
||||||
const wchar_t *argv0(void) const { return argv_array.get()[0]; }
|
|
||||||
|
|
||||||
/** Returns argv[idx] */
|
/** Returns argv[idx] */
|
||||||
const wchar_t *argv(size_t idx) const { return argv_array.get()[idx]; }
|
const wchar_t *argv(size_t idx) const {
|
||||||
|
const wchar_t * const *argv = argv_array.get();
|
||||||
|
assert(argv != NULL);
|
||||||
|
return argv[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns argv[0], or NULL */
|
||||||
|
const wchar_t *argv0(void) const {
|
||||||
|
const wchar_t * const *argv = argv_array.get();
|
||||||
|
return argv ? argv[0] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns argv[0] as a char * */
|
||||||
|
const char *argv0_cstr(void) const {
|
||||||
|
return argv0_narrow.get();
|
||||||
|
}
|
||||||
|
|
||||||
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. malloc'd! */
|
/** actual command to pass to exec in case of EXTERNAL or INTERNAL_EXEC. malloc'd! */
|
||||||
const wchar_t *actual_cmd;
|
const wchar_t *actual_cmd;
|
||||||
|
@ -283,6 +306,20 @@ void release_job_id(job_id_t jobid);
|
||||||
|
|
||||||
class job_t
|
class job_t
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
The original command which led to the creation of this
|
||||||
|
job. It is used for displaying messages about job status
|
||||||
|
on the terminal.
|
||||||
|
*/
|
||||||
|
wcstring command;
|
||||||
|
|
||||||
|
/* narrow copy so we don't have to convert after fork */
|
||||||
|
narrow_string_rep_t command_narrow;
|
||||||
|
|
||||||
|
/* No copying */
|
||||||
|
job_t(const job_t &rhs) : job_id(0) { }
|
||||||
|
void operator=(const job_t &) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
job_t(job_id_t jobid) :
|
job_t(job_id_t jobid) :
|
||||||
|
@ -307,16 +344,21 @@ class job_t
|
||||||
}
|
}
|
||||||
release_job_id(job_id);
|
release_job_id(job_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** Returns whether the command is empty. */
|
||||||
The original command which led to the creation of this
|
bool command_is_empty() const { return command.empty(); }
|
||||||
job. It is used for displaying messages about job status
|
|
||||||
on the terminal.
|
|
||||||
*/
|
|
||||||
wcstring command;
|
|
||||||
|
|
||||||
const wchar_t *command_cstr() const { return command.c_str(); }
|
/** Returns the command as a wchar_t *. */
|
||||||
|
const wchar_t *command_wcstr() const { return command.c_str(); }
|
||||||
|
|
||||||
|
/** Returns the command as a char *. */
|
||||||
|
const char *command_cstr() const { return command_narrow.get(); }
|
||||||
|
|
||||||
|
/** Sets the command */
|
||||||
|
void set_command(const wcstring &cmd) {
|
||||||
|
command = cmd;
|
||||||
|
command_narrow.set(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A linked list of all the processes in this job. We are responsible for deleting this when we are deallocated.
|
A linked list of all the processes in this job. We are responsible for deleting this when we are deallocated.
|
||||||
|
|
|
@ -194,6 +194,7 @@ bool set_cloexec(int fd) {
|
||||||
|
|
||||||
static int wopen_internal(const wcstring &pathname, int flags, mode_t mode, bool cloexec)
|
static int wopen_internal(const wcstring &pathname, int flags, mode_t mode, bool cloexec)
|
||||||
{
|
{
|
||||||
|
ASSERT_IS_NOT_FORKED_CHILD();
|
||||||
cstring tmp = wcs2string(pathname);
|
cstring tmp = wcs2string(pathname);
|
||||||
/* Prefer to use O_CLOEXEC. It has to both be defined and nonzero */
|
/* Prefer to use O_CLOEXEC. It has to both be defined and nonzero */
|
||||||
#ifdef O_CLOEXEC
|
#ifdef O_CLOEXEC
|
||||||
|
@ -214,6 +215,7 @@ int wopen(const wcstring &pathname, int flags, mode_t mode)
|
||||||
{
|
{
|
||||||
// off the main thread, always use wopen_cloexec
|
// off the main thread, always use wopen_cloexec
|
||||||
ASSERT_IS_MAIN_THREAD();
|
ASSERT_IS_MAIN_THREAD();
|
||||||
|
ASSERT_IS_NOT_FORKED_CHILD();
|
||||||
return wopen_internal(pathname, flags, mode, false);
|
return wopen_internal(pathname, flags, mode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue