source: launchers/macosx/include/subprocess.hpp @ beede950

Last change on this file since beede950 was beede950, checked in by meeh <meeh@…>, 2 years ago

Preparing for XCode project. Removing now obsolete files.

  • Property mode set to 100644
File size: 43.1 KB
Line 
1/*!
2
3Documentation for C++ subprocessing libraray.
4
5@copyright The code is licensed under the [MIT
6  License](http://opensource.org/licenses/MIT):
7  <br>
8  Copyright &copy; 2016-2018 Arun Muralidharan.
9  <br>
10  Permission is hereby granted, free of charge, to any person obtaining a copy
11  of this software and associated documentation files (the "Software"), to deal
12  in the Software without restriction, including without limitation the rights
13  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  copies of the Software, and to permit persons to whom the Software is
15  furnished to do so, subject to the following conditions:
16  <br>
17  The above copyright notice and this permission notice shall be included in
18  all copies or substantial portions of the Software.
19  <br>
20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  SOFTWARE.
27
28@author [Arun Muralidharan]
29@see https://github.com/arun11299/cpp-subprocess to download the source code
30
31@version 1.0.0
32*/
33
34#ifndef SUBPROCESS_HPP
35#define SUBPROCESS_HPP
36
37#include <map>
38#include <algorithm>
39#include <iostream>
40#include <string>
41#include <cstdlib>
42#include <cassert>
43#include <cstring>
44#include <cstdio>
45#include <csignal>
46#include <future>
47#include <vector>
48#include <sstream>
49#include <memory>
50#include <initializer_list>
51#include <exception>
52
53extern "C" {
54  #include <unistd.h>
55  #include <fcntl.h>
56  #include <sys/types.h>
57  #include <sys/wait.h>
58  #include <signal.h>
59}
60
61/*!
62 * Getting started with reading this source code.
63 * The source is mainly divided into four parts:
64 * 1. Exception Classes:
65 *    These are very basic exception classes derived from
66 *    runtime_error exception.
67 *    There are two types of exception thrown from subprocess
68 *    library: OSError and CalledProcessError
69 *
70 * 2. Popen Class
71 *    This is the main class the users will deal with. It
72 *    provides with all the API's to deal with processes.
73 *
74 * 3. Util namespace
75 *    It includes some helper functions to split/join a string,
76 *    reading from file descriptors, waiting on a process, fcntl
77 *    options on file descriptors etc.
78 *
79 * 4. Detail namespace
80 *    This includes some metaprogramming and helper classes.
81 */
82
83
84namespace subprocess {
85
86// Max buffer size allocated on stack for read error
87// from pipe
88static const size_t SP_MAX_ERR_BUF_SIZ = 1024;
89
90// Default buffer capcity for OutBuffer and ErrBuffer.
91// If the data exceeds this capacity, the buffer size is grown
92// by 1.5 times its previous capacity
93static const size_t DEFAULT_BUF_CAP_BYTES = 8192;
94
95
96/*-----------------------------------------------
97 *    EXCEPTION CLASSES
98 *-----------------------------------------------
99 */
100
101/*!
102 * class: CalledProcessError
103 * Thrown when there was error executing the command.
104 * Check Popen class API's to know when this exception
105 * can be thrown.
106 *
107 */
108class CalledProcessError: public std::runtime_error
109{
110public:
111  CalledProcessError(const std::string& error_msg):
112    std::runtime_error(error_msg)
113  {}
114};
115
116
117/*!
118 * class: OSError
119 * Thrown when some system call fails to execute or give result.
120 * The exception message contains the name of the failed system call
121 * with the stringisized errno code.
122 * Check Popen class API's to know when this exception would be
123 * thrown.
124 * Its usual that the API exception specification would have
125 * this exception together with CalledProcessError.
126 */
127class OSError: public std::runtime_error
128{
129public:
130  OSError(const std::string& err_msg, int err_code):
131    std::runtime_error( err_msg + " : " + std::strerror(err_code) )
132  {}
133};
134
135//--------------------------------------------------------------------
136
137namespace util
138{
139
140  /*!
141   * Function: split
142   * Parameters:
143   * [in] str : Input string which needs to be split based upon the
144   *            delimiters provided.
145   * [in] deleims : Delimiter characters based upon which the string needs
146   *                to be split. Default constructed to ' '(space) and '\t'(tab)
147   * [out] vector<string> : Vector of strings split at deleimiter.
148   */
149  static inline std::vector<std::string>
150  split(const std::string& str, const std::string& delims=" \t")
151  {
152    std::vector<std::string> res;
153    size_t init = 0;
154
155    while (true) {
156      auto pos = str.find_first_of(delims, init);
157      if (pos == std::string::npos) {
158        res.emplace_back(str.substr(init, str.length()));
159        break;
160      }
161      res.emplace_back(str.substr(init, pos - init));
162      pos++;
163      init = pos;
164    }
165
166    return res;
167  }
168
169
170  /*!
171   * Function: join
172   * Parameters:
173   * [in] vec : Vector of strings which needs to be joined to form
174   *            a single string with words seperated by a seperator char.
175   *  [in] sep : String used to seperate 2 words in the joined string.
176   *             Default constructed to ' ' (space).
177   *  [out] string: Joined string.
178   */
179  static inline
180  std::string join(const std::vector<std::string>& vec,
181                   const std::string& sep = " ")
182  {
183    std::string res;
184    for (auto& elem : vec) res.append(elem + sep);
185    res.erase(--res.end());
186    return res;
187  }
188
189
190  /*!
191   * Function: set_clo_on_exec
192   * Sets/Resets the FD_CLOEXEC flag on the provided file descriptor
193   * based upon the `set` parameter.
194   * Parameters:
195   * [in] fd : The descriptor on which FD_CLOEXEC needs to be set/reset.
196   * [in] set : If 'true', set FD_CLOEXEC.
197   *            If 'false' unset FD_CLOEXEC.
198   */
199  static inline
200  void set_clo_on_exec(int fd, bool set = true)
201  {
202    int flags = fcntl(fd, F_GETFD, 0);
203    if (set) flags |= FD_CLOEXEC;
204    else flags &= ~FD_CLOEXEC;
205    //TODO: should check for errors
206    fcntl(fd, F_SETFD, flags);
207  }
208
209
210  /*!
211   * Function: pipe_cloexec
212   * Creates a pipe and sets FD_CLOEXEC flag on both
213   * read and write descriptors of the pipe.
214   * Parameters:
215   * [out] : A pair of file descriptors.
216   *         First element of pair is the read descriptor of pipe.
217   *         Second element is the write descriptor of pipe.
218   */
219  static inline
220  std::pair<int, int> pipe_cloexec() throw (OSError)
221  {
222    int pipe_fds[2];
223    int res = pipe(pipe_fds);
224    if (res) {
225      throw OSError("pipe failure", errno);
226    }
227
228    set_clo_on_exec(pipe_fds[0]);
229    set_clo_on_exec(pipe_fds[1]);
230
231    return std::make_pair(pipe_fds[0], pipe_fds[1]);
232  }
233
234
235  /*!
236   * Function: write_n
237   * Writes `length` bytes to the file descriptor `fd`
238   * from the buffer `buf`.
239   * Parameters:
240   * [in] fd : The file descriptotr to write to.
241   * [in] buf: Buffer from which data needs to be written to fd.
242   * [in] length: The number of bytes that needs to be written from
243   *              `buf` to `fd`.
244   * [out] int : Number of bytes written or -1 in case of failure.
245   */
246  static inline
247  int write_n(int fd, const char* buf, size_t length)
248  {
249    size_t nwritten = 0;
250    while (nwritten < length) {
251      int written = write(fd, buf + nwritten, length - nwritten);
252      if (written == -1) return -1;
253      nwritten += written;
254    }
255    return nwritten;
256  }
257
258
259  /*!
260   * Function: read_atmost_n
261   * Reads at the most `read_upto` bytes from the
262   * file descriptor `fd` before returning.
263   * Parameters:
264   * [in] fd : The file descriptor from which it needs to read.
265   * [in] buf : The buffer into which it needs to write the data.
266   * [in] read_upto: Max number of bytes which must be read from `fd`.
267   * [out] int : Number of bytes written to `buf` or read from `fd`
268   *             OR -1 in case of error.
269   *  NOTE: In case of EINTR while reading from socket, this API
270   *  will retry to read from `fd`, but only till the EINTR counter
271   *  reaches 50 after which it will return with whatever data it read.
272   */
273  static inline
274  int read_atmost_n(int fd, char* buf, size_t read_upto)
275  {
276    int rbytes = 0;
277    int eintr_cnter = 0;
278
279    while (1) {
280      int read_bytes = read(fd, buf + rbytes, read_upto - rbytes);
281      if (read_bytes == -1) {
282        if (errno == EINTR) {
283          if (eintr_cnter >= 50) return -1;
284          eintr_cnter++;
285          continue;
286        }
287        return -1;
288      }
289      if (read_bytes == 0) return rbytes;
290
291      rbytes += read_bytes;
292    }
293    return rbytes;
294  }
295
296
297  /*!
298   * Function: read_all
299   * Reads all the available data from `fd` into
300   * `buf`. Internally calls read_atmost_n.
301   * Parameters:
302   * [in] fd : The file descriptor from which to read from.
303   * [in] buf : The buffer of type `class Buffer` into which
304   *            the read data is written to.
305   * [out] int: Number of bytes read OR -1 in case of failure.
306   *
307   * NOTE: `class Buffer` is a exposed public class. See below.
308   */
309  template <typename Buffer>
310  // Requires Buffer to be of type class Buffer
311  static inline int read_all(int fd, Buffer& buf)
312  {
313    size_t orig_size = buf.size();
314    int increment = orig_size;
315    auto buffer = buf.data();
316    int total_bytes_read = 0;
317
318    while (1) {
319      int rd_bytes = read_atmost_n(fd, buffer, buf.size());
320      if (rd_bytes == increment) {
321        // Resize the buffer to accomodate more
322        orig_size = orig_size * 1.5;
323        increment = orig_size - buf.size();
324        buf.resize(orig_size);
325        //update the buffer pointer
326        buffer = buf.data();
327        buffer += rd_bytes;
328        total_bytes_read += rd_bytes;
329
330      } else if (rd_bytes != -1) {
331        total_bytes_read += rd_bytes;
332        break;
333
334      } else {
335        if (total_bytes_read == 0) return -1;
336        break;
337      }
338    }
339    return total_bytes_read;
340  }
341
342
343  /*!
344   * Function: wait_for_child_exit
345   * Waits for the process with pid `pid` to exit
346   * and returns its status.
347   * Parameters:
348   * [in] pid : The pid of the process.
349   * [out] pair<int, int>:
350   *    pair.first : Return code of the waitpid call.
351   *    pair.second : Exit status of the process.
352   *
353   *  NOTE: This is a blocking call as in, it will loop
354   *  till the child is exited.
355   */
356  static inline
357  std::pair<int, int> wait_for_child_exit(int pid)
358  {
359    int status = 0;
360    int ret = -1;
361    while (1) {
362      ret = waitpid(pid, &status, WNOHANG);
363      if (ret == -1) break;
364      if (ret == 0) continue;
365      return std::make_pair(ret, status);
366    }
367
368    return std::make_pair(ret, status);
369  }
370
371
372}; // end namespace util
373
374
375
376/* -------------------------------
377 *     Popen Arguments
378 * -------------------------------
379 */
380
381/*!
382 * The buffer size of the stdin/stdout/stderr
383 * streams of the child process.
384 * Default value is 0.
385 */
386struct bufsize {
387  bufsize(int siz): bufsiz(siz) {}
388  int  bufsiz = 0;
389};
390
391/*!
392 * Option to defer spawning of the child process
393 * till `Popen::start_process` API is called.
394 * Default value is false.
395 */
396struct defer_spawn {
397  defer_spawn(bool d): defer(d) {}
398  bool defer  = false;
399};
400
401/*!
402 * Option to close all file descriptors
403 * when the child process is spawned.
404 * The close fd list does not include
405 * input/output/error if they are explicitly
406 * set as part of the Popen arguments.
407 *
408 * Default value is false.
409 */
410struct close_fds {
411  close_fds(bool c): close_all(c) {}
412  bool close_all = false;
413};
414
415/*!
416 * Option to make the child process as the
417 * session leader and thus the process
418 * group leader.
419 * Default value is false.
420 */
421struct session_leader {
422  session_leader(bool sl): leader_(sl) {}
423  bool leader_ = false;
424};
425
426struct shell {
427  shell(bool s): shell_(s) {}
428  bool shell_ = false;
429};
430
431/*!
432 * Base class for all arguments involving string value.
433 */
434struct string_arg
435{
436  string_arg(const char* arg): arg_value(arg) {}
437  string_arg(std::string&& arg): arg_value(std::move(arg)) {}
438  string_arg(std::string arg): arg_value(std::move(arg)) {}
439  std::string arg_value;
440};
441
442/*!
443 * Option to specify the executable name seperately
444 * from the args sequence.
445 * In this case the cmd args must only contain the
446 * options required for this executable.
447 *
448 * Eg: executable{"ls"}
449 */
450struct executable: string_arg
451{
452  template <typename T>
453  executable(T&& arg): string_arg(std::forward<T>(arg)) {}
454};
455
456/*!
457 * Option to set the current working directory
458 * of the spawned process.
459 *
460 * Eg: cwd{"/som/path/x"}
461 */
462struct cwd: string_arg
463{
464  template <typename T>
465  cwd(T&& arg): string_arg(std::forward<T>(arg)) {}
466};
467
468/*!
469 * Option to specify environment variables required by
470 * the spawned process.
471 *
472 * Eg: environment{{ {"K1", "V1"}, {"K2", "V2"},... }}
473 */
474struct environment
475{
476  environment(std::map<std::string, std::string>&& env):
477    env_(std::move(env)) {}
478  environment(const std::map<std::string, std::string>& env):
479    env_(env) {}
480  std::map<std::string, std::string> env_;
481};
482
483
484/*!
485 * Used for redirecting input/output/error
486 */
487enum IOTYPE {
488  STDOUT = 1,
489  STDERR,
490  PIPE,
491};
492
493//TODO: A common base/interface for below stream structures ??
494
495/*!
496 * Option to specify the input channel for the child
497 * process. It can be:
498 * 1. An already open file descriptor.
499 * 2. A file name.
500 * 3. IOTYPE. Usuall a PIPE
501 *
502 * Eg: input{PIPE}
503 * OR in case of redirection, output of another Popen
504 * input{popen.output()}
505 */
506struct input
507{
508  // For an already existing file descriptor.
509  input(int fd): rd_ch_(fd) {}
510
511  // FILE pointer.
512  input (FILE* fp):input(fileno(fp)) { assert(fp); }
513
514  input(const char* filename) {
515    int fd = open(filename, O_RDONLY);
516    if (fd == -1) throw OSError("File not found: ", errno);
517    rd_ch_ = fd;
518  }
519  input(IOTYPE typ) {
520    assert (typ == PIPE && "STDOUT/STDERR not allowed");
521    std::tie(rd_ch_, wr_ch_) = util::pipe_cloexec();
522  }
523
524  int rd_ch_ = -1;
525  int wr_ch_ = -1;
526};
527
528
529/*!
530 * Option to specify the output channel for the child
531 * process. It can be:
532 * 1. An already open file descriptor.
533 * 2. A file name.
534 * 3. IOTYPE. Usually a PIPE.
535 *
536 * Eg: output{PIPE}
537 * OR output{"output.txt"}
538 */
539struct output
540{
541  output(int fd): wr_ch_(fd) {}
542
543  output (FILE* fp):output(fileno(fp)) { assert(fp); }
544
545  output(const char* filename) {
546    int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
547    if (fd == -1) throw OSError("File not found: ", errno);
548    wr_ch_ = fd;
549  }
550  output(IOTYPE typ) {
551    assert (typ == PIPE && "STDOUT/STDERR not allowed");
552    std::tie(rd_ch_, wr_ch_) = util::pipe_cloexec();
553  }
554
555  int rd_ch_ = -1;
556  int wr_ch_ = -1;
557};
558
559
560/*!
561 * Option to specify the error channel for the child
562 * process. It can be:
563 * 1. An already open file descriptor.
564 * 2. A file name.
565 * 3. IOTYPE. Usually a PIPE or STDOUT
566 *
567 */
568struct error
569{
570  error(int fd): wr_ch_(fd) {}
571
572  error(FILE* fp):error(fileno(fp)) { assert(fp); }
573
574  error(const char* filename) {
575    int fd = open(filename, O_APPEND | O_CREAT | O_RDWR, 0640);
576    if (fd == -1) throw OSError("File not found: ", errno);
577    wr_ch_ = fd;
578  }
579  error(IOTYPE typ) {
580    assert ((typ == PIPE || typ == STDOUT) && "STDERR not aloowed");
581    if (typ == PIPE) {
582      std::tie(rd_ch_, wr_ch_) = util::pipe_cloexec();
583    } else {
584      // Need to defer it till we have checked all arguments
585      deferred_ = true;
586    }
587  }
588
589  bool deferred_ = false;
590  int rd_ch_ = -1;
591  int wr_ch_ = -1;
592};
593
594// Impoverished, meager, needy, truly needy
595// version of type erasure to store function pointers
596// needed to provide the functionality of preexec_func
597// ATTN: Can be used only to execute functions with no
598// arguments and returning void.
599// Could have used more efficient methods, ofcourse, but
600// that wont yield me the consistent syntax which I am
601// aiming for. If you know, then please do let me know.
602
603class preexec_func
604{
605public:
606  preexec_func() {}
607
608  template <typename Func>
609  preexec_func(Func f): holder_(new FuncHolder<Func>(f))
610  {}
611
612  void operator()() {
613    (*holder_)();
614  }
615
616private:
617  struct HolderBase {
618    virtual void operator()() const = 0;
619  };
620  template <typename T>
621  struct FuncHolder: HolderBase {
622    FuncHolder(T func): func_(func) {}
623    void operator()() const override {}
624    // The function pointer/reference
625    T func_;
626  };
627
628  std::unique_ptr<HolderBase> holder_ = nullptr;
629};
630
631// ~~~~ End Popen Args ~~~~
632
633
634/*!
635 * class: Buffer
636 * This class is a very thin wrapper around std::vector<char>
637 * This is basically used to determine the length of the actual
638 * data stored inside the dynamically resized vector.
639 *
640 * This is what is returned as the output to communicate and check_output
641 * functions, so, users must know about this class.
642 *
643 * OutBuffer and ErrBuffer are just different typedefs to this class.
644 */
645class Buffer
646{
647public:
648  Buffer() {}
649  Buffer(size_t cap) { buf.resize(cap); }
650  void add_cap(size_t cap) { buf.resize(cap); }
651
652#if 0
653  Buffer(const Buffer& other):
654    buf(other.buf),
655    length(other.length)
656  {
657    std::cout << "COPY" << std::endl;
658  }
659
660  Buffer(Buffer&& other):
661    buf(std::move(other.buf)),
662    length(other.length)
663  {
664    std::cout << "MOVE" << std::endl;
665  }
666#endif
667
668public:
669  std::vector<char> buf;
670  size_t length = 0;
671};
672
673// Buffer for storing output written to output fd
674using OutBuffer = Buffer;
675// Buffer for storing output written to error fd
676using ErrBuffer = Buffer;
677
678
679// Fwd Decl.
680class Popen;
681
682/*---------------------------------------------------
683 *      DETAIL NAMESPACE
684 *---------------------------------------------------
685 */
686
687namespace detail {
688
689// Metaprogram for searching a type within
690// a variadic parameter pack
691// This is particularly required to do a compile time
692// checking of the arguments provided to 'check_ouput' function
693// wherein the user is not expected to provide an 'ouput' option.
694
695template <typename... T> struct param_pack{};
696
697template <typename F, typename T> struct has_type;
698
699template <typename F>
700struct has_type<F, param_pack<>> {
701  static constexpr bool value = false;
702};
703
704template <typename F, typename... T>
705struct has_type<F, param_pack<F, T...>> {
706  static constexpr bool value = true;
707};
708
709template <typename F, typename H, typename... T>
710struct has_type<F, param_pack<H,T...>> {
711  static constexpr bool value =
712    std::is_same<F, typename std::decay<H>::type>::value ? true : has_type<F, param_pack<T...>>::value;
713};
714
715//----
716
717/*!
718 * A helper class to Popen class for setting
719 * options as provided in the Popen constructor
720 * or in check_ouput arguments.
721 * This design allows us to _not_ have any fixed position
722 * to any arguments and specify them in a way similar to what
723 * can be done in python.
724 */
725struct ArgumentDeducer
726{
727  ArgumentDeducer(Popen* p): popen_(p) {}
728
729  void set_option(executable&& exe);
730  void set_option(cwd&& cwdir);
731  void set_option(bufsize&& bsiz);
732  void set_option(environment&& env);
733  void set_option(defer_spawn&& defer);
734  void set_option(shell&& sh);
735  void set_option(input&& inp);
736  void set_option(output&& out);
737  void set_option(error&& err);
738  void set_option(close_fds&& cfds);
739  void set_option(preexec_func&& prefunc);
740  void set_option(session_leader&& sleader);
741
742private:
743  Popen* popen_ = nullptr;
744};
745
746/*!
747 * A helper class to Popen.
748 * This takes care of all the fork-exec logic
749 * in the execute_child API.
750 */
751class Child
752{
753public:
754  Child(Popen* p, int err_wr_pipe):
755    parent_(p),
756    err_wr_pipe_(err_wr_pipe)
757  {}
758
759  void execute_child();
760
761private:
762  // Lets call it parent even though
763  // technically a bit incorrect
764  Popen* parent_ = nullptr;
765  int err_wr_pipe_ = -1;
766};
767
768// Fwd Decl.
769class Streams;
770
771/*!
772 * A helper class to Streams.
773 * This takes care of management of communicating
774 * with the child process with the means of the correct
775 * file descriptor.
776 */
777class Communication
778{
779public:
780  Communication(Streams* stream): stream_(stream)
781  {}
782  void operator=(const Communication&) = delete;
783public:
784  int send(const char* msg, size_t length);
785  int send(const std::vector<char>& msg);
786
787  std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length);
788  std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg)
789  { return communicate(msg.data(), msg.size()); }
790
791  void set_out_buf_cap(size_t cap) { out_buf_cap_ = cap; }
792  void set_err_buf_cap(size_t cap) { err_buf_cap_ = cap; }
793
794private:
795  std::pair<OutBuffer, ErrBuffer> communicate_threaded(
796      const char* msg, size_t length);
797
798private:
799  Streams* stream_;
800  size_t out_buf_cap_ = DEFAULT_BUF_CAP_BYTES;
801  size_t err_buf_cap_ = DEFAULT_BUF_CAP_BYTES;
802};
803
804
805
806/*!
807 * This is a helper class to Popen.
808 * It takes care of management of all the file descriptors
809 * and file pointers.
810 * It dispatches of the communication aspects to the
811 * Communication class.
812 * Read through the data members to understand about the
813 * various file descriptors used.
814 */
815class Streams
816{
817public:
818  Streams():comm_(this) {}
819  void operator=(const Streams&) = delete;
820
821public:
822  void setup_comm_channels();
823
824  void cleanup_fds()
825  {
826    if (write_to_child_ != -1 && read_from_parent_ != -1) {
827      close(write_to_child_);
828    }
829    if (write_to_parent_ != -1 && read_from_child_ != -1) {
830      close(read_from_child_);
831    }
832    if (err_write_ != -1 && err_read_ != -1) {
833      close(err_read_);
834    }
835  }
836
837  void close_parent_fds()
838  {
839    if (write_to_child_ != -1)  close(write_to_child_);
840    if (read_from_child_ != -1) close(read_from_child_);
841    if (err_read_ != -1)        close(err_read_);
842  }
843
844  void close_child_fds()
845  {
846    if (write_to_parent_ != -1)  close(write_to_parent_);
847    if (read_from_parent_ != -1) close(read_from_parent_);
848    if (err_write_ != -1)        close(err_write_);
849  }
850
851  FILE* input()  { return input_.get(); }
852  FILE* output() { return output_.get(); }
853  FILE* error()  { return error_.get(); }
854
855  void input(FILE* fp)  { input_.reset(fp, fclose); }
856  void output(FILE* fp) { output_.reset(fp, fclose); }
857  void error(FILE* fp)  { error_.reset(fp, fclose); }
858
859  void set_out_buf_cap(size_t cap) { comm_.set_out_buf_cap(cap); }
860  void set_err_buf_cap(size_t cap) { comm_.set_err_buf_cap(cap); }
861
862public: /* Communication forwarding API's */
863  int send(const char* msg, size_t length)
864  { return comm_.send(msg, length); }
865
866  int send(const std::vector<char>& msg)
867  { return comm_.send(msg); }
868
869  std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length)
870  { return comm_.communicate(msg, length); }
871
872  std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg)
873  { return comm_.communicate(msg); }
874
875
876public:// Yes they are public
877
878  std::shared_ptr<FILE> input_  = nullptr;
879  std::shared_ptr<FILE> output_ = nullptr;
880  std::shared_ptr<FILE> error_  = nullptr;
881
882  // Buffer size for the IO streams
883  int bufsiz_ = 0;
884
885  // Pipes for communicating with child
886
887  // Emulates stdin
888  int write_to_child_   = -1; // Parent owned descriptor
889  int read_from_parent_ = -1; // Child owned descriptor
890
891  // Emulates stdout
892  int write_to_parent_ = -1; // Child owned descriptor
893  int read_from_child_ = -1; // Parent owned descriptor
894
895  // Emulates stderr
896  int err_write_ = -1; // Write error to parent (Child owned)
897  int err_read_  = -1; // Read error from child (Parent owned)
898
899private:
900  Communication comm_;
901};
902
903}; // end namespace detail
904
905
906
907/*!
908 * class: Popen
909 * This is the single most important class in the whole library
910 * and glues together all the helper classes to provide a common
911 * interface to the client.
912 *
913 * API's provided by the class:
914 * 1. Popen({"cmd"}, output{..}, error{..}, cwd{..}, ....)
915 *    Command provided as a sequence.
916 * 2. Popen("cmd arg1"m output{..}, error{..}, cwd{..}, ....)
917 *    Command provided in a single string.
918 * 3. wait()             - Wait for the child to exit.
919 * 4. retcode()          - The return code of the exited child.
920 * 5. pid()              - PID of the spawned child.
921 * 6. poll()             - Check the status of the running child.
922 * 7. kill(sig_num)      - Kill the child. SIGTERM used by default.
923 * 8. send(...)          - Send input to the input channel of the child.
924 * 9. communicate(...)   - Get the output/error from the child and close the channels
925 *                         from the parent side.
926 *10. input()            - Get the input channel/File pointer. Can be used for
927 *                         cutomizing the way of sending input to child.
928 *11. output()           - Get the output channel/File pointer. Usually used
929                           in case of redirection. See piping examples.
930 *12. error()            - Get the error channel/File poiner. Usually used
931                           in case of redirection.
932 *13. start_process()    - Start the child process. Only to be used when
933 *                         `defer_spawn` option was provided in Popen constructor.
934 */
935class Popen
936{
937public:
938  friend struct detail::ArgumentDeducer;
939  friend class detail::Child;
940
941  template <typename... Args>
942  Popen(const std::string& cmd_args, Args&& ...args):
943    args_(cmd_args)
944  {
945    vargs_ = util::split(cmd_args);
946    init_args(std::forward<Args>(args)...);
947
948    // Setup the communication channels of the Popen class
949    stream_.setup_comm_channels();
950
951    if (!defer_process_start_) execute_process();
952  }
953
954  template <typename... Args>
955  Popen(std::initializer_list<const char*> cmd_args, Args&& ...args)
956  {
957    vargs_.insert(vargs_.end(), cmd_args.begin(), cmd_args.end());
958    init_args(std::forward<Args>(args)...);
959
960    // Setup the communication channels of the Popen class
961    stream_.setup_comm_channels();
962
963    if (!defer_process_start_) execute_process();
964  }
965
966  void start_process() throw (CalledProcessError, OSError);
967
968  int pid() const noexcept { return child_pid_; }
969
970  int retcode() const noexcept { return retcode_; }
971
972  int wait() throw(OSError);
973
974  int poll() throw(OSError);
975
976  // Does not fail, Caller is expected to recheck the
977  // status with a call to poll()
978  void kill(int sig_num = 9);
979
980  void set_out_buf_cap(size_t cap) { stream_.set_out_buf_cap(cap); }
981
982  void set_err_buf_cap(size_t cap) { stream_.set_err_buf_cap(cap); }
983
984  int send(const char* msg, size_t length)
985  { return stream_.send(msg, length); }
986
987  int send(const std::vector<char>& msg)
988  { return stream_.send(msg); }
989
990  std::pair<OutBuffer, ErrBuffer> communicate(const char* msg, size_t length)
991  {
992    auto res = stream_.communicate(msg, length);
993    retcode_ = wait();
994    return res;
995  }
996
997  std::pair<OutBuffer, ErrBuffer> communicate(const std::vector<char>& msg)
998  {
999    auto res = stream_.communicate(msg);
1000    retcode_ = wait();
1001    return res;
1002  }
1003
1004  std::pair<OutBuffer, ErrBuffer> communicate()
1005  {
1006    return communicate(nullptr, 0);
1007  }
1008
1009  FILE* input()  { return stream_.input(); }
1010  FILE* output() { return stream_.output();}
1011  FILE* error()  { return stream_.error(); }
1012
1013private:
1014  template <typename F, typename... Args>
1015  void init_args(F&& farg, Args&&... args);
1016  void init_args();
1017  void populate_c_argv();
1018  void execute_process() throw (CalledProcessError, OSError);
1019
1020private:
1021  detail::Streams stream_;
1022
1023  bool defer_process_start_ = false;
1024  bool close_fds_ = false;
1025  bool has_preexec_fn_ = false;
1026  bool shell_ = false;
1027  bool session_leader_ = false;
1028
1029  std::string exe_name_;
1030  std::string cwd_;
1031  std::map<std::string, std::string> env_;
1032  preexec_func preexec_fn_;
1033
1034  // Command in string format
1035  std::string args_;
1036  // Comamnd provided as sequence
1037  std::vector<std::string> vargs_;
1038  std::vector<char*> cargv_;
1039
1040  bool child_created_ = false;
1041  // Pid of the child process
1042  int child_pid_ = -1;
1043
1044  int retcode_ = -1;
1045};
1046
1047inline void Popen::init_args() {
1048  populate_c_argv();
1049}
1050
1051template <typename F, typename... Args>
1052inline void Popen::init_args(F&& farg, Args&&... args)
1053{
1054  detail::ArgumentDeducer argd(this);
1055  argd.set_option(std::forward<F>(farg));
1056  init_args(std::forward<Args>(args)...);
1057}
1058
1059inline void Popen::populate_c_argv()
1060{
1061  cargv_.clear();
1062  cargv_.reserve(vargs_.size() + 1);
1063  for (auto& arg : vargs_) cargv_.push_back(&arg[0]);
1064  cargv_.push_back(nullptr);
1065}
1066
1067inline void Popen::start_process() throw (CalledProcessError, OSError)
1068{
1069  // The process was started/tried to be started
1070  // in the constructor itself.
1071  // For explicitly calling this API to start the
1072  // process, 'defer_spawn' argument must be set to
1073  // true in the constructor.
1074  if (!defer_process_start_) {
1075    assert (0);
1076    return;
1077  }
1078  execute_process();
1079}
1080
1081inline int Popen::wait() throw (OSError)
1082{
1083  int ret, status;
1084  std::tie(ret, status) = util::wait_for_child_exit(pid());
1085  if (ret == -1) {
1086    if (errno != ECHILD) throw OSError("waitpid failed", errno);
1087    return 0;
1088  }
1089  if (WIFEXITED(status)) return WEXITSTATUS(status);
1090  if (WIFSIGNALED(status)) return WTERMSIG(status);
1091  else return 255;
1092
1093  return 0;
1094}
1095
1096inline int Popen::poll() throw (OSError)
1097{
1098  int status;
1099  if (!child_created_) return -1; // TODO: ??
1100
1101  // Returns zero if child is still running
1102  int ret = waitpid(child_pid_, &status, WNOHANG);
1103  if (ret == 0) return -1;
1104
1105  if (ret == child_pid_) {
1106    if (WIFSIGNALED(status)) {
1107      retcode_ = WTERMSIG(status);
1108    } else if (WIFEXITED(status)) {
1109      retcode_ = WEXITSTATUS(status);
1110    } else {
1111      retcode_ = 255;
1112    }
1113    return retcode_;
1114  }
1115
1116  if (ret == -1) {
1117    // From subprocess.py
1118    // This happens if SIGCHLD is set to be ignored
1119    // or waiting for child process has otherwise been disabled
1120    // for our process. This child is dead, we cannot get the
1121    // status.
1122    if (errno == ECHILD) retcode_ = 0;
1123    else throw OSError("waitpid failed", errno);
1124  } else {
1125    retcode_ = ret;
1126  }
1127
1128  return retcode_;
1129}
1130
1131inline void Popen::kill(int sig_num)
1132{
1133  if (session_leader_) killpg(child_pid_, sig_num);
1134  else ::kill(child_pid_, sig_num);
1135}
1136
1137
1138inline void Popen::execute_process() throw (CalledProcessError, OSError)
1139{
1140  int err_rd_pipe, err_wr_pipe;
1141  std::tie(err_rd_pipe, err_wr_pipe) = util::pipe_cloexec();
1142
1143  if (shell_) {
1144    auto new_cmd = util::join(vargs_);
1145    vargs_.clear();
1146    vargs_.insert(vargs_.begin(), {"/bin/sh", "-c"});
1147    vargs_.push_back(new_cmd);
1148    populate_c_argv();
1149  }
1150
1151  if (exe_name_.length()) {
1152    vargs_.insert(vargs_.begin(), exe_name_);
1153    populate_c_argv();
1154  }
1155  exe_name_ = vargs_[0];
1156
1157  child_pid_ = fork();
1158
1159  if (child_pid_ < 0) {
1160    close(err_rd_pipe);
1161    close(err_wr_pipe);
1162    throw OSError("fork failed", errno);
1163  }
1164
1165  child_created_ = true;
1166
1167  if (child_pid_ == 0)
1168  {
1169    // Close descriptors belonging to parent
1170    stream_.close_parent_fds();
1171
1172    //Close the read end of the error pipe
1173    close(err_rd_pipe);
1174
1175    detail::Child chld(this, err_wr_pipe);
1176    chld.execute_child();
1177  }
1178  else
1179  {
1180    close (err_wr_pipe);// close child side of pipe, else get stuck in read below
1181
1182    stream_.close_child_fds();
1183
1184    try {
1185      char err_buf[SP_MAX_ERR_BUF_SIZ] = {0,};
1186
1187      int read_bytes = util::read_atmost_n(
1188                                  err_rd_pipe,
1189                                  err_buf,
1190                                  SP_MAX_ERR_BUF_SIZ);
1191      close(err_rd_pipe);
1192
1193      if (read_bytes || strlen(err_buf)) {
1194        // Call waitpid to reap the child process
1195        // waitpid suspends the calling process until the
1196        // child terminates.
1197        wait();
1198
1199        // Throw whatever information we have about child failure
1200        throw CalledProcessError(err_buf);
1201      }
1202    } catch (std::exception& exp) {
1203      stream_.cleanup_fds();
1204      throw exp;
1205    }
1206
1207  }
1208}
1209
1210namespace detail {
1211
1212  inline void ArgumentDeducer::set_option(executable&& exe) {
1213    popen_->exe_name_ = std::move(exe.arg_value);
1214  }
1215
1216  inline void ArgumentDeducer::set_option(cwd&& cwdir) {
1217    popen_->cwd_ = std::move(cwdir.arg_value);
1218  }
1219
1220  inline void ArgumentDeducer::set_option(bufsize&& bsiz) {
1221    popen_->stream_.bufsiz_ = bsiz.bufsiz;
1222  }
1223
1224  inline void ArgumentDeducer::set_option(environment&& env) {
1225    popen_->env_ = std::move(env.env_);
1226  }
1227
1228  inline void ArgumentDeducer::set_option(defer_spawn&& defer) {
1229    popen_->defer_process_start_ = defer.defer;
1230  }
1231
1232  inline void ArgumentDeducer::set_option(shell&& sh) {
1233    popen_->shell_ = sh.shell_;
1234  }
1235
1236  inline void ArgumentDeducer::set_option(session_leader&& sleader) {
1237    popen_->session_leader_ = sleader.leader_;
1238  }
1239
1240  inline void ArgumentDeducer::set_option(input&& inp) {
1241    if (inp.rd_ch_ != -1) popen_->stream_.read_from_parent_ = inp.rd_ch_;
1242    if (inp.wr_ch_ != -1) popen_->stream_.write_to_child_ = inp.wr_ch_;
1243  }
1244
1245  inline void ArgumentDeducer::set_option(output&& out) {
1246    if (out.wr_ch_ != -1) popen_->stream_.write_to_parent_ = out.wr_ch_;
1247    if (out.rd_ch_ != -1) popen_->stream_.read_from_child_ = out.rd_ch_;
1248  }
1249
1250  inline void ArgumentDeducer::set_option(error&& err) {
1251    if (err.deferred_) {
1252      if (popen_->stream_.write_to_parent_) {
1253        popen_->stream_.err_write_ = popen_->stream_.write_to_parent_;
1254      } else {
1255        throw std::runtime_error("Set output before redirecting error to output");
1256      }
1257    }
1258    if (err.wr_ch_ != -1) popen_->stream_.err_write_ = err.wr_ch_;
1259    if (err.rd_ch_ != -1) popen_->stream_.err_read_ = err.rd_ch_;
1260  }
1261
1262  inline void ArgumentDeducer::set_option(close_fds&& cfds) {
1263    popen_->close_fds_ = cfds.close_all;
1264  }
1265
1266  inline void ArgumentDeducer::set_option(preexec_func&& prefunc) {
1267    popen_->preexec_fn_ = std::move(prefunc);
1268    popen_->has_preexec_fn_ = true;
1269  }
1270
1271
1272  inline void Child::execute_child() {
1273    int sys_ret = -1;
1274    auto& stream = parent_->stream_;
1275
1276    try {
1277      if (stream.write_to_parent_ == 0)
1278        stream.write_to_parent_ = dup(stream.write_to_parent_);
1279
1280      if (stream.err_write_ == 0 || stream.err_write_ == 1)
1281        stream.err_write_ = dup(stream.err_write_);
1282
1283      // Make the child owned descriptors as the
1284      // stdin, stdout and stderr for the child process
1285      auto _dup2_ = [](int fd, int to_fd) {
1286        if (fd == to_fd) {
1287          // dup2 syscall does not reset the
1288          // CLOEXEC flag if the descriptors
1289          // provided to it are same.
1290          // But, we need to reset the CLOEXEC
1291          // flag as the provided descriptors
1292          // are now going to be the standard
1293          // input, output and error
1294          util::set_clo_on_exec(fd, false);
1295        } else if(fd != -1) {
1296          int res = dup2(fd, to_fd);
1297          if (res == -1) throw OSError("dup2 failed", errno);
1298        }
1299      };
1300
1301      // Create the standard streams
1302      _dup2_(stream.read_from_parent_, 0); // Input stream
1303      _dup2_(stream.write_to_parent_,  1); // Output stream
1304      _dup2_(stream.err_write_,        2); // Error stream
1305
1306      // Close the duped descriptors
1307      if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2)
1308        close(stream.read_from_parent_);
1309
1310      if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2)
1311        close(stream.write_to_parent_);
1312
1313      if (stream.err_write_ != -1 && stream.err_write_ > 2)
1314        close(stream.err_write_);
1315
1316      // Close all the inherited fd's except the error write pipe
1317      if (parent_->close_fds_) {
1318        int max_fd = sysconf(_SC_OPEN_MAX);
1319        if (max_fd == -1) throw OSError("sysconf failed", errno);
1320
1321        for (int i = 3; i < max_fd; i++) {
1322          if (i == err_wr_pipe_) continue;
1323          close(i);
1324        }
1325      }
1326
1327      // Change the working directory if provided
1328      if (parent_->cwd_.length()) {
1329        sys_ret = chdir(parent_->cwd_.c_str());
1330        if (sys_ret == -1) throw OSError("chdir failed", errno);
1331      }
1332
1333      if (parent_->has_preexec_fn_) {
1334        parent_->preexec_fn_();
1335      }
1336
1337      if (parent_->session_leader_) {
1338        sys_ret = setsid();
1339        if (sys_ret == -1) throw OSError("setsid failed", errno);
1340      }
1341
1342      // Replace the current image with the executable
1343      if (parent_->env_.size()) {
1344        for (auto& kv : parent_->env_) {
1345          setenv(kv.first.c_str(), kv.second.c_str(), 1);
1346        }
1347        sys_ret = execvp(parent_->exe_name_.c_str(), parent_->cargv_.data());
1348      } else {
1349        sys_ret = execvp(parent_->exe_name_.c_str(), parent_->cargv_.data());
1350      }
1351
1352      if (sys_ret == -1) throw OSError("execve failed", errno);
1353
1354    } catch (const OSError& exp) {
1355      // Just write the exception message
1356      // TODO: Give back stack trace ?
1357      std::string err_msg(exp.what());
1358      //ATTN: Can we do something on error here ?
1359      util::write_n(err_wr_pipe_, err_msg.c_str(), err_msg.length());
1360      throw exp;
1361    }
1362
1363    // Calling application would not get this
1364    // exit failure
1365    exit (EXIT_FAILURE);
1366  }
1367
1368
1369  inline void Streams::setup_comm_channels()
1370  {
1371    if (write_to_child_ != -1)  input(fdopen(write_to_child_, "wb"));
1372    if (read_from_child_ != -1) output(fdopen(read_from_child_, "rb"));
1373    if (err_read_ != -1)        error(fdopen(err_read_, "rb"));
1374
1375    auto handles = {input(), output(), error()};
1376
1377    for (auto& h : handles) {
1378      if (h == nullptr) continue;
1379      switch (bufsiz_) {
1380      case 0:
1381        setvbuf(h, nullptr, _IONBF, BUFSIZ);
1382        break;
1383      case 1:
1384        setvbuf(h, nullptr, _IONBF, BUFSIZ);
1385        break;
1386      default:
1387        setvbuf(h, nullptr, _IOFBF, bufsiz_);
1388      };
1389    }
1390  }
1391
1392  inline int Communication::send(const char* msg, size_t length)
1393  {
1394    if (stream_->input() == nullptr) return -1;
1395    return std::fwrite(msg, sizeof(char), length, stream_->input());
1396  }
1397
1398  inline int Communication::send(const std::vector<char>& msg)
1399  {
1400    return send(msg.data(), msg.size());
1401  }
1402
1403  inline std::pair<OutBuffer, ErrBuffer>
1404  Communication::communicate(const char* msg, size_t length)
1405  {
1406    // Optimization from subprocess.py
1407    // If we are using one pipe, or no pipe
1408    // at all, using select() or threads is unnecessary.
1409    auto hndls = {stream_->input(), stream_->output(), stream_->error()};
1410    int count = std::count(std::begin(hndls), std::end(hndls), nullptr);
1411    const int len_conv = length;
1412
1413    if (count >= 2) {
1414      OutBuffer obuf;
1415      ErrBuffer ebuf;
1416      if (stream_->input()) {
1417        if (msg) {
1418          int wbytes = std::fwrite(msg, sizeof(char), length, stream_->input());
1419          if (wbytes < len_conv) {
1420            if (errno != EPIPE && errno != EINVAL) {
1421              throw OSError("fwrite error", errno);
1422            }
1423          }
1424        }
1425        // Close the input stream
1426        stream_->input_.reset();
1427      } else if (stream_->output()) {
1428        // Read till EOF
1429        // ATTN: This could be blocking, if the process
1430        // at the other end screws up, we get screwed as well
1431        obuf.add_cap(out_buf_cap_);
1432
1433        int rbytes = util::read_all(
1434                            fileno(stream_->output()),
1435                            obuf.buf);
1436
1437        if (rbytes == -1) {
1438          throw OSError("read to obuf failed", errno);
1439        }
1440
1441        obuf.length = rbytes;
1442        // Close the output stream
1443        stream_->output_.reset();
1444
1445      } else if (stream_->error()) {
1446        // Same screwness applies here as well
1447        ebuf.add_cap(err_buf_cap_);
1448
1449        int rbytes = util::read_atmost_n(
1450                                  fileno(stream_->error()),
1451                                  ebuf.buf.data(),
1452                                  ebuf.buf.size());
1453
1454        if (rbytes == -1) {
1455          throw OSError("read to ebuf failed", errno);
1456        }
1457
1458        ebuf.length = rbytes;
1459        // Close the error stream
1460        stream_->error_.reset();
1461      }
1462      return std::make_pair(std::move(obuf), std::move(ebuf));
1463    }
1464
1465    return communicate_threaded(msg, length);
1466  }
1467
1468
1469  inline std::pair<OutBuffer, ErrBuffer>
1470  Communication::communicate_threaded(const char* msg, size_t length)
1471  {
1472    OutBuffer obuf;
1473    ErrBuffer ebuf;
1474    std::future<int> out_fut, err_fut;
1475    const int length_conv = length;
1476
1477    if (stream_->output()) {
1478      obuf.add_cap(out_buf_cap_);
1479
1480      out_fut = std::async(std::launch::async,
1481                          [&obuf, this] {
1482                            return util::read_all(fileno(this->stream_->output()), obuf.buf);
1483                          });
1484    }
1485    if (stream_->error()) {
1486      ebuf.add_cap(err_buf_cap_);
1487
1488      err_fut = std::async(std::launch::async,
1489                          [&ebuf, this] {
1490                            return util::read_all(fileno(this->stream_->error()), ebuf.buf);
1491                          });
1492    }
1493    if (stream_->input()) {
1494      if (msg) {
1495        int wbytes = std::fwrite(msg, sizeof(char), length, stream_->input());
1496        if (wbytes < length_conv) {
1497          if (errno != EPIPE && errno != EINVAL) {
1498            throw OSError("fwrite error", errno);
1499          }
1500        }
1501      }
1502      stream_->input_.reset();
1503    }
1504
1505    if (out_fut.valid()) {
1506      int res = out_fut.get();
1507      if (res != -1) obuf.length = res;
1508      else obuf.length = 0;
1509    }
1510    if (err_fut.valid()) {
1511      int res = err_fut.get();
1512      if (res != -1) ebuf.length = res;
1513      else ebuf.length = 0;
1514    }
1515
1516    return std::make_pair(std::move(obuf), std::move(ebuf));
1517  }
1518
1519}; // end namespace detail
1520
1521
1522
1523// Convenience Functions
1524//
1525//
1526namespace detail
1527{
1528  template<typename F, typename... Args>
1529  OutBuffer check_output_impl(F& farg, Args&&... args)
1530  {
1531    static_assert(!detail::has_type<output, detail::param_pack<Args...>>::value, "output not allowed in args");
1532    auto p = Popen(std::forward<F>(farg), std::forward<Args>(args)..., output{PIPE});
1533    auto res = p.communicate();
1534    auto retcode = p.poll();
1535    if (retcode > 0) {
1536      throw CalledProcessError("Command failed : Non zero retcode");
1537    }
1538    return std::move(res.first);
1539  }
1540
1541  template<typename F, typename... Args>
1542  int call_impl(F& farg, Args&&... args)
1543  {
1544    return Popen(std::forward<F>(farg), std::forward<Args>(args)...).wait();
1545  }
1546
1547  static inline void pipeline_impl(std::vector<Popen>& cmds)
1548  {
1549    /* EMPTY IMPL */
1550  }
1551
1552  template<typename... Args>
1553  static inline void pipeline_impl(std::vector<Popen>& cmds,
1554                                   const std::string& cmd,
1555                                   Args&&... args)
1556  {
1557    if (cmds.size() == 0) {
1558      cmds.emplace_back(cmd, output{PIPE}, defer_spawn{true});
1559    } else {
1560      cmds.emplace_back(cmd, input{cmds.back().output()}, output{PIPE}, defer_spawn{true});
1561    }
1562
1563    pipeline_impl(cmds, std::forward<Args>(args)...);
1564  }
1565
1566}
1567
1568/*-----------------------------------------------------------
1569 *        CONVIENIENCE FUNCTIONS
1570 *-----------------------------------------------------------
1571 */
1572
1573
1574/*!
1575 * Run the command with arguments and wait for it to complete.
1576 * The parameters passed to the argument are exactly the same
1577 * one would use for Popen constructors.
1578 */
1579template<typename... Args>
1580int call(std::initializer_list<const char*> plist, Args&&... args)
1581{
1582  return (detail::call_impl(plist, std::forward<Args>(args)...));
1583}
1584
1585template<typename... Args>
1586int call(const std::string& arg, Args&&... args)
1587{
1588  return (detail::call_impl(arg, std::forward<Args>(args)...));
1589}
1590
1591
1592/*!
1593 * Run the command with arguments and wait for it to complete.
1594 * If the exit code was non-zero it raises a CalledProcessError.
1595 * The arguments are the same as for the Popen constructor.
1596 */
1597template <typename... Args>
1598OutBuffer check_output(std::initializer_list<const char*> plist, Args&&... args)
1599{
1600  return (detail::check_output_impl(plist, std::forward<Args>(args)...));
1601}
1602
1603template <typename... Args>
1604OutBuffer check_output(const std::string& arg, Args&&... args)
1605{
1606  return (detail::check_output_impl(arg, std::forward<Args>(args)...));
1607}
1608
1609
1610/*!
1611 * An easy way to pipeline easy commands.
1612 * Provide the commands that needs to be pipelined in the order they
1613 * would appear in a regular command.
1614 * It would wait for the last command provided in the pipeline
1615 * to finish and then return the OutBuffer.
1616 */
1617template<typename... Args>
1618// Args expected to be flat commands using string instead of initializer_list
1619OutBuffer pipeline(Args&&... args)
1620{
1621  std::vector<Popen> pcmds;
1622  detail::pipeline_impl(pcmds, std::forward<Args>(args)...);
1623
1624  for (auto& p : pcmds) p.start_process();
1625  return (pcmds.back().communicate().first);
1626}
1627
1628};
1629
1630#endif // SUBPROCESS_HPP
Note: See TracBrowser for help on using the repository browser.