]>
Commit | Line | Data |
---|---|---|
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 | } |