mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Merge branch 'split-io' of git://github.com/xiaq/fish-shell into xiaq-split-io
This commit is contained in:
commit
f850c021b7
8 changed files with 308 additions and 242 deletions
6
common.h
6
common.h
|
@ -22,6 +22,12 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Avoid writing the type name twice in a common "static_cast-initialization".
|
||||||
|
Caveat: This doesn't work with type names containing commas!
|
||||||
|
*/
|
||||||
|
#define CAST_INIT(type, dst, src) type dst = static_cast<type >(src)
|
||||||
|
|
||||||
class completion_t;
|
class completion_t;
|
||||||
|
|
||||||
/* Common string type */
|
/* Common string type */
|
||||||
|
|
110
exec.cpp
110
exec.cpp
|
@ -164,8 +164,8 @@ static bool use_fd_in_pipe(int fd, const io_chain_t &io_chain)
|
||||||
if ((io->io_mode == IO_BUFFER) ||
|
if ((io->io_mode == IO_BUFFER) ||
|
||||||
(io->io_mode == IO_PIPE))
|
(io->io_mode == IO_PIPE))
|
||||||
{
|
{
|
||||||
if (io->param1.pipe_fd[0] == fd ||
|
CAST_INIT(const io_pipe_t *, io_pipe, io.get());
|
||||||
io->param1.pipe_fd[1] == fd)
|
if (io_pipe->pipe_fd[0] == fd || io_pipe->pipe_fd[1] == fd)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,17 +406,13 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t &out_chain, s
|
||||||
*/
|
*/
|
||||||
case IO_FILE:
|
case IO_FILE:
|
||||||
{
|
{
|
||||||
out.reset(new io_data_t());
|
|
||||||
out->fd = in->fd;
|
|
||||||
out->io_mode = IO_FD;
|
|
||||||
out->param2.close_old = 1;
|
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
if ((fd=open(in->filename_cstr, in->param2.flags, OPEN_MASK))==-1)
|
CAST_INIT(io_file_t *, in_file, in.get());
|
||||||
|
if ((fd=open(in_file->filename_cstr, in_file->flags, OPEN_MASK))==-1)
|
||||||
{
|
{
|
||||||
debug(1,
|
debug(1,
|
||||||
FILE_ERROR,
|
FILE_ERROR,
|
||||||
in->filename_cstr);
|
in_file->filename_cstr);
|
||||||
|
|
||||||
wperror(L"open");
|
wperror(L"open");
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -424,7 +420,7 @@ static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t &out_chain, s
|
||||||
}
|
}
|
||||||
|
|
||||||
opened_fds.push_back(fd);
|
opened_fds.push_back(fd);
|
||||||
out->param1.old_fd = fd;
|
out.reset(new io_fd_t(in->fd, fd, true));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -521,7 +517,8 @@ static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *proce
|
||||||
const shared_ptr<const io_data_t> &io = job->io.at(idx);
|
const shared_ptr<const io_data_t> &io = job->io.at(idx);
|
||||||
if (io->io_mode == IO_FILE)
|
if (io->io_mode == IO_FILE)
|
||||||
{
|
{
|
||||||
const char *path = io->filename_cstr;
|
CAST_INIT(const io_file_t *, io_file, io.get());
|
||||||
|
const char *path = io_file->filename_cstr;
|
||||||
/* This IO action is a file redirection. Only allow /dev/null, which is a common case we assume won't fail. */
|
/* This IO action is a file redirection. Only allow /dev/null, which is a common case we assume won't fail. */
|
||||||
if (strcmp(path, "/dev/null") != 0)
|
if (strcmp(path, "/dev/null") != 0)
|
||||||
{
|
{
|
||||||
|
@ -541,7 +538,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
int mypipe[2];
|
int mypipe[2];
|
||||||
sigset_t chldset;
|
sigset_t chldset;
|
||||||
|
|
||||||
shared_ptr<io_data_t> io_buffer;
|
shared_ptr<io_buffer_t> io_buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set to true if something goes wrong while exec:ing the job, in
|
Set to true if something goes wrong while exec:ing the job, in
|
||||||
|
@ -569,25 +566,29 @@ void exec(parser_t &parser, job_t *j)
|
||||||
io_duplicate_prepend(parser.block_io, j->io);
|
io_duplicate_prepend(parser.block_io, j->io);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<const io_data_t> input_redirect;
|
const io_buffer_t *input_redirect = 0;
|
||||||
for (size_t idx = 0; idx < j->io.size(); idx++)
|
for (size_t idx = 0; idx < j->io.size(); idx++)
|
||||||
{
|
{
|
||||||
input_redirect = j->io.at(idx);
|
shared_ptr<io_data_t> &io = j->io.at(idx);
|
||||||
|
|
||||||
if ((input_redirect->io_mode == IO_BUFFER) &&
|
if ((io->io_mode == IO_BUFFER))
|
||||||
input_redirect->is_input)
|
|
||||||
{
|
{
|
||||||
/*
|
CAST_INIT(io_buffer_t *, io_buffer, io.get());
|
||||||
Input redirection - create a new gobetween process to take
|
if (io_buffer->is_input)
|
||||||
care of buffering
|
{
|
||||||
*/
|
/*
|
||||||
process_t *fake = new process_t();
|
Input redirection - create a new gobetween process to take
|
||||||
fake->type = INTERNAL_BUFFER;
|
care of buffering, save the redirection in input_redirect
|
||||||
fake->pipe_write_fd = 1;
|
*/
|
||||||
j->first_process->pipe_read_fd = input_redirect->fd;
|
process_t *fake = new process_t();
|
||||||
fake->next = j->first_process;
|
fake->type = INTERNAL_BUFFER;
|
||||||
j->first_process = fake;
|
fake->pipe_write_fd = 1;
|
||||||
break;
|
j->first_process->pipe_read_fd = io->fd;
|
||||||
|
fake->next = j->first_process;
|
||||||
|
j->first_process = fake;
|
||||||
|
input_redirect = io_buffer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,17 +619,11 @@ void exec(parser_t &parser, job_t *j)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<io_data_t> pipe_read(new io_data_t);
|
shared_ptr<io_pipe_t> pipe_read(new io_pipe_t(0, true));
|
||||||
pipe_read->fd = 0;
|
pipe_read->pipe_fd[0] = pipe_read->pipe_fd[1] = -1;
|
||||||
pipe_read->io_mode = IO_PIPE;
|
|
||||||
pipe_read->is_input = 1;
|
|
||||||
pipe_read->param1.pipe_fd[0] = pipe_read->param1.pipe_fd[1] = -1;
|
|
||||||
|
|
||||||
shared_ptr<io_data_t> pipe_write(new io_data_t);
|
shared_ptr<io_pipe_t> pipe_write(new io_pipe_t(1, false));
|
||||||
pipe_write->fd = 1;
|
pipe_write->pipe_fd[0] = pipe_write->pipe_fd[1] = -1;
|
||||||
pipe_write->io_mode = IO_PIPE;
|
|
||||||
pipe_write->is_input = 0;
|
|
||||||
pipe_write->param1.pipe_fd[0] = pipe_write->param1.pipe_fd[1] = -1;
|
|
||||||
|
|
||||||
j->io.push_back(pipe_write);
|
j->io.push_back(pipe_write);
|
||||||
|
|
||||||
|
@ -741,7 +736,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(pipe_write->param1.pipe_fd, mypipe, sizeof(int)*2);
|
memcpy(pipe_write->pipe_fd, mypipe, sizeof(int)*2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -804,7 +799,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
|
|
||||||
if (p->next)
|
if (p->next)
|
||||||
{
|
{
|
||||||
io_buffer.reset(io_buffer_create(0));
|
io_buffer.reset(io_buffer_t::create(0));
|
||||||
j->io.push_back(io_buffer);
|
j->io.push_back(io_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,7 +816,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
{
|
{
|
||||||
if (p->next)
|
if (p->next)
|
||||||
{
|
{
|
||||||
io_buffer.reset(io_buffer_create(0));
|
io_buffer.reset(io_buffer_t::create(0));
|
||||||
j->io.push_back(io_buffer);
|
j->io.push_back(io_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,25 +847,28 @@ void exec(parser_t &parser, job_t *j)
|
||||||
|
|
||||||
case IO_FD:
|
case IO_FD:
|
||||||
{
|
{
|
||||||
builtin_stdin = in->param1.old_fd;
|
CAST_INIT(const io_fd_t *, in_fd, in.get());
|
||||||
|
builtin_stdin = in_fd->old_fd;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IO_PIPE:
|
case IO_PIPE:
|
||||||
{
|
{
|
||||||
builtin_stdin = in->param1.pipe_fd[0];
|
CAST_INIT(const io_pipe_t *, in_pipe, in.get());
|
||||||
|
builtin_stdin = in_pipe->pipe_fd[0];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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=open(in->filename_cstr,
|
CAST_INIT(const io_file_t *, in_file, in.get());
|
||||||
in->param2.flags, OPEN_MASK);
|
builtin_stdin=open(in_file->filename_cstr,
|
||||||
|
in_file->flags, OPEN_MASK);
|
||||||
if (builtin_stdin == -1)
|
if (builtin_stdin == -1)
|
||||||
{
|
{
|
||||||
debug(1,
|
debug(1,
|
||||||
FILE_ERROR,
|
FILE_ERROR,
|
||||||
in->filename_cstr);
|
in_file->filename_cstr);
|
||||||
wperror(L"open");
|
wperror(L"open");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -909,7 +907,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builtin_stdin = pipe_read->param1.pipe_fd[0];
|
builtin_stdin = pipe_read->pipe_fd[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builtin_stdin == -1)
|
if (builtin_stdin == -1)
|
||||||
|
@ -1009,7 +1007,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
|
|
||||||
io_remove(j->io, io_buffer);
|
io_remove(j->io, io_buffer);
|
||||||
|
|
||||||
io_buffer_read(io_buffer.get());
|
io_buffer->read();
|
||||||
|
|
||||||
const char *buffer = io_buffer->out_buffer_ptr();
|
const char *buffer = io_buffer->out_buffer_ptr();
|
||||||
size_t count = io_buffer->out_buffer_size();
|
size_t count = io_buffer->out_buffer_size();
|
||||||
|
@ -1055,8 +1053,6 @@ void exec(parser_t &parser, job_t *j)
|
||||||
p->completed = 1;
|
p->completed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
io_buffer_destroy(io_buffer);
|
|
||||||
|
|
||||||
io_buffer.reset();
|
io_buffer.reset();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1136,8 +1132,9 @@ void exec(parser_t &parser, job_t *j)
|
||||||
(! get_stdout_buffer().empty()) &&
|
(! get_stdout_buffer().empty()) &&
|
||||||
(buffer_stdout))
|
(buffer_stdout))
|
||||||
{
|
{
|
||||||
|
CAST_INIT(io_buffer_t *, io_buffer, io.get());
|
||||||
const std::string res = wcs2string(get_stdout_buffer());
|
const std::string res = wcs2string(get_stdout_buffer());
|
||||||
io->out_buffer_append(res.c_str(), res.size());
|
io_buffer->out_buffer_append(res.c_str(), res.size());
|
||||||
skip_fork = true;
|
skip_fork = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1162,7 +1159,7 @@ void exec(parser_t &parser, job_t *j)
|
||||||
for (io_chain_t::iterator iter = j->io.begin(); iter != j->io.end(); iter++)
|
for (io_chain_t::iterator iter = j->io.begin(); iter != j->io.end(); iter++)
|
||||||
{
|
{
|
||||||
const shared_ptr<io_data_t> &tmp_io = *iter;
|
const shared_ptr<io_data_t> &tmp_io = *iter;
|
||||||
if (tmp_io->io_mode == IO_FILE && strcmp(tmp_io->filename_cstr, "/dev/null") != 0)
|
if (tmp_io->io_mode == IO_FILE && strcmp(static_cast<const io_file_t *>(tmp_io.get())->filename_cstr, "/dev/null") != 0)
|
||||||
{
|
{
|
||||||
skip_fork = false;
|
skip_fork = false;
|
||||||
break;
|
break;
|
||||||
|
@ -1334,14 +1331,14 @@ void exec(parser_t &parser, job_t *j)
|
||||||
Close the pipe the current process uses to read from the
|
Close the pipe the current process uses to read from the
|
||||||
previous process_t
|
previous process_t
|
||||||
*/
|
*/
|
||||||
if (pipe_read->param1.pipe_fd[0] >= 0)
|
if (pipe_read->pipe_fd[0] >= 0)
|
||||||
exec_close(pipe_read->param1.pipe_fd[0]);
|
exec_close(pipe_read->pipe_fd[0]);
|
||||||
/*
|
/*
|
||||||
Set up the pipe the next process uses to read from the
|
Set up the pipe the next process uses to read from the
|
||||||
current process_t
|
current process_t
|
||||||
*/
|
*/
|
||||||
if (p_wants_pipe)
|
if (p_wants_pipe)
|
||||||
pipe_read->param1.pipe_fd[0] = mypipe[0];
|
pipe_read->pipe_fd[0] = mypipe[0];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If there is a next process in the pipeline, close the
|
If there is a next process in the pipeline, close the
|
||||||
|
@ -1411,7 +1408,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
|
||||||
|
|
||||||
is_subshell=1;
|
is_subshell=1;
|
||||||
|
|
||||||
const shared_ptr<io_data_t> io_buffer(io_buffer_create(0));
|
const shared_ptr<io_buffer_t> io_buffer(io_buffer_t::create(0));
|
||||||
|
|
||||||
prev_status = proc_get_last_status();
|
prev_status = proc_get_last_status();
|
||||||
|
|
||||||
|
@ -1425,7 +1422,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
|
||||||
status = proc_get_last_status();
|
status = proc_get_last_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
io_buffer_read(io_buffer.get());
|
io_buffer->read();
|
||||||
|
|
||||||
proc_set_last_status(prev_status);
|
proc_set_last_status(prev_status);
|
||||||
|
|
||||||
|
@ -1455,7 +1452,6 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io_buffer_destroy(io_buffer);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
89
io.cpp
89
io.cpp
|
@ -51,23 +51,54 @@ Utilities for io redirection.
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
|
|
||||||
void io_buffer_read(io_data_t *d)
|
io_data_t::~io_data_t()
|
||||||
{
|
{
|
||||||
exec_close(d->param1.pipe_fd[1]);
|
}
|
||||||
|
|
||||||
if (d->io_mode == IO_BUFFER)
|
void io_close_t::print() const
|
||||||
|
{
|
||||||
|
fprintf(stderr, "close %d\n", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void io_fd_t::print() const
|
||||||
|
{
|
||||||
|
fprintf(stderr, "FD map %d -> %d\n", old_fd, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void io_file_t::print() const
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file (%s)\n", filename_cstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void io_pipe_t::print() const
|
||||||
|
{
|
||||||
|
fprintf(stderr, "pipe {%d, %d} (input: %s)\n", pipe_fd[0], pipe_fd[1],
|
||||||
|
is_input ? "yes" : "no");
|
||||||
|
}
|
||||||
|
|
||||||
|
void io_buffer_t::print() const
|
||||||
|
{
|
||||||
|
fprintf(stderr, "buffer %p (input: %s, size %lu)\n", out_buffer_ptr(),
|
||||||
|
is_input ? "yes" : "no", out_buffer_size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void io_buffer_t::read()
|
||||||
|
{
|
||||||
|
exec_close(pipe_fd[1]);
|
||||||
|
|
||||||
|
if (io_mode == IO_BUFFER)
|
||||||
{
|
{
|
||||||
/* if( fcntl( d->param1.pipe_fd[0], F_SETFL, 0 ) )
|
/* if( fcntl( pipe_fd[0], F_SETFL, 0 ) )
|
||||||
{
|
{
|
||||||
wperror( L"fcntl" );
|
wperror( L"fcntl" );
|
||||||
return;
|
return;
|
||||||
} */
|
} */
|
||||||
debug(4, L"io_buffer_read: blocking read on fd %d", d->param1.pipe_fd[0]);
|
debug(4, L"io_buffer_t::read: blocking read on fd %d", pipe_fd[0]);
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
char b[4096];
|
char b[4096];
|
||||||
long l;
|
long l;
|
||||||
l=read_blocked(d->param1.pipe_fd[0], b, 4096);
|
l=read_blocked(pipe_fd[0], b, 4096);
|
||||||
if (l==0)
|
if (l==0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -85,37 +116,34 @@ void io_buffer_read(io_data_t *d)
|
||||||
{
|
{
|
||||||
debug(1,
|
debug(1,
|
||||||
_(L"An error occured while reading output from code block on file descriptor %d"),
|
_(L"An error occured while reading output from code block on file descriptor %d"),
|
||||||
d->param1.pipe_fd[0]);
|
pipe_fd[0]);
|
||||||
wperror(L"io_buffer_read");
|
wperror(L"io_buffer_t::read");
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d->out_buffer_append(b, l);
|
out_buffer_append(b, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
io_data_t *io_buffer_create(bool is_input)
|
io_buffer_t *io_buffer_t::create(bool is_input)
|
||||||
{
|
{
|
||||||
bool success = true;
|
bool success = true;
|
||||||
io_data_t *buffer_redirect = new io_data_t;
|
io_buffer_t *buffer_redirect = new io_buffer_t(is_input ? 0 : 1, is_input);
|
||||||
buffer_redirect->out_buffer_create();
|
buffer_redirect->out_buffer_create();
|
||||||
buffer_redirect->io_mode = IO_BUFFER;
|
|
||||||
buffer_redirect->is_input = is_input ? true : false;
|
|
||||||
buffer_redirect->fd=is_input?0:1;
|
|
||||||
|
|
||||||
if (exec_pipe(buffer_redirect->param1.pipe_fd) == -1)
|
if (exec_pipe(buffer_redirect->pipe_fd) == -1)
|
||||||
{
|
{
|
||||||
debug(1, PIPE_ERROR);
|
debug(1, PIPE_ERROR);
|
||||||
wperror(L"pipe");
|
wperror(L"pipe");
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
else if (fcntl(buffer_redirect->param1.pipe_fd[0],
|
else if (fcntl(buffer_redirect->pipe_fd[0],
|
||||||
F_SETFL,
|
F_SETFL,
|
||||||
O_NONBLOCK))
|
O_NONBLOCK))
|
||||||
{
|
{
|
||||||
|
@ -133,19 +161,19 @@ io_data_t *io_buffer_create(bool is_input)
|
||||||
return buffer_redirect;
|
return buffer_redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void io_buffer_destroy(const shared_ptr<io_data_t> &io_buffer)
|
io_buffer_t::~io_buffer_t()
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If this is an input buffer, then io_read_buffer will not have
|
If this is an input buffer, then io_read_buffer will not have
|
||||||
been called, and we need to close the output fd as well.
|
been called, and we need to close the output fd as well.
|
||||||
*/
|
*/
|
||||||
if (io_buffer->is_input)
|
if (is_input)
|
||||||
{
|
{
|
||||||
exec_close(io_buffer->param1.pipe_fd[1]);
|
exec_close(pipe_fd[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
exec_close(io_buffer->param1.pipe_fd[0]);
|
exec_close(pipe_fd[0]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Dont free fd for writing. This should already be free'd before
|
Dont free fd for writing. This should already be free'd before
|
||||||
|
@ -194,25 +222,8 @@ void io_print(const io_chain_t &chain)
|
||||||
for (size_t i=0; i < chain.size(); i++)
|
for (size_t i=0; i < chain.size(); i++)
|
||||||
{
|
{
|
||||||
const shared_ptr<const io_data_t> &io = chain.at(i);
|
const shared_ptr<const io_data_t> &io = chain.at(i);
|
||||||
fprintf(stderr, "\t%lu: fd:%d, input:%s, ", (unsigned long)i, io->fd, io->is_input ? "yes" : "no");
|
fprintf(stderr, "\t%lu: fd:%d, ", (unsigned long)i, io->fd);
|
||||||
switch (io->io_mode)
|
io->print();
|
||||||
{
|
|
||||||
case IO_FILE:
|
|
||||||
fprintf(stderr, "file (%s)\n", io->filename_cstr);
|
|
||||||
break;
|
|
||||||
case IO_PIPE:
|
|
||||||
fprintf(stderr, "pipe {%d, %d}\n", io->param1.pipe_fd[0], io->param1.pipe_fd[1]);
|
|
||||||
break;
|
|
||||||
case IO_FD:
|
|
||||||
fprintf(stderr, "FD map %d -> %d\n", io->param1.old_fd, io->fd);
|
|
||||||
break;
|
|
||||||
case IO_BUFFER:
|
|
||||||
fprintf(stderr, "buffer %p (size %lu)\n", io->out_buffer_ptr(), io->out_buffer_size());
|
|
||||||
break;
|
|
||||||
case IO_CLOSE:
|
|
||||||
fprintf(stderr, "close %d\n", io->fd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
171
io.h
171
io.h
|
@ -8,7 +8,7 @@ using std::tr1::shared_ptr;
|
||||||
/**
|
/**
|
||||||
Describes what type of IO operation an io_data_t represents
|
Describes what type of IO operation an io_data_t represents
|
||||||
*/
|
*/
|
||||||
enum io_mode
|
enum io_mode_t
|
||||||
{
|
{
|
||||||
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
|
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
|
||||||
};
|
};
|
||||||
|
@ -17,42 +17,63 @@ enum io_mode
|
||||||
class io_data_t
|
class io_data_t
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
/** buffer to save output in for IO_BUFFER. Note that in the original fish, the buffer was a pointer to a buffer_t stored in the param2 union down below, and when an io_data_t was duplicated the pointer was copied so that two io_data_ts referenced the same buffer. It's not clear to me how this was ever cleaned up correctly. But it's important that they share the same buffer for reasons I don't yet understand either. We can get correct sharing and cleanup with shared_ptr. */
|
|
||||||
shared_ptr<std::vector<char> > out_buffer;
|
|
||||||
|
|
||||||
/* No assignment or copying allowed */
|
/* No assignment or copying allowed */
|
||||||
io_data_t(const io_data_t &rhs);
|
io_data_t(const io_data_t &rhs);
|
||||||
void operator=(const io_data_t &rhs);
|
void operator=(const io_data_t &rhs);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
io_data_t(io_mode_t m, int f) :
|
||||||
|
io_mode(m),
|
||||||
|
fd(f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Type of redirect */
|
/** Type of redirect */
|
||||||
int io_mode;
|
const io_mode_t io_mode;
|
||||||
/** FD to redirect */
|
/** FD to redirect */
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/**
|
virtual void print() const = 0;
|
||||||
Type-specific parameter for redirection
|
virtual ~io_data_t() = 0;
|
||||||
*/
|
};
|
||||||
union
|
|
||||||
|
class io_close_t : public io_data_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
io_close_t(int f) :
|
||||||
|
io_data_t(IO_CLOSE, f)
|
||||||
{
|
{
|
||||||
/** Fds for IO_PIPE and for IO_BUFFER */
|
}
|
||||||
int pipe_fd[2];
|
|
||||||
/** fd to redirect specified fd to, for IO_FD */
|
|
||||||
int old_fd;
|
|
||||||
} param1;
|
|
||||||
|
|
||||||
|
virtual void print() const;
|
||||||
|
};
|
||||||
|
|
||||||
/** Second type-specific paramter for redirection */
|
class io_fd_t : public io_data_t
|
||||||
union
|
{
|
||||||
|
public:
|
||||||
|
/** fd to redirect specified fd to */
|
||||||
|
int old_fd;
|
||||||
|
/** Whether to close old_fd */
|
||||||
|
int close_old;
|
||||||
|
|
||||||
|
virtual void print() const;
|
||||||
|
|
||||||
|
io_fd_t(int f, int old, bool close = false) :
|
||||||
|
io_data_t(IO_FD, f),
|
||||||
|
old_fd(old),
|
||||||
|
close_old(close)
|
||||||
{
|
{
|
||||||
/** file creation flags to send to open for IO_FILE */
|
}
|
||||||
int flags;
|
};
|
||||||
/** Whether to close old_fd for IO_FD */
|
|
||||||
int close_old;
|
|
||||||
} param2;
|
|
||||||
|
|
||||||
/** Filename IO_FILE. malloc'd. This needs to be used after fork, so don't use wcstring here. */
|
class io_file_t : public io_data_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Filename, malloc'd. This needs to be used after fork, so don't use wcstring here. */
|
||||||
const char *filename_cstr;
|
const char *filename_cstr;
|
||||||
|
/** file creation flags to send to open */
|
||||||
|
int flags;
|
||||||
|
|
||||||
/** Convenience to set filename_cstr via wcstring */
|
/** Convenience to set filename_cstr via wcstring */
|
||||||
void set_filename(const wcstring &str)
|
void set_filename(const wcstring &str)
|
||||||
|
@ -61,6 +82,62 @@ public:
|
||||||
filename_cstr = wcs2str(str.c_str());
|
filename_cstr = wcs2str(str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void print() const;
|
||||||
|
|
||||||
|
io_file_t(int f, const char *fname = NULL, int fl = 0) :
|
||||||
|
io_data_t(IO_FILE, f),
|
||||||
|
filename_cstr(fname ? strdup(fname) : NULL),
|
||||||
|
flags(fl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~io_file_t()
|
||||||
|
{
|
||||||
|
free((void *)filename_cstr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class io_pipe_t : public io_data_t
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
io_pipe_t(io_mode_t m, int f, bool i):
|
||||||
|
io_data_t(m, f),
|
||||||
|
pipe_fd(),
|
||||||
|
is_input(i)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int pipe_fd[2];
|
||||||
|
bool is_input;
|
||||||
|
|
||||||
|
virtual void print() const;
|
||||||
|
|
||||||
|
io_pipe_t(int f, bool i):
|
||||||
|
io_data_t(IO_PIPE, f),
|
||||||
|
pipe_fd(),
|
||||||
|
is_input(i)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class io_buffer_t : public io_pipe_t
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/** buffer to save output in */
|
||||||
|
shared_ptr<std::vector<char> > out_buffer;
|
||||||
|
|
||||||
|
io_buffer_t(int f, bool i):
|
||||||
|
io_pipe_t(IO_BUFFER, f, i),
|
||||||
|
out_buffer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void print() const;
|
||||||
|
|
||||||
|
virtual ~io_buffer_t();
|
||||||
|
|
||||||
/** Function to create the output buffer */
|
/** Function to create the output buffer */
|
||||||
void out_buffer_create()
|
void out_buffer_create()
|
||||||
{
|
{
|
||||||
|
@ -94,24 +171,21 @@ public:
|
||||||
return out_buffer->size();
|
return out_buffer->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set to true if this is an input io redirection */
|
/**
|
||||||
bool is_input;
|
Close output pipe, and read from input pipe until eof.
|
||||||
|
*/
|
||||||
|
void read();
|
||||||
|
|
||||||
io_data_t() :
|
/**
|
||||||
out_buffer(),
|
Create a IO_BUFFER type io redirection, complete with a pipe and a
|
||||||
io_mode(0),
|
vector<char> for output. The default file descriptor used is 1 for
|
||||||
fd(0),
|
output buffering and 0 for input buffering.
|
||||||
param1(),
|
|
||||||
param2(),
|
|
||||||
filename_cstr(NULL),
|
|
||||||
is_input(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~io_data_t()
|
\param is_input set this parameter to zero if the buffer should be
|
||||||
{
|
used to buffer the output of a command, or non-zero to buffer the
|
||||||
free((void *)filename_cstr);
|
input to a command.
|
||||||
}
|
*/
|
||||||
|
static io_buffer_t *create(bool is_input);
|
||||||
};
|
};
|
||||||
|
|
||||||
class io_chain_t : public std::vector<shared_ptr<io_data_t> >
|
class io_chain_t : public std::vector<shared_ptr<io_data_t> >
|
||||||
|
@ -151,27 +225,6 @@ shared_ptr<const io_data_t> io_chain_get(const io_chain_t &src, int fd);
|
||||||
shared_ptr<io_data_t> io_chain_get(io_chain_t &src, int fd);
|
shared_ptr<io_data_t> io_chain_get(io_chain_t &src, int fd);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Free all resources used by a IO_BUFFER type io redirection.
|
|
||||||
*/
|
|
||||||
void io_buffer_destroy(const shared_ptr<io_data_t> &io_buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Create a IO_BUFFER type io redirection, complete with a pipe and a
|
|
||||||
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
|
|
||||||
used to buffer the output of a command, or non-zero to buffer the
|
|
||||||
input to a command.
|
|
||||||
*/
|
|
||||||
io_data_t *io_buffer_create(bool is_input);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Close output pipe, and read from input pipe until eof.
|
|
||||||
*/
|
|
||||||
void io_buffer_read(io_data_t *d);
|
|
||||||
|
|
||||||
/** Print debug information about the specified IO redirection chain to stderr. */
|
/** Print debug information about the specified IO redirection chain to stderr. */
|
||||||
void io_print(const io_chain_t &chain);
|
void io_print(const io_chain_t &chain);
|
||||||
|
|
||||||
|
|
88
parser.cpp
88
parser.cpp
|
@ -1518,13 +1518,12 @@ void parser_t::parse_job_argument_list(process_t *p,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_io.reset(new io_data_t);
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
new_io->fd = fish_wcstoi(tok_last(tok),
|
int fd = fish_wcstoi(tok_last(tok),
|
||||||
&end,
|
&end,
|
||||||
10);
|
10);
|
||||||
if (new_io->fd < 0 || errno || *end)
|
if (fd < 0 || errno || *end)
|
||||||
{
|
{
|
||||||
error(SYNTAX_ERROR,
|
error(SYNTAX_ERROR,
|
||||||
tok_get_pos(tok),
|
tok_get_pos(tok),
|
||||||
|
@ -1569,65 +1568,60 @@ void parser_t::parse_job_argument_list(process_t *p,
|
||||||
_(L"Invalid IO redirection"));
|
_(L"Invalid IO redirection"));
|
||||||
tok_next(tok);
|
tok_next(tok);
|
||||||
}
|
}
|
||||||
|
else if (type == TOK_REDIRECT_FD)
|
||||||
|
{
|
||||||
|
if (target == L"-")
|
||||||
|
{
|
||||||
|
new_io.reset(new io_close_t(fd));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wchar_t *end;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
int old_fd = fish_wcstoi(target.c_str(), &end, 10);
|
||||||
|
|
||||||
|
if (old_fd < 0 || errno || *end)
|
||||||
|
{
|
||||||
|
error(SYNTAX_ERROR,
|
||||||
|
tok_get_pos(tok),
|
||||||
|
_(L"Requested redirection to something that is not a file descriptor %ls"),
|
||||||
|
target.c_str());
|
||||||
|
|
||||||
|
tok_next(tok);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_io.reset(new io_fd_t(fd, old_fd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int flags = 0;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case TOK_REDIRECT_APPEND:
|
case TOK_REDIRECT_APPEND:
|
||||||
new_io->io_mode = IO_FILE;
|
flags = O_CREAT | O_APPEND | O_WRONLY;
|
||||||
new_io->param2.flags = O_CREAT | O_APPEND | O_WRONLY;
|
|
||||||
new_io->set_filename(target);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_OUT:
|
case TOK_REDIRECT_OUT:
|
||||||
new_io->io_mode = IO_FILE;
|
flags = O_CREAT | O_WRONLY | O_TRUNC;
|
||||||
new_io->param2.flags = O_CREAT | O_WRONLY | O_TRUNC;
|
|
||||||
new_io->set_filename(target);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_NOCLOB:
|
case TOK_REDIRECT_NOCLOB:
|
||||||
new_io->io_mode = IO_FILE;
|
flags = O_CREAT | O_EXCL | O_WRONLY;
|
||||||
new_io->param2.flags = O_CREAT | O_EXCL | O_WRONLY;
|
|
||||||
new_io->set_filename(target);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_IN:
|
case TOK_REDIRECT_IN:
|
||||||
new_io->io_mode = IO_FILE;
|
flags = O_RDONLY;
|
||||||
new_io->param2.flags = O_RDONLY;
|
|
||||||
new_io->set_filename(target);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_REDIRECT_FD:
|
|
||||||
{
|
|
||||||
if (target == L"-")
|
|
||||||
{
|
|
||||||
new_io->io_mode = IO_CLOSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wchar_t *end;
|
|
||||||
|
|
||||||
new_io->io_mode = IO_FD;
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
new_io->param1.old_fd = fish_wcstoi(target.c_str(), &end, 10);
|
|
||||||
|
|
||||||
if ((new_io->param1.old_fd < 0) ||
|
|
||||||
errno || *end)
|
|
||||||
{
|
|
||||||
error(SYNTAX_ERROR,
|
|
||||||
tok_get_pos(tok),
|
|
||||||
_(L"Requested redirection to something that is not a file descriptor %ls"),
|
|
||||||
target.c_str());
|
|
||||||
|
|
||||||
tok_next(tok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
io_file_t *new_io_file = new io_file_t(fd, NULL, flags);
|
||||||
|
new_io_file->set_filename(target);
|
||||||
|
new_io.reset(new_io_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
64
postfork.cpp
64
postfork.cpp
|
@ -121,15 +121,16 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
|
||||||
for (size_t j = 0; j < max; j++)
|
for (size_t j = 0; j < max; j++)
|
||||||
{
|
{
|
||||||
/* We're only interested in pipes */
|
/* We're only interested in pipes */
|
||||||
io_data_t *possible_conflict = io_chain.at(j).get();
|
io_data_t *io = io_chain.at(j).get();
|
||||||
if (possible_conflict->io_mode != IO_PIPE && possible_conflict->io_mode != IO_BUFFER)
|
if (io->io_mode != IO_PIPE && io->io_mode != IO_BUFFER)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
CAST_INIT(io_pipe_t *, possible_conflict, io);
|
||||||
/* If the pipe is a conflict, dup it to some other value */
|
/* If the pipe is a conflict, dup it to some other value */
|
||||||
for (int k=0; k<2; k++)
|
for (int k=0; k<2; k++)
|
||||||
{
|
{
|
||||||
/* If it's not a conflict, we don't care */
|
/* If it's not a conflict, we don't care */
|
||||||
if (possible_conflict->param1.pipe_fd[k] != fd_to_free)
|
if (possible_conflict->pipe_fd[k] != fd_to_free)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Repeat until we have a replacement fd */
|
/* Repeat until we have a replacement fd */
|
||||||
|
@ -144,7 +145,7 @@ static void free_redirected_fds_from_pipes(io_chain_t &io_chain)
|
||||||
FATAL_EXIT();
|
FATAL_EXIT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
possible_conflict->param1.pipe_fd[k] = replacement_fd;
|
possible_conflict->pipe_fd[k] = replacement_fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +174,7 @@ static int handle_child_io(io_chain_t &io_chain)
|
||||||
io_data_t *io = io_chain.at(idx).get();
|
io_data_t *io = io_chain.at(idx).get();
|
||||||
int tmp;
|
int tmp;
|
||||||
|
|
||||||
if (io->io_mode == IO_FD && io->fd == io->param1.old_fd)
|
if (io->io_mode == IO_FD && io->fd == static_cast<io_fd_t*>(io)->old_fd)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -193,17 +194,18 @@ static int handle_child_io(io_chain_t &io_chain)
|
||||||
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=open(io->filename_cstr,
|
CAST_INIT(io_file_t *, io_file, io);
|
||||||
io->param2.flags, OPEN_MASK))==-1)
|
if ((tmp=open(io_file->filename_cstr,
|
||||||
|
io_file->flags, OPEN_MASK))==-1)
|
||||||
{
|
{
|
||||||
if ((io->param2.flags & O_EXCL) &&
|
if ((io_file->flags & O_EXCL) &&
|
||||||
(errno ==EEXIST))
|
(errno ==EEXIST))
|
||||||
{
|
{
|
||||||
debug_safe(1, NOCLOB_ERROR, io->filename_cstr);
|
debug_safe(1, NOCLOB_ERROR, io_file->filename_cstr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
debug_safe(1, FILE_ERROR, io->filename_cstr);
|
debug_safe(1, FILE_ERROR, io_file->filename_cstr);
|
||||||
safe_perror("open");
|
safe_perror("open");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +238,7 @@ static int handle_child_io(io_chain_t &io_chain)
|
||||||
*/
|
*/
|
||||||
close(io->fd);
|
close(io->fd);
|
||||||
|
|
||||||
if (dup2(io->param1.old_fd, io->fd) == -1)
|
if (dup2(static_cast<const io_fd_t *>(io)->old_fd, io->fd) == -1)
|
||||||
{
|
{
|
||||||
debug_safe_int(1, FD_ERROR, io->fd);
|
debug_safe_int(1, FD_ERROR, io->fd);
|
||||||
safe_perror("dup2");
|
safe_perror("dup2");
|
||||||
|
@ -248,28 +250,29 @@ static int handle_child_io(io_chain_t &io_chain)
|
||||||
case IO_BUFFER:
|
case IO_BUFFER:
|
||||||
case IO_PIPE:
|
case IO_PIPE:
|
||||||
{
|
{
|
||||||
|
CAST_INIT(io_pipe_t *, io_pipe, io);
|
||||||
/* If write_pipe_idx is 0, it means we're connecting to the read end (first pipe fd). If it's 1, we're connecting to the write end (second pipe fd). */
|
/* If write_pipe_idx is 0, it means we're connecting to the read end (first pipe fd). If it's 1, we're connecting to the write end (second pipe fd). */
|
||||||
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
|
unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1);
|
||||||
/*
|
/*
|
||||||
debug( 0,
|
debug( 0,
|
||||||
L"%ls %ls on fd %d (%d %d)",
|
L"%ls %ls on fd %d (%d %d)",
|
||||||
write_pipe?L"write":L"read",
|
write_pipe?L"write":L"read",
|
||||||
(io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
|
(io->io_mode == IO_BUFFER)?L"buffer":L"pipe",
|
||||||
io->fd,
|
io->fd,
|
||||||
io->param1.pipe_fd[0],
|
io->pipe_fd[0],
|
||||||
io->param1.pipe_fd[1]);
|
io->pipe_fd[1]);
|
||||||
*/
|
*/
|
||||||
if (dup2(io->param1.pipe_fd[write_pipe_idx], io->fd) != io->fd)
|
if (dup2(io_pipe->pipe_fd[write_pipe_idx], io->fd) != io->fd)
|
||||||
{
|
{
|
||||||
debug_safe(1, LOCAL_PIPE_ERROR);
|
debug_safe(1, LOCAL_PIPE_ERROR);
|
||||||
safe_perror("dup2");
|
safe_perror("dup2");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (io->param1.pipe_fd[0] >= 0)
|
if (io_pipe->pipe_fd[0] >= 0)
|
||||||
exec_close(io->param1.pipe_fd[0]);
|
exec_close(io_pipe->pipe_fd[0]);
|
||||||
if (io->param1.pipe_fd[1] >= 0)
|
if (io_pipe->pipe_fd[1] >= 0)
|
||||||
exec_close(io->param1.pipe_fd[1]);
|
exec_close(io_pipe->pipe_fd[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,9 +450,11 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
{
|
{
|
||||||
shared_ptr<const io_data_t> io = j->io.at(idx);
|
shared_ptr<const io_data_t> io = j->io.at(idx);
|
||||||
|
|
||||||
if (io->io_mode == IO_FD && io->fd == io->param1.old_fd)
|
if (io->io_mode == IO_FD)
|
||||||
{
|
{
|
||||||
continue;
|
CAST_INIT(const io_fd_t *, io_fd, io.get());
|
||||||
|
if (io->fd == io_fd->old_fd)
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (io->fd > 2)
|
if (io->fd > 2)
|
||||||
|
@ -469,23 +474,26 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
|
|
||||||
case IO_FILE:
|
case IO_FILE:
|
||||||
{
|
{
|
||||||
|
CAST_INIT(const io_file_t *, io_file, io.get());
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addopen(actions, io->fd, io->filename_cstr, io->param2.flags /* mode */, OPEN_MASK);
|
err = posix_spawn_file_actions_addopen(actions, io->fd, io_file->filename_cstr, io_file->flags /* mode */, OPEN_MASK);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IO_FD:
|
case IO_FD:
|
||||||
{
|
{
|
||||||
|
CAST_INIT(const io_fd_t *, io_fd, io.get());
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_adddup2(actions, io->param1.old_fd /* from */, io->fd /* to */);
|
err = posix_spawn_file_actions_adddup2(actions, io_fd->old_fd /* from */, io->fd /* to */);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IO_BUFFER:
|
case IO_BUFFER:
|
||||||
case IO_PIPE:
|
case IO_PIPE:
|
||||||
{
|
{
|
||||||
unsigned int write_pipe_idx = (io->is_input ? 0 : 1);
|
CAST_INIT(const io_pipe_t *, io_pipe, io.get());
|
||||||
int from_fd = io->param1.pipe_fd[write_pipe_idx];
|
unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1);
|
||||||
|
int from_fd = io_pipe->pipe_fd[write_pipe_idx];
|
||||||
int to_fd = io->fd;
|
int to_fd = io->fd;
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);
|
err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd);
|
||||||
|
@ -494,14 +502,14 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_fil
|
||||||
if (write_pipe_idx > 0)
|
if (write_pipe_idx > 0)
|
||||||
{
|
{
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
|
err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]);
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[1]);
|
err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (! err)
|
if (! err)
|
||||||
err = posix_spawn_file_actions_addclose(actions, io->param1.pipe_fd[0]);
|
err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
13
proc.cpp
13
proc.cpp
|
@ -869,10 +869,11 @@ static int select_try(job_t *j)
|
||||||
|
|
||||||
for (size_t idx = 0; idx < j->io.size(); idx++)
|
for (size_t idx = 0; idx < j->io.size(); idx++)
|
||||||
{
|
{
|
||||||
const io_data_t *d = j->io.at(idx).get();
|
const io_data_t *io = j->io.at(idx).get();
|
||||||
if (d->io_mode == IO_BUFFER)
|
if (io->io_mode == IO_BUFFER)
|
||||||
{
|
{
|
||||||
int fd = d->param1.pipe_fd[0];
|
CAST_INIT(const io_pipe_t *, io_pipe, io);
|
||||||
|
int fd = io_pipe->pipe_fd[0];
|
||||||
// fwprintf( stderr, L"fd %d on job %ls\n", fd, j->command );
|
// fwprintf( stderr, L"fd %d on job %ls\n", fd, j->command );
|
||||||
FD_SET(fd, &fds);
|
FD_SET(fd, &fds);
|
||||||
maxfd = maxi(maxfd, fd);
|
maxfd = maxi(maxfd, fd);
|
||||||
|
@ -902,7 +903,7 @@ static int select_try(job_t *j)
|
||||||
*/
|
*/
|
||||||
static void read_try(job_t *j)
|
static void read_try(job_t *j)
|
||||||
{
|
{
|
||||||
io_data_t *buff=NULL;
|
io_buffer_t *buff=NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Find the last buffer, which is the one we want to read from
|
Find the last buffer, which is the one we want to read from
|
||||||
|
@ -912,7 +913,7 @@ static void read_try(job_t *j)
|
||||||
io_data_t *d = j->io.at(idx).get();
|
io_data_t *d = j->io.at(idx).get();
|
||||||
if (d->io_mode == IO_BUFFER)
|
if (d->io_mode == IO_BUFFER)
|
||||||
{
|
{
|
||||||
buff=d;
|
buff = static_cast<io_buffer_t *>(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,7 +925,7 @@ static void read_try(job_t *j)
|
||||||
char b[BUFFER_SIZE];
|
char b[BUFFER_SIZE];
|
||||||
long l;
|
long l;
|
||||||
|
|
||||||
l=read_blocked(buff->param1.pipe_fd[0],
|
l=read_blocked(buff->pipe_fd[0],
|
||||||
b, BUFFER_SIZE);
|
b, BUFFER_SIZE);
|
||||||
if (l==0)
|
if (l==0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1064,7 +1064,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
|
||||||
is_quoted?L"-q":L"",
|
is_quoted?L"-q":L"",
|
||||||
prefix_esc.c_str());
|
prefix_esc.c_str());
|
||||||
|
|
||||||
shared_ptr<io_data_t> in(io_buffer_create(true));
|
shared_ptr<io_buffer_t> in(io_buffer_t::create(true));
|
||||||
in->fd = 3;
|
in->fd = 3;
|
||||||
|
|
||||||
escaped_separator = escape(COMPLETE_SEP_STR, 1);
|
escaped_separator = escape(COMPLETE_SEP_STR, 1);
|
||||||
|
@ -1133,7 +1133,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
|
||||||
|
|
||||||
term_donate();
|
term_donate();
|
||||||
|
|
||||||
shared_ptr<io_data_t> out(io_buffer_create(false));
|
shared_ptr<io_buffer_t> out(io_buffer_t::create(false));
|
||||||
out->fd = 4;
|
out->fd = 4;
|
||||||
|
|
||||||
parser_t &parser = parser_t::principal_parser();
|
parser_t &parser = parser_t::principal_parser();
|
||||||
|
@ -1143,7 +1143,7 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
|
||||||
parser.eval(cmd, io_chain, TOP);
|
parser.eval(cmd, io_chain, TOP);
|
||||||
term_steal();
|
term_steal();
|
||||||
|
|
||||||
io_buffer_read(out.get());
|
out->read();
|
||||||
|
|
||||||
int nil=0;
|
int nil=0;
|
||||||
out->out_buffer_append((char *)&nil, 1);
|
out->out_buffer_append((char *)&nil, 1);
|
||||||
|
@ -1158,9 +1158,6 @@ static void run_pager(const wcstring &prefix, int is_quoted, const std::vector<c
|
||||||
input_unreadch(str.at(idx));
|
input_unreadch(str.at(idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io_buffer_destroy(out);
|
|
||||||
io_buffer_destroy(in);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct autosuggestion_context_t
|
struct autosuggestion_context_t
|
||||||
|
|
Loading…
Reference in a new issue