* @returns A \c FILE* handle for streaming if successful, \c NULL
* otherwise.
*/
-FILE *
+std::pair <pid_t, FILE *>
inpipebuf::init_without_shell (const char *const *argv,
const bool out,
const bool err) const
PIPE_CTOR_FAIL("dup2/stderr");
}
+ close (pipefd [1]);
+
errno = 0;
if (execve (argv [0], const_cast <char *const *>(argv), NULL) == -1) {
PIPE_CTOR_FAIL("exec");
}
}
- return pipeobj;
+ return std::make_pair (childpid, pipeobj);
}
inpipebuf::inpipebuf(const char *const *command,
const bool out,
const bool err)
: pipe (NULL) /* brr: shadowing global ident */
+ , pid (-1)
, status_set (NULL)
, exit_status (NULL)
{
PIPE_CTOR_FAIL("command");
}
- this->pipe = this->init_without_shell (command, out, err);
+ std::pair <pid_t, FILE *> tmp = this->init_without_shell (command, out, err);
+ this->pid = tmp.first; /* no std::tie :/ */
+ this->pipe = tmp.second;
setg (&buffer, &buffer, &buffer);
}
const bool out,
const bool err)
: pipe (NULL) /* brr: shadowing global ident */
+ , pid (-1)
, status_set (NULL)
, exit_status (NULL)
{
PIPE_CTOR_FAIL("malloc");
}
- this->pipe = this->init_without_shell (argv.get (), out, err);
+ std::pair <pid_t, FILE *> tmp = this->init_without_shell (argv.get (), out, err);
+ this->pid = tmp.first;
+ this->pipe = tmp.second;
setg (&buffer, &buffer, &buffer);
}
inpipebuf::inpipebuf(const std::string& command,
const bool _ignored_out,
const bool _ignored_err)
+ : pid (-1)
+ , status_set (NULL)
+ , exit_status (NULL)
{
- status_set = NULL;
- exit_status = NULL;
-
pipe = popen (command.c_str(), "r");
if (pipe == NULL)
throw EXCEPTION (pipestream_error, "can't open program or permission denied");
inpipebuf::~inpipebuf()
{
if (pipe != NULL) {
- int pclose_exit = pclose (pipe);
+ int status;
- if (exit_status && pclose_exit != -1)
+ if (this->pid == -1)
{
- if (status_set)
- *status_set = true;
- *exit_status = pclose_exit;
+ errno = 0;
+ status = pclose (pipe);
+ if (status != -1) {
+ if (exit_status != NULL) {
+ *exit_status = status;
+ if (status_set != NULL) {
+ *status_set = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ errno = 0;
+ status = fclose (pipe);
+ if (status != EOF) {
+ if (exit_status != NULL) {
+ *exit_status = status; /* might be overwritten below */
+ if (status_set != NULL) {
+ *status_set = true;
+ }
+ }
+ }
+
+ errno = 0;
+ while (waitpid (this->pid, &status, 0) == -1) {
+ if (errno != EINTR) {
+ status = -1;
+ break;
+ }
+ }
+ if (status != 0 && exit_status != NULL) {
+ *exit_status = status; /* might overwrite pipe status above */
+ if (status_set != NULL) {
+ *status_set = true;
+ }
+ }
}
pipe = NULL;
char buffer;
FILE *pipe;
+ pid_t pid;
// "callback" variables for destructor to store exit status
bool *status_set;
virtual int_type underflow();
private:
- FILE *init_without_shell (const char *const *argv,
- const bool out, const bool err) const;
+ std::pair <pid_t, FILE *>
+ init_without_shell (const char *const *argv,
+ const bool out, const bool err) const;
};
/** @brief stream around inpipebuf -- see comment there */