2005-10-08 19:20:51 +08:00
|
|
|
#ifndef FISH_IO_H
|
|
|
|
#define FISH_IO_H
|
|
|
|
|
2012-03-07 16:54:01 +08:00
|
|
|
#include <vector>
|
2013-04-10 05:07:19 +08:00
|
|
|
#if __cplusplus > 199711L
|
2013-05-05 17:33:17 +08:00
|
|
|
// C++11
|
|
|
|
#include <memory>
|
|
|
|
using std::shared_ptr;
|
2013-04-10 05:07:19 +08:00
|
|
|
#else
|
2013-05-05 17:33:17 +08:00
|
|
|
// C++03
|
|
|
|
#include <tr1/memory>
|
|
|
|
using std::tr1::shared_ptr;
|
2013-04-10 05:07:19 +08:00
|
|
|
#endif
|
2012-03-04 18:35:30 +08:00
|
|
|
|
2005-10-08 19:20:51 +08:00
|
|
|
/**
|
|
|
|
Describes what type of IO operation an io_data_t represents
|
|
|
|
*/
|
2013-01-01 01:11:46 +08:00
|
|
|
enum io_mode_t
|
2005-10-08 19:20:51 +08:00
|
|
|
{
|
2013-01-15 17:39:20 +08:00
|
|
|
IO_FILE, IO_PIPE, IO_FD, IO_BUFFER, IO_CLOSE
|
2012-03-04 18:35:30 +08:00
|
|
|
};
|
2005-10-08 19:20:51 +08:00
|
|
|
|
|
|
|
/** Represents an FD redirection */
|
2012-03-04 18:35:30 +08:00
|
|
|
class io_data_t
|
2005-10-08 19:20:51 +08:00
|
|
|
{
|
2012-03-04 18:35:30 +08:00
|
|
|
private:
|
2013-01-07 23:04:55 +08:00
|
|
|
/* No assignment or copying allowed */
|
|
|
|
io_data_t(const io_data_t &rhs);
|
2012-08-06 04:24:33 +08:00
|
|
|
void operator=(const io_data_t &rhs);
|
2013-01-04 18:03:41 +08:00
|
|
|
|
2013-01-15 17:39:20 +08:00
|
|
|
protected:
|
|
|
|
io_data_t(io_mode_t m, int f) :
|
|
|
|
io_mode(m),
|
2013-01-16 11:55:57 +08:00
|
|
|
fd(f)
|
2013-01-15 17:39:20 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-03-04 18:35:30 +08:00
|
|
|
public:
|
2012-11-19 08:30:30 +08:00
|
|
|
/** Type of redirect */
|
2013-01-17 14:46:02 +08:00
|
|
|
const io_mode_t io_mode;
|
2012-11-19 08:30:30 +08:00
|
|
|
/** FD to redirect */
|
2013-02-04 20:07:16 +08:00
|
|
|
const int fd;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2013-01-15 17:39:20 +08:00
|
|
|
virtual void print() const = 0;
|
|
|
|
virtual ~io_data_t() = 0;
|
2012-02-10 10:43:36 +08:00
|
|
|
};
|
2013-01-09 16:02:04 +08:00
|
|
|
|
|
|
|
class io_close_t : public io_data_t
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
io_close_t(int f) :
|
|
|
|
io_data_t(IO_CLOSE, f)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void print() const;
|
|
|
|
};
|
2013-01-15 15:37:33 +08:00
|
|
|
|
|
|
|
class io_fd_t : public io_data_t
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/** fd to redirect specified fd to */
|
2013-02-04 20:14:48 +08:00
|
|
|
const int old_fd;
|
2013-01-15 15:37:33 +08:00
|
|
|
/** Whether to close old_fd */
|
2013-02-04 20:14:48 +08:00
|
|
|
const bool close_old;
|
2013-01-15 15:37:33 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
2013-01-15 16:18:03 +08:00
|
|
|
|
|
|
|
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. */
|
2013-01-20 02:59:43 +08:00
|
|
|
const char * const filename_cstr;
|
2013-01-15 16:18:03 +08:00
|
|
|
/** file creation flags to send to open */
|
2013-02-04 20:15:32 +08:00
|
|
|
const int flags;
|
2013-01-21 10:34:18 +08:00
|
|
|
|
2013-01-15 16:18:03 +08:00
|
|
|
virtual void print() const;
|
|
|
|
|
2013-01-20 02:59:43 +08:00
|
|
|
io_file_t(int f, const wcstring &fname, int fl = 0) :
|
2013-01-15 16:18:03 +08:00
|
|
|
io_data_t(IO_FILE, f),
|
2013-01-20 02:59:43 +08:00
|
|
|
filename_cstr(wcs2str(fname)),
|
2013-01-15 16:18:03 +08:00
|
|
|
flags(fl)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~io_file_t()
|
|
|
|
{
|
|
|
|
free((void *)filename_cstr);
|
|
|
|
}
|
|
|
|
};
|
2005-10-08 19:20:51 +08:00
|
|
|
|
2013-01-15 17:31:36 +08:00
|
|
|
class io_pipe_t : public io_data_t
|
|
|
|
{
|
2013-01-17 14:46:02 +08:00
|
|
|
protected:
|
|
|
|
io_pipe_t(io_mode_t m, int f, bool i):
|
|
|
|
io_data_t(m, f),
|
|
|
|
is_input(i)
|
|
|
|
{
|
2013-01-30 18:22:38 +08:00
|
|
|
pipe_fd[0] = pipe_fd[1] = -1;
|
2013-01-17 14:46:02 +08:00
|
|
|
}
|
|
|
|
|
2013-01-15 17:31:36 +08:00
|
|
|
public:
|
|
|
|
int pipe_fd[2];
|
2013-01-30 18:22:38 +08:00
|
|
|
const bool is_input;
|
2013-01-15 17:31:36 +08:00
|
|
|
|
|
|
|
virtual void print() const;
|
|
|
|
|
2013-01-16 11:55:57 +08:00
|
|
|
io_pipe_t(int f, bool i):
|
2013-01-15 17:31:36 +08:00
|
|
|
io_data_t(IO_PIPE, f),
|
2013-01-16 11:55:57 +08:00
|
|
|
is_input(i)
|
2013-01-15 17:31:36 +08:00
|
|
|
{
|
2013-01-30 18:22:38 +08:00
|
|
|
pipe_fd[0] = pipe_fd[1] = -1;
|
2013-01-15 17:31:36 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class io_buffer_t : public io_pipe_t
|
2013-01-15 16:44:31 +08:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
/** buffer to save output in */
|
2013-01-20 02:59:43 +08:00
|
|
|
std::vector<char> out_buffer;
|
2013-01-15 16:44:31 +08:00
|
|
|
|
2013-01-16 11:55:57 +08:00
|
|
|
io_buffer_t(int f, bool i):
|
2013-01-17 14:46:02 +08:00
|
|
|
io_pipe_t(IO_BUFFER, f, i),
|
2013-01-17 15:46:10 +08:00
|
|
|
out_buffer()
|
2013-01-15 16:44:31 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-01-15 17:07:30 +08:00
|
|
|
public:
|
|
|
|
virtual void print() const;
|
|
|
|
|
2013-01-16 11:30:18 +08:00
|
|
|
virtual ~io_buffer_t();
|
2013-01-15 17:02:46 +08:00
|
|
|
|
2013-01-15 16:44:31 +08:00
|
|
|
/** Function to append to the buffer */
|
|
|
|
void out_buffer_append(const char *ptr, size_t count)
|
|
|
|
{
|
2013-01-20 02:59:43 +08:00
|
|
|
out_buffer.insert(out_buffer.end(), ptr, ptr + count);
|
2013-01-15 16:44:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Function to get a pointer to the buffer */
|
|
|
|
char *out_buffer_ptr(void)
|
|
|
|
{
|
2013-01-20 02:59:43 +08:00
|
|
|
return out_buffer.empty() ? NULL : &out_buffer.at(0);
|
2013-01-15 16:44:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *out_buffer_ptr(void) const
|
|
|
|
{
|
2013-01-20 02:59:43 +08:00
|
|
|
return out_buffer.empty() ? NULL : &out_buffer.at(0);
|
2013-01-15 16:44:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Function to get the size of the buffer */
|
|
|
|
size_t out_buffer_size(void) const
|
|
|
|
{
|
2013-01-20 02:59:43 +08:00
|
|
|
return out_buffer.size();
|
2013-01-15 16:44:31 +08:00
|
|
|
}
|
2013-01-15 17:07:30 +08:00
|
|
|
|
2013-01-15 17:10:40 +08:00
|
|
|
/**
|
|
|
|
Close output pipe, and read from input pipe until eof.
|
|
|
|
*/
|
|
|
|
void read();
|
|
|
|
|
2013-01-15 17:07:30 +08:00
|
|
|
/**
|
|
|
|
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.
|
2013-02-04 20:07:16 +08:00
|
|
|
|
|
|
|
\param fd when -1, determined from is_input.
|
2013-01-15 17:07:30 +08:00
|
|
|
*/
|
2013-02-04 20:07:16 +08:00
|
|
|
static io_buffer_t *create(bool is_input, int fd = -1);
|
2013-01-15 16:44:31 +08:00
|
|
|
};
|
|
|
|
|
2013-01-07 23:04:55 +08:00
|
|
|
class io_chain_t : public std::vector<shared_ptr<io_data_t> >
|
2012-11-19 08:30:30 +08:00
|
|
|
{
|
2012-08-15 15:57:56 +08:00
|
|
|
public:
|
|
|
|
io_chain_t();
|
2013-01-07 23:04:55 +08:00
|
|
|
io_chain_t(const shared_ptr<io_data_t> &);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2013-01-07 23:04:55 +08:00
|
|
|
void remove(const shared_ptr<const io_data_t> &element);
|
2013-01-30 18:22:38 +08:00
|
|
|
void push_back(const shared_ptr<io_data_t> &element);
|
2013-08-19 07:55:01 +08:00
|
|
|
void push_front(const shared_ptr<io_data_t> &element);
|
Big fat refactoring of how redirections work. In fish 1.x and 2.0.0, the redirections for a process were flattened into a big list associated with the job, so there was no way to tell which redirections applied to each process. Each process therefore got all the redirections associated with the job. See https://github.com/fish-shell/fish-shell/issues/877 for how this could manifest.
With this change, jobs only track their block-level redirections. Process level redirections are correctly associated with the process, and at exec time we stitch them together (block, pipe, and process redirects).
This fixes the weird issues where redirects bleed across pipelines (like #877), and also allows us to play with the order in which redirections are applied, since the final list is constructed right before it's needed. This lets us put pipes after block level redirections but before process level redirections, so that a 2>&1-type redirection gets picked up after the pipe, i.e. it should fix https://github.com/fish-shell/fish-shell/issues/110
This is a significant change. The tests all pass. Cross your fingers.
2013-08-20 07:16:41 +08:00
|
|
|
void append(const io_chain_t &chain);
|
2012-11-18 18:23:22 +08:00
|
|
|
|
2013-01-07 23:04:55 +08:00
|
|
|
shared_ptr<const io_data_t> get_io_for_fd(int fd) const;
|
|
|
|
shared_ptr<io_data_t> get_io_for_fd(int fd);
|
2012-08-15 15:57:56 +08:00
|
|
|
};
|
2005-10-08 19:20:51 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
Remove the specified io redirection from the chain
|
|
|
|
*/
|
2013-01-07 23:04:55 +08:00
|
|
|
void io_remove(io_chain_t &list, const shared_ptr<const io_data_t> &element);
|
2005-10-08 19:20:51 +08:00
|
|
|
|
2012-08-15 15:57:56 +08:00
|
|
|
/** Destroys an io_chain */
|
|
|
|
void io_chain_destroy(io_chain_t &chain);
|
2005-10-08 19:20:51 +08:00
|
|
|
|
|
|
|
/**
|
2007-04-17 04:10:53 +08:00
|
|
|
Return the last io redirection in the chain for the specified file descriptor.
|
2005-10-08 19:20:51 +08:00
|
|
|
*/
|
2013-01-07 23:04:55 +08:00
|
|
|
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);
|
2005-10-08 19:20:51 +08:00
|
|
|
|
|
|
|
|
2012-08-15 15:57:56 +08:00
|
|
|
/** Print debug information about the specified IO redirection chain to stderr. */
|
2012-11-19 08:30:30 +08:00
|
|
|
void io_print(const io_chain_t &chain);
|
2006-05-15 06:29:05 +08:00
|
|
|
|
2005-10-08 19:20:51 +08:00
|
|
|
#endif
|