#include // errno, EAGAIN, EINTR #include // size_t #include // perror #include // exit, WEXITSTATUS #include // strcpy, strtok #include // function #include #include #include // waitpid #include // close, dup2, execvp, fork, pipe, read #include #include "util/system.h" namespace Util { System::System() { } System::System(const std::vector& arguments) : m_arguments(arguments) { } System System::operator()() { return exec(); } System System::operator()(const char* command) { return operator()(std::string { command }); } System System::operator()(std::string command) { std::vector arguments; size_t index = 0; while (index != std::string::npos) { index = command.find_first_of(" "); arguments.push_back(command.substr(0, index)); command = command.substr(index + 1); } return { arguments }; } System System::operator()(std::string_view command) { return operator()(std::string { command }); } System System::operator()(const std::vector& arguments) { std::vector stringArguments(arguments.size(), ""); for (size_t i = 0; i < arguments.size(); ++i) { stringArguments[i] = arguments[i]; } return { stringArguments }; } System System::operator()(const std::vector& arguments) { return { arguments }; } System System::operator()(const std::vector& arguments) { std::vector stringArguments(arguments.size(), ""); for (size_t i = 0; i < arguments.size(); ++i) { stringArguments[i] = arguments[i]; } return { stringArguments }; } // Shell equivalent ; System System::operator+(System rhs) { auto lhs = *this; lhs.exec(); rhs.m_output.append(lhs.m_output); rhs.m_error.append(lhs.m_error); rhs.exec(); return rhs; } System System::operator|(System rhs) { auto lhs = *this; lhs.exec(); rhs.exec(lhs.m_output); return rhs; } System System::operator||(System rhs) { auto lhs = *this; lhs.exec(); if (lhs.m_status == 0) { return lhs; } rhs.m_output.append(lhs.m_output); rhs.m_error.append(lhs.m_error); rhs.exec(); return rhs; } System System::operator&&(System rhs) { auto lhs = *this; lhs.exec(); if (lhs.m_status > 0) { return lhs; } rhs.m_output.append(lhs.m_output); rhs.m_error.append(lhs.m_error); rhs.exec(); return rhs; } void System::print(const std::vector& arguments) { if (!arguments.size()) { return; } printf("----------\n"); printf("size: %zu\n", arguments.size()); printf("command: "); for (size_t i = 0; i < arguments.size(); ++i) { printf("%s ", arguments.at(i).c_str()); } printf("\n"); printf("----------\n"); } // ----------------------------------------- System System::exec(std::string input) { if (m_arguments.empty()) { return *this; } int stdinFd[2]; int stdoutFd[2]; int stderrFd[2]; if (pipe(stdinFd) < 0) { perror("\033[31;1mError:\033[0m pipe"); } if (pipe(stdoutFd) < 0) { perror("\033[31;1mError:\033[0m pipe"); } if (pipe(stderrFd) < 0) { perror("\033[31;1mError:\033[0m pipe"); } pid_t pid = fork(); switch (pid) { // Failed case -1: perror("\033[31;1mError:\033[0m fork"); break; // Child case 0: { close(stdinFd[WriteFileDescriptor]); dup2(stdinFd[ReadFileDescriptor], fileno(stdin)); close(stdinFd[ReadFileDescriptor]); close(stdoutFd[ReadFileDescriptor]); dup2(stdoutFd[WriteFileDescriptor], fileno(stdout)); close(stdoutFd[WriteFileDescriptor]); close(stderrFd[ReadFileDescriptor]); dup2(stderrFd[WriteFileDescriptor], fileno(stderr)); close(stderrFd[WriteFileDescriptor]); std::vector charArguments(m_arguments.size() + 1, 0); for (size_t i = 0; i < m_arguments.size(); ++i) { charArguments[i] = const_cast(m_arguments[i].c_str()); } execvp(charArguments[0], &charArguments[0]); exit(0); } // Parent default: m_arguments.clear(); break; } close(stdinFd[ReadFileDescriptor]); if (!input.empty()) { write(stdinFd[WriteFileDescriptor], input.c_str(), input.size()); } close(stdinFd[WriteFileDescriptor]); readFromFileDescriptor(stdoutFd, m_output); readFromFileDescriptor(stderrFd, m_error); int result; do { result = waitpid(pid, &m_status, 0); } while (result == -1 && errno == EINTR); m_status = WEXITSTATUS(m_status); return *this; } void System::readFromFileDescriptor(int fileDescriptor[2], std::string& output) { close(fileDescriptor[WriteFileDescriptor]); constexpr int bufferSize = 4096; char buffer[bufferSize]; do { const ssize_t result = read(fileDescriptor[ReadFileDescriptor], buffer, bufferSize); // FIXME: also handle failure cases if (result > 0) { output.append(buffer, result); } } while (errno == EAGAIN || errno == EINTR); close(fileDescriptor[ReadFileDescriptor]); } } // namespace Util