diff -r 9172bd97ae99 -r 6f15f18d2abf src/SystemProcess.h --- a/src/SystemProcess.h Mon Nov 11 14:42:13 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,145 +0,0 @@ -/** - * Relational pipes - * Copyright © 2019 František Kučera (Frantovo.cz, GlobalCode.info) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace relpipe { -namespace in { -namespace filesystem { - -/** - * Simple wrapper for a system process (fork+exec) that captures and returns just the STDOUT. - */ -class SystemProcess { -private: - /** - * the command + its arguments - */ - std::vector commandLine; - std::vector environment; - int nullFile = -1; - - /** - * TODO: move to a common library (copied from the AWK module) - * @param args - */ - void execp(const std::vector& args) { - const char** a = new const char*[args.size() + 1]; - for (size_t i = 0; i < args.size(); i++) a[i] = args[i].c_str(); - a[args.size()] = nullptr; - - execvp(a[0], (char*const*) a); - - delete[] a; - throw relpipe::cli::RelpipeCLIException(L"Unable to do execvp().", relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception? - } - - /** - * TODO: move to a common library (copied from the AWK module) - * @param readerFD - * @param writerFD - */ - void createPipe(int& readerFD, int& writerFD) { - int fds[2]; - int result = pipe(fds); - readerFD = fds[0]; - writerFD = fds[1]; - if (result < 0) throw relpipe::cli::RelpipeCLIException(L"Unable to create a pipe.", relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception? - } - - /** - * TODO: move to a common library (copied from the AWK module) - */ - void redirectFD(int oldfd, int newfd) { - int result = dup2(oldfd, newfd); - if (result < 0) throw relpipe::cli::RelpipeCLIException(L"Unable redirect FD.", relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception? - } - - /** - * TODO: move to a common library (copied from the AWK module) - */ - void closeOrThrow(int fd) { - int error = close(fd); - if (error) throw relpipe::cli::RelpipeCLIException(L"Unable to close FD: " + to_wstring(fd) + L" from PID: " + to_wstring(getpid()), relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception? - } - -public: - - SystemProcess(const std::vector& commandLine, const std::vector& environment = {}) : commandLine(commandLine), environment(environment) { - nullFile = open("/dev/null", O_RDWR); - } - - virtual ~SystemProcess() { - close(nullFile); - } - - std::string execute() { - - std::stringstream result; - - // FIXME: different kinds of exception or return the exit code (now it enters infinite loop if the execp() fails) - // TODO: rename (not specific to hash) - int hashReaderFD; - int hashWriterFD; - createPipe(hashReaderFD, hashWriterFD); - - __pid_t hashPid = fork(); - - if (hashPid < 0) { - throw relpipe::cli::RelpipeCLIException(L"Unable to fork the hash process.", relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception? - } else if (hashPid == 0) { - // Child process - closeOrThrow(hashReaderFD); - redirectFD(nullFile, STDIN_FILENO); - redirectFD(nullFile, STDERR_FILENO); - redirectFD(hashWriterFD, STDOUT_FILENO); - for (int i = 0; i < environment.size();) { - std::string name = environment[i++]; - std::string value = environment[i++]; - setenv(name.c_str(), value.c_str(), true); - } - execp(commandLine); - } else { - // Parent process - closeOrThrow(hashWriterFD); - - __gnu_cxx::stdio_filebuf hashReaderBuffer(hashReaderFD, std::ios::in); - std::istream hashReader(&hashReaderBuffer); - - for (char ch; hashReader.read(&ch, 1).good();) result.put(ch); - - int waitError; - __pid_t waitPID = wait(&waitError); - if (waitError) throw relpipe::cli::RelpipeCLIException(L"The child process returned an error exit code.", relpipe::cli::CLI::EXIT_CODE_UNEXPECTED_ERROR); // TODO: better exception? - } - - return result.str(); - } -}; - -} -} -}