X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/7f4713547665e12e032501228a98586e5add48f7..59a0e89da8ee86f0d94a9ee1d4e22722178aff50:/cmdline/apt-dump-solver.cc diff --git a/cmdline/apt-dump-solver.cc b/cmdline/apt-dump-solver.cc index 5bcfe4f06..e94021fcf 100644 --- a/cmdline/apt-dump-solver.cc +++ b/cmdline/apt-dump-solver.cc @@ -7,44 +7,179 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ +#include + +#include +#include #include +#include +#include -#include +#include #include +#include +#include +#include + +#include +#include + +#include +#include + +#include /*}}}*/ -// ShowHelp - Show a help screen /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool ShowHelp() { - - std::cout << - PACKAGE " " VERSION " for " COMMON_ARCH " compiled on " __DATE__ " " __TIME__ << std::endl << - "Usage: apt-dump-resolver\n" - "\n" - "apt-dump-resolver is a dummy solver who just dumps its input to the\n" - "file /tmp/dump.edsp and exists with a proper EDSP error.\n" - "\n" - " This dump has lost Super Cow Powers.\n"; - return true; +static bool ShowHelp(CommandLine &) /*{{{*/ +{ + std::cout << + _("Usage: apt-dump-solver\n" + "\n" + "apt-dump-solver is an interface to store an EDSP scenario in\n" + "a file and optionally forwards it to another solver.\n"); + return true; +} + /*}}}*/ +static std::vector GetCommands() /*{{{*/ +{ + return {}; +} + /*}}}*/ +static int WriteError(char const * const uid, std::ostringstream &out, FileFd &stdoutfd, pid_t const &Solver)/*{{{*/ +{ + _error->DumpErrors(out); + // ensure the solver isn't printing into "our" error message, too + if (Solver != 0) + ExecWait(Solver, "dump", true); + EDSP::WriteError(uid, out.str(), stdoutfd); + return 0; } /*}}}*/ int main(int argc,const char *argv[]) /*{{{*/ { - if (argc > 1 && (strcmp(argv[1], "--help") == 0 || strcmp(argv[1],"-h") == 0 || - strcmp(argv[1],"-v") == 0 || strcmp(argv[1],"--version") == 0)) { - ShowHelp(); - return 0; - } - - FILE* input = fdopen(STDIN_FILENO, "r"); - FILE* output = fopen("/tmp/dump.edsp", "w"); - char buffer[400]; - while (fgets(buffer, sizeof(buffer), input) != NULL) - fputs(buffer, output); - fclose(output); - fclose(input); - - EDSP::WriteError("I am too dumb, i can just dump!", stdout); + CommandLine CmdL; + ParseCommandLine(CmdL, APT_CMD::APT_DUMP_SOLVER, &_config, nullptr, argc, argv, &ShowHelp, &GetCommands); + _config->Clear("Dir::Log"); + + bool const is_forwarding_dumper = (CmdL.FileSize() != 0); + + FileFd stdoutfd; + if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false) + return 252; + + FileFd dump; + char const * const filename = is_forwarding_dumper ? CmdL.FileList[0] : getenv("APT_EDSP_DUMP_FILENAME"); + if (filename == nullptr || strlen(filename) == 0) + { + if (is_forwarding_dumper == false) + { + EDSP::WriteError("ERR_NO_FILENAME", "You have to set the environment variable APT_EDSP_DUMP_FILENAME\n" + "to a valid filename to store the dump of EDSP solver input in.\n" + "For example with: export APT_EDSP_DUMP_FILENAME=/tmp/dump.edsp", stdoutfd); + return 0; + } + } + else + { + // ignore errors here as logging isn't really critical + _error->PushToStack(); + if (dump.Open(filename, FileFd::WriteOnly | FileFd::Exclusive | FileFd::Create, FileFd::Extension, 0644) == false && + is_forwarding_dumper == false) + { + _error->MergeWithStack(); + std::ostringstream out; + out << "Writing EDSP solver input to file '" << filename << "' failed as it couldn't be created!\n"; + return WriteError("ERR_CREATE_FILE", out, stdoutfd, 0); + } + _error->RevertToStack(); + } + + pid_t Solver = 0; + FileFd forward; + if (is_forwarding_dumper) + { + int external[] = {-1, -1}; + if (pipe(external) != 0) + return 250; + for (int i = 0; i < 2; ++i) + SetCloseExec(external[i], true); + + Solver = ExecFork(); + if (Solver == 0) { + _config->Set("APT::Sandbox::User", _config->Find("APT::Solver::RunAsUser", _config->Find("APT::Sandbox::User"))); + DropPrivileges(); + dup2(external[0], STDIN_FILENO); + execv(CmdL.FileList[1], const_cast(CmdL.FileList + 1)); + std::cerr << "Failed to execute '" << CmdL.FileList[1] << "'!" << std::endl; + _exit(100); + } + close(external[0]); + + if (WaitFd(external[1], true, 5) == false) + return 251; + + if (forward.OpenDescriptor(external[1], FileFd::WriteOnly | FileFd::BufferedWrite, true) == false) + return 252; + } + + DropPrivileges(); + + FileFd input; + if (input.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly) == false) + { + std::ostringstream out; + out << "Writing EDSP solver input to file '" << filename << "' failed as stdin couldn't be opened!\n"; + return WriteError("ERR_READ_ERROR", out, stdoutfd, Solver); + } + + constexpr size_t BufSize = 64 * 1024; + std::unique_ptr Buf(new char[BufSize]); + unsigned long long ToRead = 0; + do { + if (input.Read(Buf.get(),BufSize, &ToRead) == false) + { + std::ostringstream out; + out << "Writing EDSP solver input to file '" << filename << "' failed as reading from stdin failed!\n"; + return WriteError("ERR_READ_ERROR", out, stdoutfd, Solver); + } + if (ToRead == 0) + break; + if (forward.IsOpen() && forward.Failed() == false && forward.Write(Buf.get(),ToRead) == false) + forward.Close(); + if (dump.IsOpen() && dump.Failed() == false && dump.Write(Buf.get(),ToRead) == false) + dump.Close(); + } while (true); + input.Close(); + forward.Close(); + dump.Close(); + + if (_error->PendingError()) + { + std::ostringstream out; + out << "Writing EDSP solver input to file '" << filename << "' failed due to write errors!\n"; + return WriteError("ERR_WRITE_ERROR", out, stdoutfd, Solver); + } + + if (is_forwarding_dumper) + { + // Wait and collect the error code + int Status; + while (waitpid(Solver, &Status, 0) != Solver) + { + if (errno == EINTR) + continue; + + std::ostringstream out; + ioprintf(out, _("Waited for %s but it wasn't there"), CmdL.FileList[1]); + return WriteError("ERR_FORWARD", out, stdoutfd, 0); + } + if (WIFEXITED(Status)) + return WEXITSTATUS(Status); + else + return 255; + } + else + EDSP::WriteError("ERR_JUST_DUMPING", "I am too dumb, i can just dump!\nPlease use one of my friends instead!", stdoutfd); + return 0; }