]> git.saurik.com Git - apt.git/blob - cmdline/apt-dump-solver.cc
Not /not/ immediately mapping a file is INSANE :/.
[apt.git] / cmdline / apt-dump-solver.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* #####################################################################
4
5 dummy solver to get quickly a scenario file out of APT
6
7 ##################################################################### */
8 /*}}}*/
9 // Include Files /*{{{*/
10 #include <config.h>
11
12 #include <apt-pkg/cmndline.h>
13 #include <apt-pkg/configuration.h>
14 #include <apt-pkg/edsp.h>
15 #include <apt-pkg/fileutl.h>
16 #include <apt-pkg/strutl.h>
17
18 #include <apt-private/private-cmndline.h>
19
20 #include <cstdio>
21 #include <iostream>
22 #include <memory>
23 #include <sstream>
24
25 #include <sys/types.h>
26 #include <sys/wait.h>
27
28 #include <string.h>
29 #include <unistd.h>
30
31 #include <apti18n.h>
32 /*}}}*/
33
34 static bool ShowHelp(CommandLine &) /*{{{*/
35 {
36 std::cout <<
37 _("Usage: apt-dump-solver\n"
38 "\n"
39 "apt-dump-solver is an interface to store an EDSP scenario in\n"
40 "a file and optionally forwards it to another solver.\n");
41 return true;
42 }
43 /*}}}*/
44 static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
45 {
46 return {};
47 }
48 /*}}}*/
49 static int WriteError(char const * const uid, std::ostringstream &out, FileFd &stdoutfd, pid_t const &Solver)/*{{{*/
50 {
51 _error->DumpErrors(out);
52 // ensure the solver isn't printing into "our" error message, too
53 if (Solver != 0)
54 ExecWait(Solver, "dump", true);
55 EDSP::WriteError(uid, out.str(), stdoutfd);
56 return 0;
57 }
58 /*}}}*/
59 int main(int argc,const char *argv[]) /*{{{*/
60 {
61 CommandLine CmdL;
62 ParseCommandLine(CmdL, APT_CMD::APT_DUMP_SOLVER, &_config, nullptr, argc, argv, &ShowHelp, &GetCommands);
63 _config->Clear("Dir::Log");
64
65 bool const is_forwarding_dumper = (CmdL.FileSize() != 0);
66
67 FileFd stdoutfd;
68 if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
69 return 252;
70
71 FileFd dump;
72 char const * const filename = is_forwarding_dumper ? CmdL.FileList[0] : getenv("APT_EDSP_DUMP_FILENAME");
73 if (filename == nullptr || strlen(filename) == 0)
74 {
75 if (is_forwarding_dumper == false)
76 {
77 EDSP::WriteError("ERR_NO_FILENAME", "You have to set the environment variable APT_EDSP_DUMP_FILENAME\n"
78 "to a valid filename to store the dump of EDSP solver input in.\n"
79 "For example with: export APT_EDSP_DUMP_FILENAME=/tmp/dump.edsp", stdoutfd);
80 return 0;
81 }
82 }
83 else
84 {
85 // ignore errors here as logging isn't really critical
86 _error->PushToStack();
87 if (dump.Open(filename, FileFd::WriteOnly | FileFd::Exclusive | FileFd::Create, FileFd::Extension, 0644) == false &&
88 is_forwarding_dumper == false)
89 {
90 _error->MergeWithStack();
91 std::ostringstream out;
92 out << "Writing EDSP solver input to file '" << filename << "' failed as it couldn't be created!\n";
93 return WriteError("ERR_CREATE_FILE", out, stdoutfd, 0);
94 }
95 _error->RevertToStack();
96 }
97
98 pid_t Solver = 0;
99 FileFd forward;
100 if (is_forwarding_dumper)
101 {
102 int external[] = {-1, -1};
103 if (pipe(external) != 0)
104 return 250;
105 for (int i = 0; i < 2; ++i)
106 SetCloseExec(external[i], true);
107
108 Solver = ExecFork();
109 if (Solver == 0) {
110 _config->Set("APT::Sandbox::User", _config->Find("APT::Solver::RunAsUser", _config->Find("APT::Sandbox::User")));
111 DropPrivileges();
112 dup2(external[0], STDIN_FILENO);
113 execv(CmdL.FileList[1], const_cast<char**>(CmdL.FileList + 1));
114 std::cerr << "Failed to execute '" << CmdL.FileList[1] << "'!" << std::endl;
115 _exit(100);
116 }
117 close(external[0]);
118
119 if (WaitFd(external[1], true, 5) == false)
120 return 251;
121
122 if (forward.OpenDescriptor(external[1], FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
123 return 252;
124 }
125
126 DropPrivileges();
127
128 FileFd input;
129 if (input.OpenDescriptor(STDIN_FILENO, FileFd::ReadOnly) == false)
130 {
131 std::ostringstream out;
132 out << "Writing EDSP solver input to file '" << filename << "' failed as stdin couldn't be opened!\n";
133 return WriteError("ERR_READ_ERROR", out, stdoutfd, Solver);
134 }
135
136 constexpr size_t BufSize = 64 * 1024;
137 std::unique_ptr<char[]> Buf(new char[BufSize]);
138 unsigned long long ToRead = 0;
139 do {
140 if (input.Read(Buf.get(),BufSize, &ToRead) == false)
141 {
142 std::ostringstream out;
143 out << "Writing EDSP solver input to file '" << filename << "' failed as reading from stdin failed!\n";
144 return WriteError("ERR_READ_ERROR", out, stdoutfd, Solver);
145 }
146 if (ToRead == 0)
147 break;
148 if (forward.IsOpen() && forward.Failed() == false && forward.Write(Buf.get(),ToRead) == false)
149 forward.Close();
150 if (dump.IsOpen() && dump.Failed() == false && dump.Write(Buf.get(),ToRead) == false)
151 dump.Close();
152 } while (true);
153 input.Close();
154 forward.Close();
155 dump.Close();
156
157 if (_error->PendingError())
158 {
159 std::ostringstream out;
160 out << "Writing EDSP solver input to file '" << filename << "' failed due to write errors!\n";
161 return WriteError("ERR_WRITE_ERROR", out, stdoutfd, Solver);
162 }
163
164 if (is_forwarding_dumper)
165 {
166 // Wait and collect the error code
167 int Status;
168 while (waitpid(Solver, &Status, 0) != Solver)
169 {
170 if (errno == EINTR)
171 continue;
172
173 std::ostringstream out;
174 ioprintf(out, _("Waited for %s but it wasn't there"), CmdL.FileList[1]);
175 return WriteError("ERR_FORWARD", out, stdoutfd, 0);
176 }
177 if (WIFEXITED(Status))
178 return WEXITSTATUS(Status);
179 else
180 return 255;
181 }
182 else
183 EDSP::WriteError("ERR_JUST_DUMPING", "I am too dumb, i can just dump!\nPlease use one of my friends instead!", stdoutfd);
184 return 0;
185 }