2015-11-03 21:20:15 +01:00
|
|
|
#include "subprocess.h"
|
|
|
|
#include <cstdio>
|
|
|
|
#include <stdexcept>
|
2018-05-20 21:25:51 +02:00
|
|
|
#include <cerrno>
|
2018-05-19 16:45:56 +02:00
|
|
|
|
2018-05-20 22:51:12 +02:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
constexpr const char* openmode = "r";
|
|
|
|
|
|
|
|
#elif !defined(_MSC_VER)
|
|
|
|
|
2015-11-28 17:06:54 +01:00
|
|
|
#include <sys/wait.h>
|
2018-05-19 16:45:56 +02:00
|
|
|
constexpr const char* openmode = "re";
|
2018-05-20 22:51:12 +02:00
|
|
|
|
2018-05-19 16:45:56 +02:00
|
|
|
#else
|
2018-05-20 22:51:12 +02:00
|
|
|
|
2018-05-19 16:45:56 +02:00
|
|
|
#define popen _popen
|
|
|
|
#define pclose _pclose
|
|
|
|
#define WEXITSTATUS(a) a
|
2018-05-21 07:22:14 +02:00
|
|
|
#define WIFEXITED(a) true
|
2018-05-19 16:45:56 +02:00
|
|
|
constexpr const char* openmode = "r";
|
2018-05-20 22:51:12 +02:00
|
|
|
|
2018-05-19 16:45:56 +02:00
|
|
|
#endif
|
2015-11-03 21:20:15 +01:00
|
|
|
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
namespace cpputils {
|
2018-05-20 09:14:17 +02:00
|
|
|
namespace {
|
2018-05-21 07:28:28 +02:00
|
|
|
class SubprocessHandle final {
|
|
|
|
public:
|
|
|
|
SubprocessHandle(const string &command)
|
|
|
|
: _subprocess(popen(command.c_str(), openmode)) {
|
|
|
|
if (!_subprocess) {
|
|
|
|
throw std::runtime_error("Error starting subprocess " + command + ". Errno: " + std::to_string(errno));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~SubprocessHandle() {
|
|
|
|
if (_subprocess != nullptr) {
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string getOutput() {
|
|
|
|
string output;
|
|
|
|
char buffer[1024];
|
|
|
|
while (fgets(buffer, sizeof(buffer), _subprocess) != nullptr) {
|
|
|
|
output += buffer;
|
|
|
|
}
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
int close() {
|
|
|
|
auto returncode = pclose(_subprocess);
|
|
|
|
_subprocess = nullptr;
|
|
|
|
if (returncode == -1) {
|
|
|
|
throw std::runtime_error("Error calling pclose. Errno: " + std::to_string(errno));
|
|
|
|
}
|
2018-10-03 05:51:33 +02:00
|
|
|
#pragma GCC diagnostic push // WIFEXITSTATUS / WEXITSTATUS use old style casts
|
|
|
|
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
2018-05-21 07:28:28 +02:00
|
|
|
if (!WIFEXITED(returncode)) {
|
|
|
|
// WEXITSTATUS is only valid if WIFEXITED is 0.
|
|
|
|
throw std::runtime_error("WIFEXITED returned " + std::to_string(WIFEXITED(returncode)));
|
|
|
|
}
|
|
|
|
return WEXITSTATUS(returncode);
|
2018-10-03 05:51:33 +02:00
|
|
|
#pragma GCC diagnostic pop
|
2018-05-21 07:28:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
FILE *_subprocess;
|
|
|
|
};
|
2015-11-03 21:20:15 +01:00
|
|
|
|
|
|
|
}
|
2015-11-03 22:11:09 +01:00
|
|
|
|
2018-05-20 09:14:17 +02:00
|
|
|
SubprocessResult Subprocess::call(const string &command) {
|
2018-05-21 07:28:28 +02:00
|
|
|
SubprocessHandle subprocess(command);
|
|
|
|
string output = subprocess.getOutput();
|
|
|
|
int exitcode = subprocess.close();
|
2015-11-03 22:11:09 +01:00
|
|
|
|
2018-05-20 09:14:17 +02:00
|
|
|
return SubprocessResult {output, exitcode};
|
2015-11-03 22:11:09 +01:00
|
|
|
}
|
|
|
|
|
2018-05-20 09:14:17 +02:00
|
|
|
SubprocessResult Subprocess::check_call(const string &command) {
|
|
|
|
auto result = call(command);
|
|
|
|
if(result.exitcode != 0) {
|
|
|
|
throw SubprocessError("Subprocess \""+command+"\" exited with code "+std::to_string(result.exitcode));
|
2015-11-03 22:11:09 +01:00
|
|
|
}
|
2018-05-20 09:14:17 +02:00
|
|
|
return result;
|
2015-11-03 22:11:09 +01:00
|
|
|
}
|
2018-05-20 09:14:17 +02:00
|
|
|
|
2015-11-07 09:11:12 +01:00
|
|
|
}
|