PStreams
pstream.h
Go to the documentation of this file.
1 /*
2 PStreams - POSIX Process I/O for C++
3 Copyright (C) 2001-2013 Jonathan Wakely
4 
5 This file is part of PStreams.
6 
7 PStreams is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11 
12 PStreams is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16 
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
30 #ifndef REDI_PSTREAM_H_SEEN
31 #define REDI_PSTREAM_H_SEEN
32 
33 #include <ios>
34 #include <streambuf>
35 #include <istream>
36 #include <ostream>
37 #include <string>
38 #include <vector>
39 #include <algorithm> // for min()
40 #include <cerrno> // for errno
41 #include <cstddef> // for size_t, NULL
42 #include <cstdlib> // for exit()
43 #include <sys/types.h> // for pid_t
44 #include <sys/wait.h> // for waitpid()
45 #include <sys/ioctl.h> // for ioctl() and FIONREAD
46 #if defined(__sun)
47 # include <sys/filio.h> // for FIONREAD on Solaris 2.5
48 #endif
49 #include <unistd.h> // for pipe() fork() exec() and filedes functions
50 #include <signal.h> // for kill()
51 #include <fcntl.h> // for fcntl()
52 #if REDI_EVISCERATE_PSTREAMS
53 # include <stdio.h> // for FILE, fdopen()
54 #endif
55 
56 
58 #define PSTREAMS_VERSION 0x0080 // 0.8.0
59 
73 namespace redi
74 {
76  struct pstreams
77  {
79  typedef std::ios_base::openmode pmode;
80 
82  typedef std::vector<std::string> argv_type;
83 
85  typedef int fd_type;
86 
87  static const pmode pstdin = std::ios_base::out;
88  static const pmode pstdout = std::ios_base::in;
89  static const pmode pstderr = std::ios_base::app;
90 
91  protected:
92  enum { bufsz = 32 };
93  enum { pbsz = 2 };
94  };
95 
97  template <typename CharT, typename Traits = std::char_traits<CharT> >
99  : public std::basic_streambuf<CharT, Traits>
100  , public pstreams
101  {
102  public:
103  // Type definitions for dependent types
104  typedef CharT char_type;
105  typedef Traits traits_type;
106  typedef typename traits_type::int_type int_type;
107  typedef typename traits_type::off_type off_type;
108  typedef typename traits_type::pos_type pos_type;
110  typedef fd_type fd_t;
111 
114 
116  basic_pstreambuf(const std::string& command, pmode mode);
117 
119  basic_pstreambuf( const std::string& file,
120  const argv_type& argv,
121  pmode mode );
122 
124  ~basic_pstreambuf();
125 
128  open(const std::string& command, pmode mode);
129 
132  open(const std::string& file, const argv_type& argv, pmode mode);
133 
136  close();
137 
140  kill(int signal = SIGTERM);
141 
144  killpg(int signal = SIGTERM);
145 
147  void
148  peof();
149 
151  bool
152  read_err(bool readerr = true);
153 
155  bool
156  is_open() const;
157 
159  bool
160  exited();
161 
162 #if REDI_EVISCERATE_PSTREAMS
163  std::size_t
165  fopen(FILE*& in, FILE*& out, FILE*& err);
166 #endif
167 
169  int
170  status() const;
171 
173  int
174  error() const;
175 
176  protected:
178  int_type
179  overflow(int_type c);
180 
182  int_type
183  underflow();
184 
186  int_type
187  pbackfail(int_type c = traits_type::eof());
188 
190  int
191  sync();
192 
194  std::streamsize
195  xsputn(const char_type* s, std::streamsize n);
196 
198  std::streamsize
199  write(const char_type* s, std::streamsize n);
200 
202  std::streamsize
203  read(char_type* s, std::streamsize n);
204 
206  std::streamsize
207  showmanyc();
208 
209  protected:
211  enum buf_read_src { rsrc_out = 0, rsrc_err = 1 };
212 
214  pid_t
215  fork(pmode mode);
216 
218  int
219  wait(bool nohang = false);
220 
222  fd_type&
223  wpipe();
224 
226  fd_type&
227  rpipe();
228 
230  fd_type&
231  rpipe(buf_read_src which);
232 
233  void
234  create_buffers(pmode mode);
235 
236  void
237  destroy_buffers(pmode mode);
238 
240  bool
241  empty_buffer();
242 
243  bool
244  fill_buffer(bool non_blocking = false);
245 
247  char_type*
248  rbuffer();
249 
251  switch_read_buffer(buf_read_src);
252 
253  private:
255  basic_pstreambuf& operator=(const basic_pstreambuf&);
256 
257  void
258  init_rbuffers();
259 
260  pid_t ppid_; // pid of process
261  fd_type wpipe_; // pipe used to write to process' stdin
262  fd_type rpipe_[2]; // two pipes to read from, stdout and stderr
263  char_type* wbuffer_;
264  char_type* rbuffer_[2];
265  char_type* rbufstate_[3];
267  buf_read_src rsrc_;
268  int status_; // hold exit status of child process
269  int error_; // hold errno if fork() or exec() fails
270  };
271 
273  template <typename CharT, typename Traits = std::char_traits<CharT> >
275  : virtual public std::basic_ios<CharT, Traits>
276  , virtual public pstreams
277  {
278  protected:
280 
281  typedef pstreams::pmode pmode;
283 
285  pstream_common();
286 
288  pstream_common(const std::string& command, pmode mode);
289 
291  pstream_common(const std::string& file, const argv_type& argv, pmode mode);
292 
294  virtual
295  ~pstream_common() = 0;
296 
298  void
299  do_open(const std::string& command, pmode mode);
300 
302  void
303  do_open(const std::string& file, const argv_type& argv, pmode mode);
304 
305  public:
307  void
308  close();
309 
311  bool
312  is_open() const;
313 
315  const std::string&
316  command() const;
317 
319  streambuf_type*
320  rdbuf() const;
321 
322 #if REDI_EVISCERATE_PSTREAMS
323  std::size_t
325  fopen(FILE*& in, FILE*& out, FILE*& err);
326 #endif
327 
328  protected:
329  std::string command_;
330  streambuf_type buf_;
331  };
332 
333 
344  template <typename CharT, typename Traits = std::char_traits<CharT> >
346  : public std::basic_istream<CharT, Traits>
347  , public pstream_common<CharT, Traits>
348  , virtual public pstreams
349  {
350  typedef std::basic_istream<CharT, Traits> istream_type;
352 
353  using pbase_type::buf_; // declare name in this scope
354 
355  pmode readable(pmode mode)
356  {
357  if (!(mode & (pstdout|pstderr)))
358  mode |= pstdout;
359  return mode;
360  }
361 
362  public:
364  typedef typename pbase_type::pmode pmode;
365 
367  typedef typename pbase_type::argv_type argv_type;
368 
371  : istream_type(NULL), pbase_type()
372  { }
373 
384  basic_ipstream(const std::string& command, pmode mode = pstdout)
385  : istream_type(NULL), pbase_type(command, readable(mode))
386  { }
387 
399  basic_ipstream( const std::string& file,
400  const argv_type& argv,
401  pmode mode = pstdout )
402  : istream_type(NULL), pbase_type(file, argv, readable(mode))
403  { }
404 
415  basic_ipstream(const argv_type& argv, pmode mode = pstdout)
416  : istream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdout)
417  { }
418 
425  { }
426 
436  void
437  open(const std::string& command, pmode mode = pstdout)
438  {
439  this->do_open(command, readable(mode));
440  }
441 
452  void
453  open( const std::string& file,
454  const argv_type& argv,
455  pmode mode = pstdout )
456  {
457  this->do_open(file, argv, readable(mode));
458  }
459 
465  out()
466  {
467  this->buf_.read_err(false);
468  return *this;
469  }
470 
476  err()
477  {
478  this->buf_.read_err(true);
479  return *this;
480  }
481  };
482 
483 
493  template <typename CharT, typename Traits = std::char_traits<CharT> >
495  : public std::basic_ostream<CharT, Traits>
496  , public pstream_common<CharT, Traits>
497  , virtual public pstreams
498  {
499  typedef std::basic_ostream<CharT, Traits> ostream_type;
501 
502  using pbase_type::buf_; // declare name in this scope
503 
504  public:
506  typedef typename pbase_type::pmode pmode;
507 
509  typedef typename pbase_type::argv_type argv_type;
510 
513  : ostream_type(NULL), pbase_type()
514  { }
515 
526  basic_opstream(const std::string& command, pmode mode = pstdin)
527  : ostream_type(NULL), pbase_type(command, mode|pstdin)
528  { }
529 
541  basic_opstream( const std::string& file,
542  const argv_type& argv,
543  pmode mode = pstdin )
544  : ostream_type(NULL), pbase_type(file, argv, mode|pstdin)
545  { }
546 
557  basic_opstream(const argv_type& argv, pmode mode = pstdin)
558  : ostream_type(NULL), pbase_type(argv.at(0), argv, mode|pstdin)
559  { }
560 
567 
577  void
578  open(const std::string& command, pmode mode = pstdin)
579  {
580  this->do_open(command, mode|pstdin);
581  }
582 
593  void
594  open( const std::string& file,
595  const argv_type& argv,
596  pmode mode = pstdin)
597  {
598  this->do_open(file, argv, mode|pstdin);
599  }
600  };
601 
602 
616  template <typename CharT, typename Traits = std::char_traits<CharT> >
618  : public std::basic_iostream<CharT, Traits>
619  , public pstream_common<CharT, Traits>
620  , virtual public pstreams
621  {
622  typedef std::basic_iostream<CharT, Traits> iostream_type;
624 
625  using pbase_type::buf_; // declare name in this scope
626 
627  public:
629  typedef typename pbase_type::pmode pmode;
630 
632  typedef typename pbase_type::argv_type argv_type;
633 
636  : iostream_type(NULL), pbase_type()
637  { }
638 
649  basic_pstream(const std::string& command, pmode mode = pstdout|pstdin)
650  : iostream_type(NULL), pbase_type(command, mode)
651  { }
652 
664  basic_pstream( const std::string& file,
665  const argv_type& argv,
666  pmode mode = pstdout|pstdin )
667  : iostream_type(NULL), pbase_type(file, argv, mode)
668  { }
669 
680  basic_pstream(const argv_type& argv, pmode mode = pstdout|pstdin)
681  : iostream_type(NULL), pbase_type(argv.at(0), argv, mode)
682  { }
683 
690 
700  void
701  open(const std::string& command, pmode mode = pstdout|pstdin)
702  {
703  this->do_open(command, mode);
704  }
705 
716  void
717  open( const std::string& file,
718  const argv_type& argv,
719  pmode mode = pstdout|pstdin )
720  {
721  this->do_open(file, argv, mode);
722  }
723 
729  out()
730  {
731  this->buf_.read_err(false);
732  return *this;
733  }
734 
740  err()
741  {
742  this->buf_.read_err(true);
743  return *this;
744  }
745  };
746 
747 
769  template <typename CharT, typename Traits = std::char_traits<CharT> >
771  : public std::basic_ostream<CharT, Traits>
772  , private std::basic_istream<CharT, Traits>
773  , private pstream_common<CharT, Traits>
774  , virtual public pstreams
775  {
776  typedef std::basic_ostream<CharT, Traits> ostream_type;
777  typedef std::basic_istream<CharT, Traits> istream_type;
779 
780  using pbase_type::buf_; // declare name in this scope
781 
782  public:
784  typedef typename pbase_type::pmode pmode;
785 
787  typedef typename pbase_type::argv_type argv_type;
788 
791  : ostream_type(NULL), istream_type(NULL), pbase_type()
792  { }
793 
804  basic_rpstream(const std::string& command, pmode mode = pstdout|pstdin)
805  : ostream_type(NULL) , istream_type(NULL) , pbase_type(command, mode)
806  { }
807 
819  basic_rpstream( const std::string& file,
820  const argv_type& argv,
821  pmode mode = pstdout|pstdin )
822  : ostream_type(NULL), istream_type(NULL), pbase_type(file, argv, mode)
823  { }
824 
835  basic_rpstream(const argv_type& argv, pmode mode = pstdout|pstdin)
836  : ostream_type(NULL), istream_type(NULL),
837  pbase_type(argv.at(0), argv, mode)
838  { }
839 
842 
852  void
853  open(const std::string& command, pmode mode = pstdout|pstdin)
854  {
855  this->do_open(command, mode);
856  }
857 
868  void
869  open( const std::string& file,
870  const argv_type& argv,
871  pmode mode = pstdout|pstdin )
872  {
873  this->do_open(file, argv, mode);
874  }
875 
881  istream_type&
882  out()
883  {
884  this->buf_.read_err(false);
885  return *this;
886  }
887 
893  istream_type&
894  err()
895  {
896  this->buf_.read_err(true);
897  return *this;
898  }
899  };
900 
901 
912 
913 
926  template <typename C, typename T>
927  inline std::basic_ostream<C,T>&
928  peof(std::basic_ostream<C,T>& s)
929  {
931  if (pstreambuf* p = dynamic_cast<pstreambuf*>(s.rdbuf()))
932  p->peof();
933  return s;
934  }
935 
936 
937  /*
938  * member definitions for pstreambuf
939  */
940 
941 
948  template <typename C, typename T>
949  inline
951  : ppid_(-1) // initialise to -1 to indicate no process run yet.
952  , wpipe_(-1)
953  , wbuffer_(NULL)
954  , rsrc_(rsrc_out)
955  , status_(-1)
956  , error_(0)
957  {
958  init_rbuffers();
959  }
960 
969  template <typename C, typename T>
970  inline
971  basic_pstreambuf<C,T>::basic_pstreambuf(const std::string& command, pmode mode)
972  : ppid_(-1) // initialise to -1 to indicate no process run yet.
973  , wpipe_(-1)
974  , wbuffer_(NULL)
975  , rsrc_(rsrc_out)
976  , status_(-1)
977  , error_(0)
978  {
979  init_rbuffers();
980  open(command, mode);
981  }
982 
992  template <typename C, typename T>
993  inline
994  basic_pstreambuf<C,T>::basic_pstreambuf( const std::string& file,
995  const argv_type& argv,
996  pmode mode )
997  : ppid_(-1) // initialise to -1 to indicate no process run yet.
998  , wpipe_(-1)
999  , wbuffer_(NULL)
1000  , rsrc_(rsrc_out)
1001  , status_(-1)
1002  , error_(0)
1003  {
1004  init_rbuffers();
1005  open(file, argv, mode);
1006  }
1007 
1012  template <typename C, typename T>
1013  inline
1015  {
1016  close();
1017  }
1018 
1046  template <typename C, typename T>
1048  basic_pstreambuf<C,T>::open(const std::string& command, pmode mode)
1049  {
1050  const char * shell_path = "/bin/sh";
1051 #if 0
1052  const std::string argv[] = { "sh", "-c", command };
1053  return this->open(shell_path, argv_type(argv, argv+3), mode);
1054 #else
1055  basic_pstreambuf<C,T>* ret = NULL;
1056 
1057  if (!is_open())
1058  {
1059  switch(fork(mode))
1060  {
1061  case 0 :
1062  // this is the new process, exec command
1063  ::execl(shell_path, "sh", "-c", command.c_str(), (char*)NULL);
1064 
1065  // can only reach this point if exec() failed
1066 
1067  // parent can get exit code from waitpid()
1068  ::_exit(errno);
1069  // using std::exit() would make static dtors run twice
1070 
1071  case -1 :
1072  // couldn't fork, error already handled in pstreambuf::fork()
1073  break;
1074 
1075  default :
1076  // this is the parent process
1077  // activate buffers
1078  create_buffers(mode);
1079  ret = this;
1080  }
1081  }
1082  return ret;
1083 #endif
1084  }
1085 
1094  inline void
1096  {
1097  if (fd >= 0 && ::close(fd) == 0)
1098  fd = -1;
1099  }
1100 
1111  template <int N>
1112  inline void
1114  {
1115  for (std::size_t i = 0; i < N; ++i)
1116  close_fd(fds[i]);
1117  }
1118 
1148  template <typename C, typename T>
1150  basic_pstreambuf<C,T>::open( const std::string& file,
1151  const argv_type& argv,
1152  pmode mode )
1153  {
1154  basic_pstreambuf<C,T>* ret = NULL;
1155 
1156  if (!is_open())
1157  {
1158  // constants for read/write ends of pipe
1159  enum { RD, WR };
1160 
1161  // open another pipe and set close-on-exec
1162  fd_type ck_exec[] = { -1, -1 };
1163  if (-1 == ::pipe(ck_exec)
1164  || -1 == ::fcntl(ck_exec[RD], F_SETFD, FD_CLOEXEC)
1165  || -1 == ::fcntl(ck_exec[WR], F_SETFD, FD_CLOEXEC))
1166  {
1167  error_ = errno;
1168  close_fd_array(ck_exec);
1169  }
1170  else
1171  {
1172  switch(fork(mode))
1173  {
1174  case 0 :
1175  // this is the new process, exec command
1176  {
1177  char** arg_v = new char*[argv.size()+1];
1178  for (std::size_t i = 0; i < argv.size(); ++i)
1179  {
1180  const std::string& src = argv[i];
1181  char*& dest = arg_v[i];
1182  dest = new char[src.size()+1];
1183  dest[ src.copy(dest, src.size()) ] = '\0';
1184  }
1185  arg_v[argv.size()] = NULL;
1186 
1187  ::execvp(file.c_str(), arg_v);
1188 
1189  // can only reach this point if exec() failed
1190 
1191  // parent can get error code from ck_exec pipe
1192  error_ = errno;
1193 
1194  while (::write(ck_exec[WR], &error_, sizeof(error_)) == -1
1195  && errno == EINTR)
1196  { }
1197 
1198  ::close(ck_exec[WR]);
1199  ::close(ck_exec[RD]);
1200 
1201  ::_exit(error_);
1202  // using std::exit() would make static dtors run twice
1203  }
1204 
1205  case -1 :
1206  // couldn't fork, error already handled in pstreambuf::fork()
1207  close_fd_array(ck_exec);
1208  break;
1209 
1210  default :
1211  // this is the parent process
1212 
1213  // check child called exec() successfully
1214  ::close(ck_exec[WR]);
1215  switch (::read(ck_exec[RD], &error_, sizeof(error_)))
1216  {
1217  case 0:
1218  // activate buffers
1219  create_buffers(mode);
1220  ret = this;
1221  break;
1222  case -1:
1223  error_ = errno;
1224  break;
1225  default:
1226  // error_ contains error code from child
1227  // call wait() to clean up and set ppid_ to 0
1228  this->wait();
1229  break;
1230  }
1231  ::close(ck_exec[RD]);
1232  }
1233  }
1234  }
1235  return ret;
1236  }
1237 
1254  template <typename C, typename T>
1255  pid_t
1257  {
1258  pid_t pid = -1;
1259 
1260  // Three pairs of file descriptors, for pipes connected to the
1261  // process' stdin, stdout and stderr
1262  // (stored in a single array so close_fd_array() can close all at once)
1263  fd_type fd[] = { -1, -1, -1, -1, -1, -1 };
1264  fd_type* const pin = fd;
1265  fd_type* const pout = fd+2;
1266  fd_type* const perr = fd+4;
1267 
1268  // constants for read/write ends of pipe
1269  enum { RD, WR };
1270 
1271  // N.B.
1272  // For the pstreambuf pin is an output stream and
1273  // pout and perr are input streams.
1274 
1275  if (!error_ && mode&pstdin && ::pipe(pin))
1276  error_ = errno;
1277 
1278  if (!error_ && mode&pstdout && ::pipe(pout))
1279  error_ = errno;
1280 
1281  if (!error_ && mode&pstderr && ::pipe(perr))
1282  error_ = errno;
1283 
1284  if (!error_)
1285  {
1286  pid = ::fork();
1287  switch (pid)
1288  {
1289  case 0 :
1290  {
1291  // this is the new process
1292 
1293  // for each open pipe close one end and redirect the
1294  // respective standard stream to the other end
1295 
1296  if (*pin >= 0)
1297  {
1298  ::close(pin[WR]);
1299  ::dup2(pin[RD], STDIN_FILENO);
1300  ::close(pin[RD]);
1301  }
1302  if (*pout >= 0)
1303  {
1304  ::close(pout[RD]);
1305  ::dup2(pout[WR], STDOUT_FILENO);
1306  ::close(pout[WR]);
1307  }
1308  if (*perr >= 0)
1309  {
1310  ::close(perr[RD]);
1311  ::dup2(perr[WR], STDERR_FILENO);
1312  ::close(perr[WR]);
1313  }
1314 
1315 #ifdef _POSIX_JOB_CONTROL
1316  // Change to a new process group
1317  ::setpgid(0, 0);
1318 #endif
1319 
1320  break;
1321  }
1322  case -1 :
1323  {
1324  // couldn't fork for some reason
1325  error_ = errno;
1326  // close any open pipes
1327  close_fd_array(fd);
1328  break;
1329  }
1330  default :
1331  {
1332  // this is the parent process, store process' pid
1333  ppid_ = pid;
1334 
1335  // store one end of open pipes and close other end
1336  if (*pin >= 0)
1337  {
1338  wpipe_ = pin[WR];
1339  ::close(pin[RD]);
1340  }
1341  if (*pout >= 0)
1342  {
1343  rpipe_[rsrc_out] = pout[RD];
1344  ::close(pout[WR]);
1345  }
1346  if (*perr >= 0)
1347  {
1348  rpipe_[rsrc_err] = perr[RD];
1349  ::close(perr[WR]);
1350  }
1351  }
1352  }
1353  }
1354  else
1355  {
1356  // close any pipes we opened before failure
1357  close_fd_array(fd);
1358  }
1359  return pid;
1360  }
1361 
1371  template <typename C, typename T>
1374  {
1375  const bool running = is_open();
1376 
1377  sync(); // this might call wait() and reap the child process
1378 
1379  // rather than trying to work out whether or not we need to clean up
1380  // just do it anyway, all cleanup functions are safe to call twice.
1381 
1382  destroy_buffers(pstdin|pstdout|pstderr);
1383 
1384  // close pipes before wait() so child gets EOF/SIGPIPE
1385  close_fd(wpipe_);
1386  close_fd_array(rpipe_);
1387 
1388  do
1389  {
1390  error_ = 0;
1391  } while (wait() == -1 && error() == EINTR);
1392 
1393  return running ? this : NULL;
1394  }
1395 
1399  template <typename C, typename T>
1400  inline void
1402  {
1403  rpipe_[rsrc_out] = rpipe_[rsrc_err] = -1;
1404  rbuffer_[rsrc_out] = rbuffer_[rsrc_err] = NULL;
1405  rbufstate_[0] = rbufstate_[1] = rbufstate_[2] = NULL;
1406  }
1407 
1408  template <typename C, typename T>
1409  void
1411  {
1412  if (mode & pstdin)
1413  {
1414  delete[] wbuffer_;
1415  wbuffer_ = new char_type[bufsz];
1416  this->setp(wbuffer_, wbuffer_ + bufsz);
1417  }
1418  if (mode & pstdout)
1419  {
1420  delete[] rbuffer_[rsrc_out];
1421  rbuffer_[rsrc_out] = new char_type[bufsz];
1422  rsrc_ = rsrc_out;
1423  this->setg(rbuffer_[rsrc_out] + pbsz, rbuffer_[rsrc_out] + pbsz,
1424  rbuffer_[rsrc_out] + pbsz);
1425  }
1426  if (mode & pstderr)
1427  {
1428  delete[] rbuffer_[rsrc_err];
1429  rbuffer_[rsrc_err] = new char_type[bufsz];
1430  if (!(mode & pstdout))
1431  {
1432  rsrc_ = rsrc_err;
1433  this->setg(rbuffer_[rsrc_err] + pbsz, rbuffer_[rsrc_err] + pbsz,
1434  rbuffer_[rsrc_err] + pbsz);
1435  }
1436  }
1437  }
1438 
1439  template <typename C, typename T>
1440  void
1442  {
1443  if (mode & pstdin)
1444  {
1445  this->setp(NULL, NULL);
1446  delete[] wbuffer_;
1447  wbuffer_ = NULL;
1448  }
1449  if (mode & pstdout)
1450  {
1451  if (rsrc_ == rsrc_out)
1452  this->setg(NULL, NULL, NULL);
1453  delete[] rbuffer_[rsrc_out];
1454  rbuffer_[rsrc_out] = NULL;
1455  }
1456  if (mode & pstderr)
1457  {
1458  if (rsrc_ == rsrc_err)
1459  this->setg(NULL, NULL, NULL);
1460  delete[] rbuffer_[rsrc_err];
1461  rbuffer_[rsrc_err] = NULL;
1462  }
1463  }
1464 
1465  template <typename C, typename T>
1468  {
1469  if (rsrc_ != src)
1470  {
1471  char_type* tmpbufstate[] = {this->eback(), this->gptr(), this->egptr()};
1472  this->setg(rbufstate_[0], rbufstate_[1], rbufstate_[2]);
1473  for (std::size_t i = 0; i < 3; ++i)
1474  rbufstate_[i] = tmpbufstate[i];
1475  rsrc_ = src;
1476  }
1477  return rsrc_;
1478  }
1479 
1496  template <typename C, typename T>
1497  int
1499  {
1500  int exited = -1;
1501  if (is_open())
1502  {
1503  int status;
1504  switch(::waitpid(ppid_, &status, nohang ? WNOHANG : 0))
1505  {
1506  case 0 :
1507  // nohang was true and process has not exited
1508  exited = 0;
1509  break;
1510  case -1 :
1511  error_ = errno;
1512  break;
1513  default :
1514  // process has exited
1515  ppid_ = 0;
1516  status_ = status;
1517  exited = 1;
1518  // Close wpipe, would get SIGPIPE if we used it.
1519  destroy_buffers(pstdin);
1520  close_fd(wpipe_);
1521  // Must free read buffers and pipes on destruction
1522  // or next call to open()/close()
1523  break;
1524  }
1525  }
1526  return exited;
1527  }
1528 
1539  template <typename C, typename T>
1540  inline basic_pstreambuf<C,T>*
1542  {
1543  basic_pstreambuf<C,T>* ret = NULL;
1544  if (is_open())
1545  {
1546  if (::kill(ppid_, signal))
1547  error_ = errno;
1548  else
1549  {
1550 #if 0
1551  // TODO call exited() to check for exit and clean up? leave to user?
1552  if (signal==SIGTERM || signal==SIGKILL)
1553  this->exited();
1554 #endif
1555  ret = this;
1556  }
1557  }
1558  return ret;
1559  }
1560 
1574  template <typename C, typename T>
1575  inline basic_pstreambuf<C,T>*
1577  {
1578  basic_pstreambuf<C,T>* ret = NULL;
1579 #ifdef _POSIX_JOB_CONTROL
1580  if (is_open())
1581  {
1582  pid_t pgid = ::getpgid(ppid_);
1583  if (pgid == -1)
1584  error_ = errno;
1585  else if (pgid == ::getpgrp())
1586  error_ = EPERM; // Don't commit suicide
1587  else if (::killpg(pgid, signal))
1588  error_ = errno;
1589  else
1590  ret = this;
1591  }
1592 #endif
1593  return ret;
1594  }
1595 
1603  template <typename C, typename T>
1604  inline bool
1606  {
1607  return ppid_ == 0 || wait(true)==1;
1608  }
1609 
1610 
1616  template <typename C, typename T>
1617  inline int
1619  {
1620  return status_;
1621  }
1622 
1626  template <typename C, typename T>
1627  inline int
1629  {
1630  return error_;
1631  }
1632 
1637  template <typename C, typename T>
1638  inline void
1640  {
1641  sync();
1642  destroy_buffers(pstdin);
1643  close_fd(wpipe_);
1644  }
1645 
1656  template <typename C, typename T>
1657  inline bool
1659  {
1660  return ppid_ > 0;
1661  }
1662 
1671  template <typename C, typename T>
1672  inline bool
1674  {
1675  buf_read_src src = readerr ? rsrc_err : rsrc_out;
1676  if (rpipe_[src]>=0)
1677  {
1678  switch_read_buffer(src);
1679  return true;
1680  }
1681  return false;
1682  }
1683 
1694  template <typename C, typename T>
1695  typename basic_pstreambuf<C,T>::int_type
1697  {
1698  if (!empty_buffer())
1699  return traits_type::eof();
1700  else if (!traits_type::eq_int_type(c, traits_type::eof()))
1701  return this->sputc(c);
1702  else
1703  return traits_type::not_eof(c);
1704  }
1705 
1706 
1707  template <typename C, typename T>
1708  int
1710  {
1711  return !exited() && empty_buffer() ? 0 : -1;
1712  }
1713 
1719  template <typename C, typename T>
1720  std::streamsize
1721  basic_pstreambuf<C,T>::xsputn(const char_type* s, std::streamsize n)
1722  {
1723  std::streamsize done = 0;
1724  while (done < n)
1725  {
1726  if (std::streamsize nbuf = this->epptr() - this->pptr())
1727  {
1728  nbuf = std::min(nbuf, n - done);
1729  traits_type::copy(this->pptr(), s + done, nbuf);
1730  this->pbump(nbuf);
1731  done += nbuf;
1732  }
1733  else if (!empty_buffer())
1734  break;
1735  }
1736  return done;
1737  }
1738 
1742  template <typename C, typename T>
1743  bool
1745  {
1746  const std::streamsize count = this->pptr() - this->pbase();
1747  if (count > 0)
1748  {
1749  const std::streamsize written = this->write(this->wbuffer_, count);
1750  if (written > 0)
1751  {
1752  if (const std::streamsize unwritten = count - written)
1753  traits_type::move(this->pbase(), this->pbase()+written, unwritten);
1754  this->pbump(-written);
1755  return true;
1756  }
1757  }
1758  return false;
1759  }
1760 
1768  template <typename C, typename T>
1769  typename basic_pstreambuf<C,T>::int_type
1771  {
1772  if (this->gptr() < this->egptr() || fill_buffer())
1773  return traits_type::to_int_type(*this->gptr());
1774  else
1775  return traits_type::eof();
1776  }
1777 
1786  template <typename C, typename T>
1787  typename basic_pstreambuf<C,T>::int_type
1789  {
1790  if (this->gptr() != this->eback())
1791  {
1792  this->gbump(-1);
1793  if (!traits_type::eq_int_type(c, traits_type::eof()))
1794  *this->gptr() = traits_type::to_char_type(c);
1795  return traits_type::not_eof(c);
1796  }
1797  else
1798  return traits_type::eof();
1799  }
1800 
1801  template <typename C, typename T>
1802  std::streamsize
1804  {
1805  int avail = 0;
1806  if (sizeof(char_type) == 1)
1807  avail = fill_buffer(true) ? this->egptr() - this->gptr() : -1;
1808 #ifdef FIONREAD
1809  else
1810  {
1811  if (::ioctl(rpipe(), FIONREAD, &avail) == -1)
1812  avail = -1;
1813  else if (avail)
1814  avail /= sizeof(char_type);
1815  }
1816 #endif
1817  return std::streamsize(avail);
1818  }
1819 
1823  template <typename C, typename T>
1824  bool
1826  {
1827  const std::streamsize pb1 = this->gptr() - this->eback();
1828  const std::streamsize pb2 = pbsz;
1829  const std::streamsize npb = std::min(pb1, pb2);
1830 
1831  char_type* const rbuf = rbuffer();
1832 
1833  traits_type::move(rbuf + pbsz - npb, this->gptr() - npb, npb);
1834 
1835  std::streamsize rc = -1;
1836 
1837  if (non_blocking)
1838  {
1839  const int flags = ::fcntl(rpipe(), F_GETFL);
1840  if (flags != -1)
1841  {
1842  const bool blocking = !(flags & O_NONBLOCK);
1843  if (blocking)
1844  ::fcntl(rpipe(), F_SETFL, flags | O_NONBLOCK); // set non-blocking
1845 
1846  error_ = 0;
1847  rc = read(rbuf + pbsz, bufsz - pbsz);
1848 
1849  if (rc == -1 && error_ == EAGAIN) // nothing available
1850  rc = 0;
1851  else if (rc == 0) // EOF
1852  rc = -1;
1853 
1854  if (blocking)
1855  ::fcntl(rpipe(), F_SETFL, flags); // restore
1856  }
1857  }
1858  else
1859  rc = read(rbuf + pbsz, bufsz - pbsz);
1860 
1861  if (rc > 0 || (rc == 0 && non_blocking))
1862  {
1863  this->setg( rbuf + pbsz - npb,
1864  rbuf + pbsz,
1865  rbuf + pbsz + rc );
1866  return true;
1867  }
1868  else
1869  {
1870  this->setg(NULL, NULL, NULL);
1871  return false;
1872  }
1873  }
1874 
1882  template <typename C, typename T>
1883  inline std::streamsize
1884  basic_pstreambuf<C,T>::write(const char_type* s, std::streamsize n)
1885  {
1886  std::streamsize nwritten = 0;
1887  if (wpipe() >= 0)
1888  {
1889  nwritten = ::write(wpipe(), s, n * sizeof(char_type));
1890  if (nwritten == -1)
1891  error_ = errno;
1892  else
1893  nwritten /= sizeof(char_type);
1894  }
1895  return nwritten;
1896  }
1897 
1905  template <typename C, typename T>
1906  inline std::streamsize
1907  basic_pstreambuf<C,T>::read(char_type* s, std::streamsize n)
1908  {
1909  std::streamsize nread = 0;
1910  if (rpipe() >= 0)
1911  {
1912  nread = ::read(rpipe(), s, n * sizeof(char_type));
1913  if (nread == -1)
1914  error_ = errno;
1915  else
1916  nread /= sizeof(char_type);
1917  }
1918  return nread;
1919  }
1920 
1922  template <typename C, typename T>
1923  inline pstreams::fd_type&
1925  {
1926  return wpipe_;
1927  }
1928 
1930  template <typename C, typename T>
1931  inline pstreams::fd_type&
1933  {
1934  return rpipe_[rsrc_];
1935  }
1936 
1938  template <typename C, typename T>
1939  inline pstreams::fd_type&
1941  {
1942  return rpipe_[which];
1943  }
1944 
1946  template <typename C, typename T>
1947  inline typename basic_pstreambuf<C,T>::char_type*
1949  {
1950  return rbuffer_[rsrc_];
1951  }
1952 
1953 
1954  /*
1955  * member definitions for pstream_common
1956  */
1957 
1967  template <typename C, typename T>
1968  inline
1970  : std::basic_ios<C,T>(NULL)
1971  , command_()
1972  , buf_()
1973  {
1974  this->std::basic_ios<C,T>::rdbuf(&buf_);
1975  }
1976 
1985  template <typename C, typename T>
1986  inline
1988  : std::basic_ios<C,T>(NULL)
1989  , command_(command)
1990  , buf_()
1991  {
1992  this->std::basic_ios<C,T>::rdbuf(&buf_);
1993  do_open(command, mode);
1994  }
1995 
2005  template <typename C, typename T>
2006  inline
2007  pstream_common<C,T>::pstream_common( const std::string& file,
2008  const argv_type& argv,
2009  pmode mode )
2010  : std::basic_ios<C,T>(NULL)
2011  , command_(file)
2012  , buf_()
2013  {
2014  this->std::basic_ios<C,T>::rdbuf(&buf_);
2015  do_open(file, argv, mode);
2016  }
2017 
2027  template <typename C, typename T>
2028  inline
2030  {
2031  }
2032 
2041  template <typename C, typename T>
2042  inline void
2043  pstream_common<C,T>::do_open(const std::string& command, pmode mode)
2044  {
2045  if (!buf_.open((command_=command), mode))
2046  this->setstate(std::ios_base::failbit);
2047  }
2048 
2058  template <typename C, typename T>
2059  inline void
2060  pstream_common<C,T>::do_open( const std::string& file,
2061  const argv_type& argv,
2062  pmode mode )
2063  {
2064  if (!buf_.open((command_=file), argv, mode))
2065  this->setstate(std::ios_base::failbit);
2066  }
2067 
2069  template <typename C, typename T>
2070  inline void
2072  {
2073  if (!buf_.close())
2074  this->setstate(std::ios_base::failbit);
2075  }
2076 
2081  template <typename C, typename T>
2082  inline bool
2084  {
2085  return buf_.is_open();
2086  }
2087 
2089  template <typename C, typename T>
2090  inline const std::string&
2092  {
2093  return command_;
2094  }
2095 
2097  // TODO document behaviour if buffer replaced.
2098  template <typename C, typename T>
2099  inline typename pstream_common<C,T>::streambuf_type*
2101  {
2102  return const_cast<streambuf_type*>(&buf_);
2103  }
2104 
2105 
2106 #if REDI_EVISCERATE_PSTREAMS
2107 
2139  template <typename C, typename T>
2140  std::size_t
2141  basic_pstreambuf<C,T>::fopen(FILE*& in, FILE*& out, FILE*& err)
2142  {
2143  in = out = err = NULL;
2144  std::size_t open_files = 0;
2145  if (wpipe() > -1)
2146  {
2147  if ((in = ::fdopen(wpipe(), "w")))
2148  {
2149  open_files |= pstdin;
2150  }
2151  }
2152  if (rpipe(rsrc_out) > -1)
2153  {
2154  if ((out = ::fdopen(rpipe(rsrc_out), "r")))
2155  {
2156  open_files |= pstdout;
2157  }
2158  }
2159  if (rpipe(rsrc_err) > -1)
2160  {
2161  if ((err = ::fdopen(rpipe(rsrc_err), "r")))
2162  {
2163  open_files |= pstderr;
2164  }
2165  }
2166  return open_files;
2167  }
2168 
2179  template <typename C, typename T>
2180  inline std::size_t
2181  pstream_common<C,T>::fopen(FILE*& fin, FILE*& fout, FILE*& ferr)
2182  {
2183  return buf_.fopen(fin, fout, ferr);
2184  }
2185 
2186 #endif // REDI_EVISCERATE_PSTREAMS
2187 
2188 
2189 } // namespace redi
2190 
2196 #endif // REDI_PSTREAM_H_SEEN
2197 
2198 // vim: ts=2 sw=2 expandtab
2199 
void close_fd(pstreams::fd_type &fd)
Helper function to close a file descriptor.
Definition: pstream.h:1095
basic_pstream(const std::string &command, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:649
int_type overflow(int_type c)
Transfer characters to the pipe when character buffer overflows.
Definition: pstream.h:1696
std::streamsize write(const char_type *s, std::streamsize n)
Insert a sequence of characters into the pipe.
Definition: pstream.h:1884
int error() const
Return the error number (errno) for the most recent failed operation.
Definition: pstream.h:1628
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:787
fd_type fd_t
Definition: pstream.h:110
~basic_pstream()
Destructor.
Definition: pstream.h:689
fd_type & wpipe()
Return the file descriptor for the output pipe.
Definition: pstream.h:1924
Class template for Bidirectional PStreams.
Definition: pstream.h:617
char_type * rbuffer()
Return the active input buffer.
Definition: pstream.h:1948
Class template for stream buffer.
Definition: pstream.h:98
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:364
std::streamsize read(char_type *s, std::streamsize n)
Extract a sequence of characters from the pipe.
Definition: pstream.h:1907
basic_rpstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:790
void open(const std::string &command, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:853
basic_pstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:635
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:506
bool read_err(bool readerr=true)
Change active input source.
Definition: pstream.h:1673
basic_rpstream(const std::string &command, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:804
virtual ~pstream_common()=0
Pure virtual destructor.
Definition: pstream.h:2029
void close_fd_array(pstreams::fd_type(&fds)[N])
Helper function to close an array of file descriptors.
Definition: pstream.h:1113
std::vector< std::string > argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:82
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:367
pstream_common()
Default constructor.
Definition: pstream.h:1969
int_type underflow()
Transfer characters from the pipe when the character buffer is empty.
Definition: pstream.h:1770
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:869
Class template for common base class.
Definition: pstream.h:274
basic_rpstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:835
basic_ipstream(const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:415
basic_pstream(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:664
basic_opstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:512
basic_pstreambuf< char > pstreambuf
Type definition for common template specialisation.
Definition: pstream.h:903
static const pmode pstderr
Read from stderr.
Definition: pstream.h:89
streambuf_type * rdbuf() const
Return a pointer to the stream buffer.
Definition: pstream.h:2100
int_type pbackfail(int_type c=traits_type::eof())
Make a character available to be returned by the next extraction.
Definition: pstream.h:1788
Common base class providing constants and typenames.
Definition: pstream.h:76
bool fill_buffer(bool non_blocking=false)
Definition: pstream.h:1825
static const pmode pstdout
Read from stdout.
Definition: pstream.h:88
int sync()
Write any buffered characters to the stream.
Definition: pstream.h:1709
basic_rpstream(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:819
basic_pstreambuf()
Default constructor.
Definition: pstream.h:950
basic_ipstream(const std::string &command, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:384
std::string command_
The command used to start the process.
Definition: pstream.h:329
bool exited()
Report whether the process has exited.
Definition: pstream.h:1605
streambuf_type buf_
The stream buffer.
Definition: pstream.h:330
buf_read_src
Enumerated type to indicate whether stdout or stderr is to be read.
Definition: pstream.h:211
basic_pstream & out()
Set streambuf to read from process&#39; stdout.
Definition: pstream.h:729
bool is_open() const
Report whether the stream&#39;s buffer has been initialised.
Definition: pstream.h:2083
basic_ipstream(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:399
Class template for Input PStreams.
Definition: pstream.h:345
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:632
std::streamsize xsputn(const char_type *s, std::streamsize n)
Insert multiple characters into the pipe.
Definition: pstream.h:1721
pid_t fork(pmode mode)
Initialise pipes and fork process.
Definition: pstream.h:1256
void open(const std::string &command, pmode mode=pstdin)
Start a process.
Definition: pstream.h:578
basic_ipstream & err()
Set streambuf to read from process&#39; stderr.
Definition: pstream.h:476
basic_pstream & err()
Set streambuf to read from process&#39; stderr.
Definition: pstream.h:740
basic_opstream(const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:557
basic_rpstream< char > rpstream
Type definition for common template specialisation.
Definition: pstream.h:911
basic_ipstream & out()
Set streambuf to read from process&#39; stdout.
Definition: pstream.h:465
void open(const std::string &command, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:701
pbase_type::argv_type argv_type
Type used to hold the arguments for a command.
Definition: pstream.h:509
All PStreams classes are declared in namespace redi.
int fd_type
Type used for file descriptors.
Definition: pstream.h:85
~basic_pstreambuf()
Destructor.
Definition: pstream.h:1014
basic_pstream(const argv_type &argv, pmode mode=pstdout|pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:680
std::ios_base::openmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:79
Class template for Restricted PStreams.
Definition: pstream.h:770
basic_pstreambuf * killpg(int signal=SIGTERM)
Send a signal to the process&#39; process group.
Definition: pstream.h:1576
basic_pstreambuf * close()
Close the stream buffer and wait for the process to exit.
Definition: pstream.h:1373
bool is_open() const
Report whether the stream buffer has been initialised.
Definition: pstream.h:1658
bool empty_buffer()
Writes buffered characters to the process&#39; stdin pipe.
Definition: pstream.h:1744
void do_open(const std::string &command, pmode mode)
Start a process.
Definition: pstream.h:2043
~basic_ipstream()
Destructor.
Definition: pstream.h:424
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:784
std::basic_ostream< C, T > & peof(std::basic_ostream< C, T > &s)
Manipulator to close the pipe connected to the process&#39; stdin.
Definition: pstream.h:928
basic_ipstream< char > ipstream
Type definition for common template specialisation.
Definition: pstream.h:905
void open(const std::string &command, pmode mode=pstdout)
Start a process.
Definition: pstream.h:437
int wait(bool nohang=false)
Wait for the child process to exit.
Definition: pstream.h:1498
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout)
Start a process.
Definition: pstream.h:453
Class template for Output PStreams.
Definition: pstream.h:494
const std::string & command() const
Return the command used to initialise the stream.
Definition: pstream.h:2091
basic_pstreambuf * open(const std::string &command, pmode mode)
Initialise the stream buffer with command.
Definition: pstream.h:1048
fd_type & rpipe()
Return the file descriptor for the active input pipe.
Definition: pstream.h:1932
istream_type & err()
Obtain a reference to the istream that reads the process&#39; stderr.
Definition: pstream.h:894
basic_ipstream()
Default constructor, creates an uninitialised stream.
Definition: pstream.h:370
~basic_rpstream()
Destructor.
Definition: pstream.h:841
void close()
Close the pipe.
Definition: pstream.h:2071
void peof()
Close the pipe connected to the process&#39; stdin.
Definition: pstream.h:1639
basic_opstream< char > opstream
Type definition for common template specialisation.
Definition: pstream.h:907
pbase_type::pmode pmode
Type used to specify how to connect to the process.
Definition: pstream.h:629
void open(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Start a process.
Definition: pstream.h:594
int status() const
Return the exit status of the process.
Definition: pstream.h:1618
basic_pstream< char > pstream
Type definition for common template specialisation.
Definition: pstream.h:909
static const pmode pstdin
Write to stdin.
Definition: pstream.h:87
std::streamsize showmanyc()
Report how many characters can be read from active input without blocking.
Definition: pstream.h:1803
void open(const std::string &file, const argv_type &argv, pmode mode=pstdout|pstdin)
Start a process.
Definition: pstream.h:717
basic_opstream(const std::string &file, const argv_type &argv, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:541
basic_opstream(const std::string &command, pmode mode=pstdin)
Constructor that initialises the stream by starting a process.
Definition: pstream.h:526
basic_pstreambuf * kill(int signal=SIGTERM)
Send a signal to the process.
Definition: pstream.h:1541
istream_type & out()
Obtain a reference to the istream that reads the process&#39; stdout.
Definition: pstream.h:882
~basic_opstream()
Destructor.
Definition: pstream.h:566