aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--builtin.cpp12
-rw-r--r--builtin_jobs.cpp2
-rw-r--r--common.cpp44
-rw-r--r--common.h24
-rw-r--r--event.cpp4
-rw-r--r--exec.cpp37
-rw-r--r--exec.h4
-rw-r--r--expand.cpp14
-rw-r--r--io.cpp2
-rw-r--r--io.h32
-rw-r--r--parser.cpp14
-rw-r--r--postfork.cpp97
-rw-r--r--proc.cpp24
-rw-r--r--proc.h68
-rw-r--r--wutil.cpp2
15 files changed, 251 insertions, 129 deletions
diff --git a/builtin.cpp b/builtin.cpp
index f16c065e..57c53d79 100644
--- a/builtin.cpp
+++ b/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" ),
argv[0],
pid,
- j->command_cstr() );
+ j->command_wcstr() );
builtin_print_help( parser, argv[0], stderr_buffer );
j=0;
}
@@ -2978,7 +2978,7 @@ static int builtin_fg( parser_t &parser, wchar_t **argv )
append_format(stderr_buffer,
FG_MSG,
j->job_id,
- j->command_cstr() );
+ j->command_wcstr() );
}
else
{
@@ -2990,10 +2990,10 @@ static int builtin_fg( parser_t &parser, wchar_t **argv )
fwprintf( stderr,
FG_MSG,
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 )
env_set( L"_", ft, ENV_EXPORT );
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"bg",
j->job_id,
- j->command_cstr() );
+ j->command_wcstr() );
builtin_print_help( parser, L"bg", stderr_buffer );
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,
_(L"Send job %d '%ls' to background\n"),
j->job_id,
- j->command_cstr() );
+ j->command_wcstr() );
}
make_first( j );
job_set_flag( j, JOB_FOREGROUND, 0 );
diff --git a/builtin_jobs.cpp b/builtin_jobs.cpp
index 957b54c6..904d62c7 100644
--- a/builtin_jobs.cpp
+++ b/builtin_jobs.cpp
@@ -98,7 +98,7 @@ static void builtin_jobs_print( const job_t *j, int mode, int header )
#endif
stdout_buffer.append(job_is_stopped(j)?_(L"stopped"):_(L"running"));
stdout_buffer.append(L"\t");
- stdout_buffer.append(j->command_cstr());
+ stdout_buffer.append(j->command_wcstr());
stdout_buffer.append(L"\t");
break;
}
diff --git a/common.cpp b/common.cpp
index 20840c4a..bf47fabc 100644
--- a/common.cpp
+++ b/common.cpp
@@ -299,14 +299,31 @@ wchar_t *str2wcs_internal( const char *in, wchar_t *out )
char *wcs2str( const wchar_t *in )
{
- char *out;
-
- out = (char *)malloc( MAX_UTF8_BYTES*wcslen(in)+1 );
-
- if( !out )
- {
- DIE_MEM();
- }
+ if (! in)
+ return NULL;
+ char *out;
+ size_t desired_size = MAX_UTF8_BYTES*wcslen(in)+1;
+ char local_buff[512];
+ if (desired_size <= sizeof local_buff / sizeof *local_buff) {
+ // 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 );
}
@@ -727,8 +744,9 @@ void debug( int level, const wchar_t *msg, ... )
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)
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') {
/* Handle a format string */
- const char *format = NULL;
- switch (param_idx++) {
- case 0: format = param1; break;
- case 1: format = param2; break;
- case 2: format = param3; break;
- }
+ assert(param_idx < sizeof params / sizeof *params);
+ const char *format = params[param_idx++];
if (! format)
format = "(null)";
write(STDERR_FILENO, format, strlen(format));
diff --git a/common.h b/common.h
index 7f943ac1..4c24afdb 100644
--- a/common.h
+++ b/common.h
@@ -288,7 +288,7 @@ wcstring format_size(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. */
-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 */
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> */
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();
/* Basic scoped lock class */
diff --git a/event.cpp b/event.cpp
index 4a9f9222..a36b729f 100644
--- a/event.cpp
+++ b/event.cpp
@@ -192,7 +192,7 @@ wcstring event_get_desc( const event_t *e )
{
job_t *j = job_get_from_pid( -e->param1.pid );
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
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 );
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
result = format_string(_(L"exit handler for job with job id %d"), j->job_id );
diff --git a/exec.cpp b/exec.cpp
index 54ee809a..111cb50b 100644
--- a/exec.cpp
+++ b/exec.cpp
@@ -65,7 +65,7 @@
/**
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
@@ -448,11 +448,11 @@ static io_data_t *io_transmogrify( io_data_t * in )
{
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,
FILE_ERROR,
- in->filename.c_str() );
+ in->filename_cstr );
wperror( L"open" );
return NULL;
@@ -574,7 +574,7 @@ void exec( parser_t &parser, job_t *j )
sigemptyset( &chldset );
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 )
{
@@ -689,6 +689,9 @@ void exec( parser_t &parser, job_t *j )
if( needs_keepalive )
{
/* 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);
if( keepalive.pid == 0 )
{
@@ -880,13 +883,13 @@ void exec( parser_t &parser, job_t *j )
case IO_FILE:
{
/* 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 );
if( builtin_stdin == -1 )
{
debug( 1,
FILE_ERROR,
- in->filename.c_str() );
+ in->filename_cstr );
wperror( L"open" );
}
else
@@ -1045,6 +1048,9 @@ void exec( parser_t &parser, job_t *j )
if( io_buffer->out_buffer_size() > 0 )
{
/* 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);
if( pid == 0 )
{
@@ -1093,6 +1099,10 @@ void exec( parser_t &parser, job_t *j )
const char *buffer = input_redirect->out_buffer_ptr();
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);
if( pid == 0 )
{
@@ -1148,7 +1158,7 @@ void exec( parser_t &parser, job_t *j )
*/
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() ) &&
( !p->next ) &&
@@ -1160,9 +1170,9 @@ void exec( parser_t &parser, job_t *j )
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;
}
@@ -1173,7 +1183,7 @@ void exec( parser_t &parser, job_t *j )
p->completed=1;
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;
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(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);
if( pid == 0 )
{
@@ -1240,9 +1254,6 @@ void exec( parser_t &parser, job_t *j )
const wchar_t *reader_current_filename();
if (g_log_forks) {
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 */);
if( pid == 0 )
diff --git a/exec.h b/exec.h
index 5d882a00..4fa4b10c 100644
--- a/exec.h
+++ b/exec.h
@@ -59,8 +59,8 @@ __warn_unused int exec_subshell(const wcstring &cmd );
/**
- Loops over close until thesyscall was run without beeing
- interrupted. Thenremoves the fd from the open_fds list.
+ Loops over close until the syscall was run without being
+ interrupted. Then removes the fd from the open_fds list.
*/
void exec_close( int fd );
diff --git a/expand.cpp b/expand.cpp
index 4b201195..047d02e1 100644
--- a/expand.cpp
+++ b/expand.cpp
@@ -348,14 +348,14 @@ static int find_process( const wchar_t *proc,
while ((j = jobs.next()))
{
wchar_t jid[16];
- if( j->command.size() == 0 )
+ if( j->command_is_empty() )
continue;
swprintf( jid, 16, L"%d", j->job_id );
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,
jid+wcslen(proc),
desc_buff,
@@ -375,7 +375,7 @@ static int find_process( const wchar_t *proc,
if( jid > 0 && !errno && !*end )
{
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;
- if( j->command_cstr() == 0 )
+ if( j->command_wcstr() == 0 )
continue;
- if( match_pid( j->command_cstr(), proc, flags, &offset ) )
+ if( match_pid( j->command_wcstr(), proc, flags, &offset ) )
{
if( flags & ACCEPT_INCOMPLETE )
{
completion_allocate( out,
- j->command_cstr() + offset + wcslen(proc),
+ j->command_wcstr() + offset + wcslen(proc),
COMPLETE_JOB_DESC,
0 );
}
@@ -425,7 +425,7 @@ static int find_process( const wchar_t *proc,
while ((j = jobs.next()))
{
process_t *p;
- if( j->command.size() == 0 )
+ if( j->command_is_empty() )
continue;
for( p=j->first_process; p; p=p->next )
{
diff --git a/io.cpp b/io.cpp
index 08bdf5d5..d238e143 100644
--- a/io.cpp
+++ b/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 )
{
- if( io == 0 )
+ if( io == NULL )
return 0;
io_data_t *res = io_get( io->next, fd );
diff --git a/io.h b/io.h
index 58fc1f88..df1cef9d 100644
--- a/io.h
+++ b/io.h
@@ -40,8 +40,6 @@ public:
int old_fd;
} param1;
- /** Filename IO_FILE */
- wcstring filename;
/** Second type-specific paramter for redirection */
union
@@ -52,6 +50,15 @@ public:
int close_old;
} 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 */
void out_buffer_create() {
out_buffer.reset(new std::vector<char>);
@@ -81,11 +88,26 @@ public:
/** Pointer to the next IO redirection */
io_data_t *next;
- io_data_t() : next(NULL)
+ io_data_t() : filename_cstr(NULL), next(NULL)
+ {
+ }
+
+ 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)
{
+
}
- /* Note: we have a default copy constructor */
+ ~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
- 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.
\param is_input set this parameter to zero if the buffer should be
diff --git a/parser.cpp b/parser.cpp
index ac01b371..5774f327 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -1538,25 +1538,25 @@ void parser_t::parse_job_argument_list( process_t *p,
case TOK_REDIRECT_APPEND:
new_io->io_mode = IO_FILE;
new_io->param2.flags = O_CREAT | O_APPEND | O_WRONLY;
- new_io->filename = target;
+ new_io->set_filename(target);
break;
case TOK_REDIRECT_OUT:
new_io->io_mode = IO_FILE;
new_io->param2.flags = O_CREAT | O_WRONLY | O_TRUNC;
- new_io->filename = target;
+ new_io->set_filename(target);
break;
case TOK_REDIRECT_NOCLOB:
new_io->io_mode = IO_FILE;
new_io->param2.flags = O_CREAT | O_EXCL | O_WRONLY;
- new_io->filename = target;
+ new_io->set_filename(target);
break;
case TOK_REDIRECT_IN:
new_io->io_mode = IO_FILE;
new_io->param2.flags = O_RDONLY;
- new_io->filename = target;
+ new_io->set_filename(target);
break;
case TOK_REDIRECT_FD:
@@ -2311,15 +2311,15 @@ void parser_t::eval_job( tokenizer *tok )
if( newline )
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
- j->command = L"";
+ j->set_command(L"");
if( profile )
{
t2 = get_time();
- profile_item->cmd = wcsdup( j->command_cstr() );
+ profile_item->cmd = wcsdup( j->command_wcstr() );
profile_item->skipped=current_block->skip;
}
diff --git a/postfork.cpp b/postfork.cpp
index 523a7816..cf9c931f 100644
--- a/postfork.cpp
+++ b/postfork.cpp
@@ -20,17 +20,27 @@
#define OPEN_MASK 0666
/** 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 */
-#define NOCLOB_ERROR _( L"The file '%ls' already exists" )
+#define NOCLOB_ERROR "The file '%s' already exists"
/** 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 */
-#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.
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 )
{
+ 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.
- debug( 1,
- _( L"Could not send process %d, '%ls' in job %d, '%ls' from group %d to group %d" ),
- p->pid,
- p->argv0(),
- j->job_id,
+ debug_safe( 1,
+ "Could not send process %s, '%s' in job %s, '%s' from group %s to group %s",
+ pid_buff,
+ p->argv0_cstr(),
+ job_id_buff,
j->command_cstr(),
- getpgid( p->pid),
- j->pgid );
+ getpgid_buff,
+ job_pgid_buff );
wperror( L"setpgid" );
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 )
{
- debug( 1, _( L"Could not send job %d ('%ls') to foreground" ),
- j->job_id,
- j->command_cstr() );
+ char job_id_buff[128];
+ format_long_safe(job_id_buff, j->job_id);
+ debug_safe( 1, "Could not send job %s ('%s') to foreground", job_id_buff, j->command_cstr() );
wperror( L"tcsetpgrp" );
res = -1;
}
@@ -102,9 +122,7 @@ static void free_fd( io_data_t *io, int fd )
{
if( errno != EINTR )
{
- debug( 1,
- FD_ERROR,
- fd );
+ debug_safe_int( 1, FD_ERROR, fd );
wperror( L"dup" );
FATAL_EXIT();
}
@@ -161,7 +179,7 @@ static int handle_child_io( io_data_t *io )
{
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" );
}
break;
@@ -170,23 +188,18 @@ static int handle_child_io( io_data_t *io )
case IO_FILE:
{
// 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 )
{
if( ( io->param2.flags & O_EXCL ) &&
( errno ==EEXIST ) )
{
- debug( 1,
- NOCLOB_ERROR,
- io->filename.c_str() );
+ debug_safe( 1, NOCLOB_ERROR, io->filename_cstr );
}
else
{
- debug( 1,
- FILE_ERROR,
- io->filename.c_str() );
-
- wperror( L"open" );
+ debug_safe( 1, FILE_ERROR, io->filename_cstr );
+ perror( "open" );
}
return -1;
@@ -201,10 +214,8 @@ static int handle_child_io( io_data_t *io )
if(dup2( tmp, io->fd ) == -1 )
{
- debug( 1,
- FD_ERROR,
- io->fd );
- wperror( L"dup2" );
+ debug_safe_int( 1, FD_ERROR, io->fd );
+ perror( "dup2" );
return -1;
}
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 )
{
- debug( 1,
- FD_ERROR,
- io->fd );
+ debug_safe_int( 1, FD_ERROR, io->fd );
wperror( L"dup2" );
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 )
{
- debug( 1, PIPE_ERROR );
- wperror( L"dup2" );
+ debug_safe( 1, LOCAL_PIPE_ERROR );
+ perror( "dup2" );
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 res=0;
+ bool ok=true;
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 );
- if( p != 0 && res )
+ ok = (0 == handle_child_io( j->io ));
+ if( p != 0 && ! ok )
{
exit_without_destructors( 1 );
}
}
/* Set the handling for job control signals back to the default. */
- if( !res )
+ if( ok )
{
signal_reset_handlers();
}
@@ -300,7 +309,7 @@ int setup_child_process( job_t *j, process_t *p )
/* Remove all signal blocks */
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");
FATAL_EXIT();
return 0;
diff --git a/proc.cpp b/proc.cpp
index 7ad35bd4..17a5fd9b 100644
--- a/proc.cpp
+++ b/proc.cpp
@@ -184,7 +184,7 @@ void proc_destroy()
while( ! jobs.empty() )
{
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 );
}
}
@@ -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 )
{
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 );
tputs(clr_eol,1,&writeb);
fwprintf (stdout, L"\n" );
@@ -613,7 +613,7 @@ int job_reap( bool interactive )
_( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
program_name,
j->job_id,
- j->command_cstr(),
+ j->command_wcstr(),
sig2wcs(WTERMSIG(p->status)),
signal_get_desc( WTERMSIG(p->status) ) );
else
@@ -623,7 +623,7 @@ int job_reap( bool interactive )
p->pid,
p->argv0(),
j->job_id,
- j->command_cstr(),
+ j->command_wcstr(),
sig2wcs(WTERMSIG(p->status)),
signal_get_desc( WTERMSIG(p->status) ) );
tputs(clr_eol,1,&writeb);
@@ -857,7 +857,7 @@ static void read_try( job_t *j )
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)
{
char b[BUFFER_SIZE];
@@ -905,7 +905,7 @@ static int terminal_give_to_job( job_t *j, int cont )
debug( 1,
_( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
- j->command_cstr() );
+ j->command_wcstr() );
wperror( L"tcsetpgrp" );
return 0;
}
@@ -917,7 +917,7 @@ static int terminal_give_to_job( job_t *j, int cont )
debug( 1,
_( L"Could not send job %d ('%ls') to foreground" ),
j->job_id,
- j->command_cstr() );
+ j->command_wcstr() );
wperror( L"tcsetattr" );
return 0;
}
@@ -977,7 +977,7 @@ void job_continue (job_t *j, int cont)
L"Continue job %d, gid %d (%ls), %ls, %ls",
j->job_id,
j->pgid,
- j->command_cstr(),
+ j->command_wcstr(),
job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
@@ -1188,8 +1188,8 @@ void proc_sanity_check()
{
debug( 0,
_( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
- fg_job->command_cstr(),
- j->command_cstr() );
+ fg_job->command_wcstr(),
+ j->command_wcstr() );
sanity_lose();
}
fg_job = j;
@@ -1207,7 +1207,7 @@ void proc_sanity_check()
{
debug( 0,
_( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
- j->command_cstr(),
+ j->command_wcstr(),
p->argv0(),
p->stopped );
sanity_lose();
@@ -1217,7 +1217,7 @@ void proc_sanity_check()
{
debug( 0,
_( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
- j->command_cstr(),
+ j->command_wcstr(),
p->argv0(),
p->completed );
sanity_lose();
diff --git a/proc.h b/proc.h
index 06757cae..45de45a1 100644
--- a/proc.h
+++ b/proc.h
@@ -130,7 +130,15 @@ class process_t
private:
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:
process_t() :
@@ -168,17 +176,32 @@ class process_t
/** 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 */
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; }
- /** Returns argv[0] */
- const wchar_t *argv0(void) const { return argv_array.get()[0]; }
-
/** 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! */
const wchar_t *actual_cmd;
@@ -283,6 +306,20 @@ void release_job_id(job_id_t jobid);
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:
job_t(job_id_t jobid) :
@@ -307,16 +344,21 @@ class job_t
}
release_job_id(job_id);
}
-
- /**
- 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;
+ /** Returns whether the command is empty. */
+ bool command_is_empty() const { return command.empty(); }
- 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.
diff --git a/wutil.cpp b/wutil.cpp
index 7e428931..da664916 100644
--- a/wutil.cpp
+++ b/wutil.cpp
@@ -194,6 +194,7 @@ bool set_cloexec(int fd) {
static int wopen_internal(const wcstring &pathname, int flags, mode_t mode, bool cloexec)
{
+ ASSERT_IS_NOT_FORKED_CHILD();
cstring tmp = wcs2string(pathname);
/* Prefer to use O_CLOEXEC. It has to both be defined and nonzero */
#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
ASSERT_IS_MAIN_THREAD();
+ ASSERT_IS_NOT_FORKED_CHILD();
return wopen_internal(pathname, flags, mode, false);
}