summaryrefslogtreecommitdiff
path: root/cmdline
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2016-06-07 17:01:33 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2016-06-08 13:07:21 +0200
commit385d9f2f23057bc5808b5e013e77ba16d1c94da4 (patch)
treeed9e6aa988b1f05c84883c3e0f8914b7d00946a3 /cmdline
parent35f3ed061f10a25a3fb28bc988fddbb976344c4d (diff)
downloadapt-385d9f2f23057bc5808b5e013e77ba16d1c94da4.tar.gz
edsp: optionally store a compressed copy of the last scenario
For bugreports and co it could be handy to have the scenario and all the settings used in it around later for inspection for EDSP like protocols. EDSP might not be the most interesting as the user can still interrupt the process before the solution is applied and users tend to have an opinion on the "rightness" of a solution, so it is disabled by default.
Diffstat (limited to 'cmdline')
-rw-r--r--cmdline/apt-dump-solver.cc215
-rw-r--r--cmdline/apt-internal-solver.cc1
-rw-r--r--cmdline/makefile4
3 files changed, 164 insertions, 56 deletions
diff --git a/cmdline/apt-dump-solver.cc b/cmdline/apt-dump-solver.cc
index 0de248e75..c6d98cd97 100644
--- a/cmdline/apt-dump-solver.cc
+++ b/cmdline/apt-dump-solver.cc
@@ -7,70 +7,177 @@
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#include <config.h>
+
+#include <apt-pkg/cmndline.h>
+#include <apt-pkg/configuration.h>
#include <apt-pkg/edsp.h>
+#include <apt-pkg/fileutl.h>
+#include <apt-pkg/strutl.h>
+
+#include <apt-private/private-cmndline.h>
-#include <string.h>
-#include <unistd.h>
#include <cstdio>
#include <iostream>
+#include <memory>
#include <sstream>
-#include <config.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <apti18n.h>
/*}}}*/
-// ShowHelp - Show a help screen /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-static bool ShowHelp() {
- ioprintf(std::cout, "%s %s (%s)\n", PACKAGE, PACKAGE_VERSION, COMMON_ARCH);
- std::cout <<
- "Usage: apt-dump-solver\n"
- "\n"
- "apt-dump-solver is a dummy solver who just dumps its input to the\n"
- "file specified in the environment variable APT_EDSP_DUMP_FILENAME and\n"
- "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<aptDispatchWithHelp> 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[]) /*{{{*/
{
- // we really don't need anything
- DropPrivileges();
-
- 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;
- }
-
- FileFd stdoutfd;
- if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
- return 1;
-
- char const * const filename = getenv("APT_EDSP_DUMP_FILENAME");
- if (filename == NULL || strlen(filename) == 0)
- {
- 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;
- }
-
- RemoveFile(argv[0], filename);
- FileFd input, output;
- if (input.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly) == false ||
- output.Open(filename, FileFd::WriteOnly | FileFd::Create | FileFd::Exclusive, FileFd::Extension, 0600) == false ||
- CopyFile(input, output) == false || input.Close() == false || output.Close() == false)
- {
- std::ostringstream out;
- out << "Writing EDSP solver input to file '" << filename << "' failed!\n";
- _error->DumpErrors(out);
- EDSP::WriteError("ERR_WRITE_ERROR", out.str(), stdoutfd);
- return 0;
- }
-
- EDSP::WriteError("ERR_JUST_DUMPING", "I am too dumb, i can just dump!\nPlease use one of my friends instead!", stdoutfd);
- return 0;
+ 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) {
+ dup2(external[0], STDIN_FILENO);
+ execv(CmdL.FileList[1], const_cast<char**>(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<char[]> 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;
}
diff --git a/cmdline/apt-internal-solver.cc b/cmdline/apt-internal-solver.cc
index 8296e8d01..aecb0eaba 100644
--- a/cmdline/apt-internal-solver.cc
+++ b/cmdline/apt-internal-solver.cc
@@ -123,6 +123,7 @@ int main(int argc,const char *argv[]) /*{{{*/
_config->Set("APT::System", "Debian APT solver interface");
_config->Set("APT::Solver", "internal");
_config->Set("edsp::scenario", "/nonexistent/stdin");
+ _config->Clear("Dir::Log");
FileFd output;
if (output.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
DIE("stdout couldn't be opened");
diff --git a/cmdline/makefile b/cmdline/makefile
index 6d21b0803..cd8ff8252 100644
--- a/cmdline/makefile
+++ b/cmdline/makefile
@@ -88,8 +88,8 @@ include $(PROGRAM_H)
# This just dumps out the state
PROGRAM=apt-dump-solver
-SLIBS = -lapt-pkg $(INTLLIBS)
-LIB_MAKES = apt-pkg/makefile
+SLIBS = -lapt-pkg -lapt-private $(INTLLIBS)
+LIB_MAKES = apt-pkg/makefile apt-private/makefile
SOURCE = apt-dump-solver.cc
include $(PROGRAM_H)