/** @brief runs command and returns it's output as string
* @param command the full command with all parameters
* @param rescode struct containing the return code, if the program exited normally and so on
+ * @param out Whether to collect \c stdout.
+ * @param err Whether to collect \c stderr; combines with \c out.
+ * @param path Wether to look up the executable in \c $PATH.
* @returns the output (stdout) of the called program
*/
template <typename CmdT>
std::string capture_exec(CmdT command, ExecResult &rescode,
- const bool out, const bool err)
+ const bool out, const bool err,
+ const bool path)
{
std::string output;
try
{
{
- inpipestream ips(command, out, err);
+ inpipestream ips(command, out, err, path);
ips.store_exit_status(&exit_set, &exit_status_waitpid);
* passed.
*/
std::string capture_exec (const std::string &command, ExecResult &res)
-{ return capture_exec<const std::string &>(command, res, true, false); }
+{ return capture_exec<const std::string &>(command, res, true, false, false); }
/** @brief Instantiation of \c capture_exec for argument lists. The
* pipestream used to run the command will not shell out.
* state in this struct.
* @param out Whether to collect \c stdout.
* @param err Whether to collect \c stderr; combines with \c out.
+ * @param path Wether to look up the executable in \c $PATH.
*
* @returns Captured output, combined into one string.
*/
std::string capture_exec (const char *const *command, ExecResult &res,
- const bool out, const bool err)
-{ return capture_exec<const char *const *>(command, res, out, err); }
+ const bool out, const bool err, const bool path)
+{ return capture_exec<const char *const *>(command, res, out, err, path); }
/** @brief Instantiation of \c capture_exec for argument lists. The
* pipestream used to run the command will not shell out.
* state in this struct.
* @param out Whether to collect \c stdout.
* @param err Whether to collect \c stderr; combines with \c out.
+ * @param path Wether to look up the executable in \c $PATH.
*
* @returns Captured output, combined into one string.
*/
std::string capture_exec (const std::vector<std::string> &command, ExecResult &res,
- const bool out, const bool err)
+ const bool out, const bool err, const bool path)
{
return capture_exec<const std::vector<std::string> &>
- (command, res, out, err);
+ (command, res, out, err, path);
}
#define PIPE_CTOR_FAIL(where) \
return boost::shared_array<char *> (ret);
}
-
/** @brief Helper aggregating common code for the shell-free ctors.
*
* @param argv Argument list prepared for \c execve(2).
std::pair <pid_t, FILE *>
inpipebuf::init_without_shell (const char *const *argv,
const bool out,
- const bool err) const
+ const bool err,
+ const bool path) const
{
FILE *pipeobj = NULL;
int pipefd [2];
if (!out) {
close (STDOUT_FILENO);
} else if (dup2 (pipefd[1], STDOUT_FILENO) == -1) {
- PIPE_CTOR_FAIL("dup2/stdout");
+ fprintf(stderr, "dup2/stdout: %m\n");
+ exit(EXIT_FAILURE);
}
if (!err) {
close (STDERR_FILENO);
} else if (dup2 (pipefd[1], STDERR_FILENO) == -1) {
- PIPE_CTOR_FAIL("dup2/stderr");
+ fprintf(stderr, "dup2/stderr: %m\n");
+ exit(EXIT_FAILURE);
}
close (pipefd [1]);
errno = 0;
- if (execve (argv [0], const_cast <char *const *>(argv), NULL) == -1) {
- PIPE_CTOR_FAIL("exec");
+ if (path) {
+ execvpe (argv [0], const_cast <char *const *>(argv), environ);
+ } else {
+ execve (argv [0], const_cast <char *const *>(argv), NULL);
}
+ exit(EXIT_FAILURE);
break;
}
default: {
inpipebuf::inpipebuf(const char *const *command,
const bool out,
- const bool err)
+ const bool err,
+ const bool path)
: pipe (NULL) /* brr: shadowing global ident */
, pid (-1)
, status_set (NULL)
PIPE_CTOR_FAIL("command");
}
- std::pair <pid_t, FILE *> tmp = this->init_without_shell (command, out, err);
+ std::pair <pid_t, FILE *> tmp =
+ this->init_without_shell (command, out, err, path);
this->pid = tmp.first; /* no std::tie :/ */
this->pipe = tmp.second;
inpipebuf::inpipebuf(const std::vector<std::string> &command,
const bool out,
- const bool err)
+ const bool err,
+ const bool path)
: pipe (NULL) /* brr: shadowing global ident */
, pid (-1)
, status_set (NULL)
PIPE_CTOR_FAIL("malloc");
}
- std::pair <pid_t, FILE *> tmp = this->init_without_shell (argv.get (), out, err);
+ std::pair <pid_t, FILE *> tmp =
+ this->init_without_shell (argv.get (), out, err, path);
this->pid = tmp.first;
this->pipe = tmp.second;
inpipebuf::inpipebuf(const std::string& command,
const bool _ignored_out,
- const bool _ignored_err)
+ const bool _ignored_err,
+ const bool _ignored_path)
: pid (-1)
, status_set (NULL)
, exit_status (NULL)
#include <stdio.h>
+#include <cstring>
#include <string>
#include <streambuf>
#include <istream>
std::string capture_exec(const std::string& command, ExecResult &rescode);
std::string capture_exec(const char *const *command, ExecResult &rescode,
- const bool out=true, const bool err=false);
+ const bool out=true, const bool err=false,
+ const bool path=false);
std::string capture_exec(const std::vector<std::string>& command, ExecResult &rescode,
- const bool out=true, const bool err=false);
+ const bool out=true, const bool err=false,
+ const bool path=false);
inline std::string capture_exec (const std::string &command)
{
public:
inpipebuf(const std::string& command,
- const bool out, const bool err);
+ const bool out, const bool err, const bool path);
inpipebuf(const char *const *command,
- const bool out, const bool err);
+ const bool out, const bool err, const bool path);
inpipebuf(const std::vector<std::string> &command,
- const bool out, const bool err);
+ const bool out, const bool err, const bool path);
~inpipebuf();
private:
std::pair <pid_t, FILE *>
init_without_shell (const char *const *argv,
- const bool out, const bool err) const;
+ const bool out, const bool err,
+ const bool path) const;
};
/** @brief stream around inpipebuf -- see comment there */
public:
inpipestream(const std::string& command,
- const bool out=true, const bool err=false)
- : std::istream(&buf), buf(command, out, err)
+ const bool out=true, const bool err=false,
+ const bool path=false)
+ : std::istream(&buf), buf(command, out, err, path)
{}
inpipestream(const char *const command[],
- const bool out=true, const bool err=false)
- : std::istream(&buf), buf(command, out, err)
+ const bool out=true, const bool err=false,
+ const bool path=false)
+ : std::istream(&buf), buf(command, out, err, path)
{}
inpipestream(const std::vector<std::string> &command,
- const bool out=true, const bool err=false)
- : std::istream(&buf), buf(command, out, err)
+ const bool out=true, const bool err=false,
+ const bool path=false)
+ : std::istream(&buf), buf(command, out, err, path)
{}
void store_exit_status(bool *_status_set, int *_exit_status)
BOOST_AUTO_TEST_CASE(abspath_zeros_shell_ok_result)
{
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result =
capture_exec (I2n::join_string (zero_bytes_argv, " "),
exres);
BOOST_AUTO_TEST_CASE(abspath_zeros_noshell_ok_result)
{
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result = capture_exec (zero_bytes_argv, exres);
BOOST_CHECK(exres.normal_exit);
{
assert (access(bad_command [0], X_OK) != 0);
- ExecResult exres;
+ ExecResult exres = ExecResult ();
+ /*
+ * Note that the next line will make the unit test spew a message
+ * to stderr which cannot be prevented due to the limitations of
+ * popen(3).
+ */
const std::string result =
capture_exec (I2n::join_string (bad_command, " "));
{
assert (access(bad_command [0], X_OK) != 0);
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result = capture_exec (bad_command, exres);
BOOST_CHECK(!exres.terminated_by_signal);
{
assert (access(bad_command [0], X_OK) != 0);
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result = capture_exec (bad_command, exres, false, true);
- BOOST_CHECK_NE(result.size (), 0);
+ BOOST_CHECK(!exres.terminated_by_signal);
+ BOOST_CHECK_EQUAL(result.size (), 0);
}
- const char *const false_argv [] = { "/bin/false", NULL };
+ const char *const false_argv_abs [] = { "/bin/false", NULL };
+ const char *const true_argv_abs [] = { "/bin/true" , NULL };
+ const char *const false_argv_rel [] = { "false" , NULL };
+ const char *const true_argv_rel [] = { "true" , NULL };
BOOST_AUTO_TEST_CASE(abspath_false_noshell_fail_exit)
{
- ExecResult exres;
- const std::string result = capture_exec (false_argv, exres, true, false);
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (false_argv_abs, exres, true, false, false);
BOOST_CHECK(exres.normal_exit);
BOOST_CHECK_EQUAL(exres.return_code, EXIT_FAILURE);
BOOST_AUTO_TEST_CASE(abspath_false_shell_fail_exit)
{
- ExecResult exres;
+ ExecResult exres = ExecResult ();
const std::string result =
- capture_exec (std::string (false_argv [0]), exres);
+ capture_exec (std::string (false_argv_abs [0]), exres);
BOOST_CHECK(exres.normal_exit);
BOOST_CHECK_EQUAL(exres.return_code, EXIT_FAILURE);
BOOST_CHECK_EQUAL(result.size (), 0);
}
+ BOOST_AUTO_TEST_CASE(relpath_true_noshell_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (true_argv_rel, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+
+ BOOST_AUTO_TEST_CASE(relpath_true_noshell_fail)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (true_argv_rel, exres, true, false, false);
+
+ BOOST_CHECK(exres.normal_exit);
+ /* no return code check since we couln't exit */
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+
+ BOOST_AUTO_TEST_CASE(abspath_true_noshell_ok)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (true_argv_abs, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ BOOST_CHECK_EQUAL(exres.return_code, EXIT_SUCCESS);
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+
+ BOOST_AUTO_TEST_CASE(relpath_false_noshell_fail)
+ {
+ ExecResult exres = ExecResult ();
+ const std::string result =
+ capture_exec (false_argv_rel, exres, true, false, true);
+
+ BOOST_CHECK(exres.normal_exit);
+ /* no return code check since we couln't exit */
+ BOOST_CHECK_EQUAL(result.size (), 0);
+ }
+
BOOST_AUTO_TEST_SUITE_END() /* [pipestream->read] */
BOOST_AUTO_TEST_SUITE_END() /* [pipestream] */