use the version id instead of the mmap offset as APT-ID
[ntk/apt.git] / apt-pkg / edsp.cc
CommitLineData
6d38011b
DK
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* ######################################################################
4 Set of methods to help writing and reading everything needed for EDSP
5 ##################################################################### */
6 /*}}}*/
7// Include Files /*{{{*/
c3b85126 8#include <apt-pkg/edsp.h>
6d38011b
DK
9#include <apt-pkg/error.h>
10#include <apt-pkg/configuration.h>
11#include <apt-pkg/version.h>
12#include <apt-pkg/policy.h>
2029276f 13#include <apt-pkg/tagfile.h>
6d38011b
DK
14
15#include <apti18n.h>
16#include <limits>
17
18#include <stdio.h>
19 /*}}}*/
20
c3b85126
DK
21// EDSP::WriteScenario - to the given file descriptor /*{{{*/
22bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output)
6d38011b
DK
23{
24 // we could use pkgCache::DepType and ::Priority, but these would be lokalized strings…
25 const char * const PrioMap[] = {0, "important", "required", "standard",
26 "optional", "extra"};
27 const char * const DepMap[] = {"", "Depends", "PreDepends", "Suggests",
28 "Recommends" , "Conflicts", "Replaces",
29 "Obsoletes", "Breaks", "Enhances"};
30
31 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
32 {
33 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
34 {
35 fprintf(output, "Package: %s\n", Pkg.Name());
36 fprintf(output, "Architecture: %s\n", Ver.Arch());
37 fprintf(output, "Version: %s\n", Ver.VerStr());
38 if (Pkg.CurrentVer() == Ver)
39 fprintf(output, "Installed: yes\n");
40 if (Pkg->SelectedState == pkgCache::State::Hold)
41 fprintf(output, "Hold: yes\n");
2a33cb16 42 fprintf(output, "APT-ID: %d\n", Ver->ID);
6d38011b
DK
43 fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
44 if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
45 fprintf(output, "Essential: yes\n");
46 fprintf(output, "Section: %s\n", Ver.Section());
47 if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
48 fprintf(output, "Multi-Arch: allowed\n");
49 else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
50 fprintf(output, "Multi-Arch: foreign\n");
51 else if (Ver->MultiArch == pkgCache::Version::Same)
52 fprintf(output, "Multi-Arch: same\n");
53 signed short Pin = std::numeric_limits<signed short>::min();
54 for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
55 signed short const p = Cache.GetPolicy().GetPriority(File.File());
56 if (Pin < p)
57 Pin = p;
58 }
59 fprintf(output, "APT-Pin: %d\n", Pin);
60 if (Cache.GetCandidateVer(Pkg) == Ver)
61 fprintf(output, "APT-Candidate: yes\n");
62 if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
63 fprintf(output, "APT-Automatic: yes\n");
64 std::string dependencies[pkgCache::Dep::Enhances + 1];
65 bool orGroup = false;
66 for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
67 {
68 // Ignore implicit dependencies for multiarch here
69 if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
70 continue;
71 if (orGroup == false)
72 dependencies[Dep->Type].append(", ");
73 dependencies[Dep->Type].append(Dep.TargetPkg().Name());
74 if (Dep->Version != 0)
75 dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
76 if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
77 {
78 dependencies[Dep->Type].append(" | ");
79 orGroup = true;
80 }
81 else
82 orGroup = false;
83 }
84 for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
85 if (dependencies[i].empty() == false)
86 fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
87 string provides;
88 for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
89 {
90 // Ignore implicit provides for multiarch here
91 if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
92 continue;
93 provides.append(", ").append(Prv.Name());
94 }
95 if (provides.empty() == false)
96 fprintf(output, "Provides: %s\n", provides.c_str()+2);
97
98
99 fprintf(output, "\n");
100 }
101 }
102 return true;
103}
104 /*}}}*/
c3b85126 105// EDSP::WriteRequest - to the given file descriptor /*{{{*/
93794bc9
DK
106bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
107 bool const DistUpgrade, bool const AutoRemove)
6d38011b 108{
93794bc9 109 string del, inst;
6d38011b
DK
110 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
111 {
112 string* req;
113 if (Cache[Pkg].Delete() == true)
114 req = &del;
93794bc9 115 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
6d38011b 116 req = &inst;
6d38011b
DK
117 else
118 continue;
6d5bd614 119 req->append(" ").append(Pkg.FullName());
6d38011b 120 }
93794bc9 121 fprintf(output, "Request: EDSP 0.2\n");
6d38011b 122 if (del.empty() == false)
6d5bd614 123 fprintf(output, "Remove: %s\n", del.c_str()+1);
6d38011b 124 if (inst.empty() == false)
6d5bd614 125 fprintf(output, "Install: %s\n", inst.c_str()+1);
93794bc9
DK
126 if (Upgrade == true)
127 fprintf(output, "Upgrade: yes\n");
128 if (DistUpgrade == true)
129 fprintf(output, "Dist-Upgrade: yes\n");
130 if (AutoRemove == true)
131 fprintf(output, "Autoremove: yes\n");
132 if (_config->FindB("APT::Solver::Strict-Pinning", true) == false)
133 fprintf(output, "Strict-Pinning: no\n");
134 string solverpref("APT::Solver::");
135 solverpref.append(_config->Find("APT::Solver::Name", "internal")).append("::Preferences");
6d5bd614 136 if (_config->Exists(solverpref) == true)
93794bc9 137 fprintf(output, "Preferences: %s\n", _config->Find(solverpref,"").c_str());
6d5bd614 138 fprintf(output, "\n");
6d38011b 139
e3674d91
DK
140 return true;
141}
142 /*}}}*/
2029276f
DK
143// EDSP::ReadResponse - from the given file descriptor /*{{{*/
144bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
145 FileFd in;
146 in.OpenDescriptor(input, FileFd::ReadOnly);
147 pkgTagFile response(&in);
148 pkgTagSection section;
2a33cb16
DK
149
150 /* We build an map id to mmap offset here
151 In theory we could use the offset as ID, but then VersionCount
152 couldn't be used to create other versionmappings anymore and it
153 would be too easy for a (buggy) solver to segfault APT… */
154 unsigned long long const VersionCount = Cache.Head().VersionCount;
155 unsigned long VerIdx[VersionCount];
156 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P)
157 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
158 VerIdx[V->ID] = V.Index();
159
2029276f
DK
160 while (response.Step(section) == true) {
161 std::string type;
162 if (section.Exists("Install") == true)
163 type = "Install";
164 else if (section.Exists("Remove") == true)
165 type = "Remove";
166 //FIXME: handle progress
167 else
168 continue;
29099cb6 169
2a33cb16
DK
170 size_t const id = section.FindULL(type.c_str(), VersionCount);
171 if (id == VersionCount) {
69a78835
DK
172 _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
173 continue;
2a33cb16
DK
174 } else if (id > Cache.Head().VersionCount) {
175 _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type.c_str()).c_str(), type.c_str());
176 continue;
69a78835 177 }
2029276f 178
2a33cb16 179 pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
69a78835
DK
180 Cache.SetCandidateVersion(Ver);
181 if (type == "Install")
182 Cache.MarkInstall(Ver.ParentPkg(), false, false);
183 else if (type == "Remove")
184 Cache.MarkDelete(Ver.ParentPkg(), false);
2029276f
DK
185 }
186 return true;
187}
188 /*}}}*/
6d5bd614
DK
189// EDSP::ReadLine - first line from the given file descriptor /*{{{*/
190// ---------------------------------------------------------------------
191/* Little helper method to read a complete line into a string. Similar to
192 fgets but we need to use the low-level read() here as otherwise the
193 listparser will be confused later on as mixing of fgets and read isn't
2029276f 194 a supported action according to the manpages and results are undefined */
6d5bd614
DK
195bool EDSP::ReadLine(int const input, std::string &line) {
196 char one;
197 ssize_t data = 0;
198 line.erase();
199 line.reserve(100);
200 while ((data = read(input, &one, sizeof(one))) != -1) {
201 if (data != 1)
202 continue;
203 if (one == '\n')
204 return true;
205 if (one == '\r')
206 continue;
207 if (line.empty() == true && isblank(one) != 0)
208 continue;
209 line += one;
210 }
211 return false;
212}
213 /*}}}*/
40795fca
DK
214// EDSP::StringToBool - convert yes/no to bool /*{{{*/
215// ---------------------------------------------------------------------
216/* we are not as lazy as we are in the global StringToBool as we really
217 only accept yes/no here - but we will ignore leading spaces */
218bool EDSP::StringToBool(char const *answer, bool const defValue) {
219 for (; isspace(*answer) != 0; ++answer);
220 if (strncasecmp(answer, "yes", 3) == 0)
221 return true;
222 else if (strncasecmp(answer, "no", 2) == 0)
223 return false;
224 else
225 _error->Warning("Value '%s' is not a boolean 'yes' or 'no'!", answer);
226 return defValue;
227}
228 /*}}}*/
6d5bd614
DK
229// EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
230bool EDSP::ReadRequest(int const input, std::list<std::string> &install,
40795fca
DK
231 std::list<std::string> &remove, bool &upgrade,
232 bool &distUpgrade, bool &autoRemove)
6d5bd614 233{
40795fca
DK
234 install.clear();
235 remove.clear();
236 upgrade = false;
237 distUpgrade = false;
238 autoRemove = false;
6d5bd614
DK
239 std::string line;
240 while (ReadLine(input, line) == true)
241 {
242 // Skip empty lines before request
243 if (line.empty() == true)
244 continue;
245 // The first Tag must be a request, so search for it
40795fca 246 if (line.compare(0, 8, "Request:") != 0)
6d5bd614
DK
247 continue;
248
249 while (ReadLine(input, line) == true)
250 {
251 // empty lines are the end of the request
252 if (line.empty() == true)
253 return true;
254
255 std::list<std::string> *request = NULL;
40795fca 256 if (line.compare(0, 8, "Install:") == 0)
6d5bd614 257 {
40795fca 258 line.erase(0, 8);
6d5bd614
DK
259 request = &install;
260 }
40795fca 261 else if (line.compare(0, 7, "Remove:") == 0)
6d5bd614 262 {
40795fca 263 line.erase(0, 7);
6d5bd614
DK
264 request = &remove;
265 }
40795fca
DK
266 else if (line.compare(0, 8, "Upgrade:") == 0)
267 upgrade = EDSP::StringToBool(line.c_str() + 9, false);
268 else if (line.compare(0, 13, "Dist-Upgrade:") == 0)
269 distUpgrade = EDSP::StringToBool(line.c_str() + 14, false);
270 else if (line.compare(0, 11, "Autoremove:") == 0)
271 autoRemove = EDSP::StringToBool(line.c_str() + 12, false);
272 else
273 _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str());
274
6d5bd614
DK
275 if (request == NULL)
276 continue;
277 size_t end = line.length();
278 do {
279 size_t begin = line.rfind(' ');
280 if (begin == std::string::npos)
281 {
40795fca 282 request->push_back(line.substr(0, end));
6d5bd614
DK
283 break;
284 }
285 else if (begin < end)
286 request->push_back(line.substr(begin + 1, end));
287 line.erase(begin);
288 end = line.find_last_not_of(' ');
289 } while (end != std::string::npos);
290 }
291 }
292 return false;
293}
294 /*}}}*/
295// EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
c3b85126 296bool EDSP::ApplyRequest(std::list<std::string> const &install,
29099cb6
DK
297 std::list<std::string> const &remove,
298 pkgDepCache &Cache)
6d5bd614
DK
299{
300 for (std::list<std::string>::const_iterator i = install.begin();
301 i != install.end(); ++i)
302 Cache.MarkInstall(Cache.FindPkg(*i), false);
303
304 for (std::list<std::string>::const_iterator i = remove.begin();
305 i != remove.end(); ++i)
306 Cache.MarkDelete(Cache.FindPkg(*i));
307 return true;
308}
309 /*}}}*/
c3b85126
DK
310// EDSP::WriteSolution - to the given file descriptor /*{{{*/
311bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
e3674d91 312{
6d5bd614 313 bool const Debug = _config->FindB("Debug::EDSP::WriteSolution", false);
e3674d91
DK
314 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
315 {
316 if (Cache[Pkg].Delete() == true)
317 fprintf(output, "Remove: %d\n", Cache.GetCandidateVer(Pkg)->ID);
318 else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
319 fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
320 else
321 continue;
322 if (Debug == true)
323 fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
324 fprintf(output, "\n");
325 }
326
6d38011b
DK
327 return true;
328}
329 /*}}}*/
c3b85126 330bool EDSP::WriteError(std::string const &message, FILE* output) { return false; }