]> git.saurik.com Git - apt.git/blob - apt-pkg/policy.cc
add a segfault handler to MMap to show the Cache-Limit message, which
[apt.git] / apt-pkg / policy.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: policy.cc,v 1.10 2003/08/12 00:17:37 mdz Exp $
4 /* ######################################################################
5
6 Package Version Policy implementation
7
8 This is just a really simple wrapper around pkgVersionMatch with
9 some added goodies to manage the list of things..
10
11 Priority Table:
12
13 1000 -> inf = Downgradeable priorities
14 1000 = The 'no downgrade' pseduo-status file
15 100 -> 1000 = Standard priorities
16 990 = Config file override package files
17 989 = Start for preference auto-priorities
18 500 = Default package files
19 100 = The status file
20 0 -> 100 = NotAutomatic sources like experimental
21 -inf -> 0 = Never selected
22
23 ##################################################################### */
24 /*}}}*/
25 // Include Files /*{{{*/
26 #include <apt-pkg/policy.h>
27 #include <apt-pkg/configuration.h>
28 #include <apt-pkg/tagfile.h>
29 #include <apt-pkg/strutl.h>
30 #include <apt-pkg/error.h>
31 #include <apt-pkg/sptr.h>
32
33 #include <apti18n.h>
34
35 #include <iostream>
36 #include <sstream>
37 /*}}}*/
38
39 using namespace std;
40
41 // Policy::Init - Startup and bind to a cache /*{{{*/
42 // ---------------------------------------------------------------------
43 /* Set the defaults for operation. The default mode with no loaded policy
44 file matches the V0 policy engine. */
45 pkgPolicy::pkgPolicy(pkgCache *Owner) : Pins(0), PFPriority(0), Cache(Owner)
46 {
47 PFPriority = new signed short[Owner->Head().PackageFileCount];
48 Pins = new Pin[Owner->Head().PackageCount];
49
50 for (unsigned long I = 0; I != Owner->Head().PackageCount; I++)
51 Pins[I].Type = pkgVersionMatch::None;
52
53 // The config file has a master override.
54 string DefRel = _config->Find("APT::Default-Release");
55 if (DefRel.empty() == false)
56 CreatePin(pkgVersionMatch::Release,"",DefRel,990);
57
58 InitDefaults();
59 }
60 /*}}}*/
61 // Policy::InitDefaults - Compute the default selections /*{{{*/
62 // ---------------------------------------------------------------------
63 /* */
64 bool pkgPolicy::InitDefaults()
65 {
66 // Initialize the priorities based on the status of the package file
67 for (pkgCache::PkgFileIterator I = Cache->FileBegin(); I != Cache->FileEnd(); I++)
68 {
69 PFPriority[I->ID] = 500;
70 if ((I->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
71 PFPriority[I->ID] = 100;
72 else
73 if ((I->Flags & pkgCache::Flag::NotAutomatic) == pkgCache::Flag::NotAutomatic)
74 PFPriority[I->ID] = 1;
75 }
76
77 // Apply the defaults..
78 SPtrArray<bool> Fixed = new bool[Cache->HeaderP->PackageFileCount];
79 memset(Fixed,0,sizeof(*Fixed)*Cache->HeaderP->PackageFileCount);
80 signed Cur = 989;
81 StatusOverride = false;
82 for (vector<Pin>::const_iterator I = Defaults.begin(); I != Defaults.end();
83 I++, Cur--)
84 {
85 pkgVersionMatch Match(I->Data,I->Type);
86 for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++)
87 {
88 if (Match.FileMatch(F) == true && Fixed[F->ID] == false)
89 {
90 if (I->Priority != 0 && I->Priority > 0)
91 Cur = I->Priority;
92
93 if (I->Priority < 0)
94 PFPriority[F->ID] = I->Priority;
95 else
96 PFPriority[F->ID] = Cur;
97
98 if (PFPriority[F->ID] > 1000)
99 StatusOverride = true;
100
101 Fixed[F->ID] = true;
102 }
103 }
104 }
105
106 if (_config->FindB("Debug::pkgPolicy",false) == true)
107 for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); F++)
108 cout << "Prio of " << F.FileName() << ' ' << PFPriority[F->ID] << endl;
109
110 return true;
111 }
112 /*}}}*/
113 // Policy::GetCandidateVer - Get the candidate install version /*{{{*/
114 // ---------------------------------------------------------------------
115 /* Evaluate the package pins and the default list to deteremine what the
116 best package is. */
117 pkgCache::VerIterator pkgPolicy::GetCandidateVer(pkgCache::PkgIterator Pkg)
118 {
119 // Look for a package pin and evaluate it.
120 signed Max = GetPriority(Pkg);
121 pkgCache::VerIterator Pref = GetMatch(Pkg);
122
123 // no package = no candidate version
124 if (Pkg.end() == true)
125 return Pref;
126
127 // packages with a pin lower than 0 have no newer candidate than the current version
128 if (Max < 0)
129 return Pkg.CurrentVer();
130
131 /* Falling through to the default version.. Setting Max to zero
132 effectively excludes everything <= 0 which are the non-automatic
133 priorities.. The status file is given a prio of 100 which will exclude
134 not-automatic sources, except in a single shot not-installed mode.
135 The second pseduo-status file is at prio 1000, above which will permit
136 the user to force-downgrade things.
137
138 The user pin is subject to the same priority rules as default
139 selections. Thus there are two ways to create a pin - a pin that
140 tracks the default when the default is taken away, and a permanent
141 pin that stays at that setting.
142 */
143 for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
144 {
145 for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; VF++)
146 {
147 /* If this is the status file, and the current version is not the
148 version in the status file (ie it is not installed, or somesuch)
149 then it is not a candidate for installation, ever. This weeds
150 out bogus entries that may be due to config-file states, or
151 other. */
152 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource &&
153 Pkg.CurrentVer() != Ver)
154 continue;
155
156 signed Prio = PFPriority[VF.File()->ID];
157 if (Prio > Max)
158 {
159 Pref = Ver;
160 Max = Prio;
161 }
162 }
163
164 if (Pkg.CurrentVer() == Ver && Max < 1000)
165 {
166 /* Elevate our current selection (or the status file itself)
167 to the Pseudo-status priority. */
168 if (Pref.end() == true)
169 Pref = Ver;
170 Max = 1000;
171
172 // Fast path optimize.
173 if (StatusOverride == false)
174 break;
175 }
176 }
177 return Pref;
178 }
179 /*}}}*/
180 // Policy::CreatePin - Create an entry in the pin table.. /*{{{*/
181 // ---------------------------------------------------------------------
182 /* For performance we have 3 tables, the default table, the main cache
183 table (hashed to the cache). A blank package name indicates the pin
184 belongs to the default table. Order of insertion matters here, the
185 earlier defaults override later ones. */
186 void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
187 string Data,signed short Priority)
188 {
189 Pin *P = 0;
190
191 if (Name.empty() == true)
192 P = &*Defaults.insert(Defaults.end(),PkgPin());
193 else
194 {
195 // Get a spot to put the pin
196 pkgCache::PkgIterator Pkg = Cache->FindPkg(Name);
197 if (Pkg.end() == true)
198 {
199 // Check the unmatched table
200 for (vector<PkgPin>::iterator I = Unmatched.begin();
201 I != Unmatched.end() && P == 0; I++)
202 if (I->Pkg == Name)
203 P = &*I;
204
205 if (P == 0)
206 P = &*Unmatched.insert(Unmatched.end(),PkgPin());
207 }
208 else
209 {
210 P = Pins + Pkg->ID;
211 }
212 }
213
214 // Set..
215 P->Type = Type;
216 P->Priority = Priority;
217 P->Data = Data;
218 }
219 /*}}}*/
220 // Policy::GetMatch - Get the matching version for a package pin /*{{{*/
221 // ---------------------------------------------------------------------
222 /* */
223 pkgCache::VerIterator pkgPolicy::GetMatch(pkgCache::PkgIterator Pkg)
224 {
225 const Pin &PPkg = Pins[Pkg->ID];
226 if (PPkg.Type != pkgVersionMatch::None)
227 {
228 pkgVersionMatch Match(PPkg.Data,PPkg.Type);
229 return Match.Find(Pkg);
230 }
231 return pkgCache::VerIterator(*Pkg.Cache());
232 }
233 /*}}}*/
234 // Policy::GetPriority - Get the priority of the package pin /*{{{*/
235 // ---------------------------------------------------------------------
236 /* */
237 signed short pkgPolicy::GetPriority(pkgCache::PkgIterator const &Pkg)
238 {
239 if (Pins[Pkg->ID].Type != pkgVersionMatch::None)
240 {
241 // In this case 0 means default priority
242 if (Pins[Pkg->ID].Priority == 0)
243 return 989;
244 return Pins[Pkg->ID].Priority;
245 }
246
247 return 0;
248 }
249 /*}}}*/
250 // PreferenceSection class - Overriding the default TrimRecord method /*{{{*/
251 // ---------------------------------------------------------------------
252 /* The preference file is a user generated file so the parser should
253 therefore be a bit more friendly by allowing comments and new lines
254 all over the place rather than forcing a special format */
255 class PreferenceSection : public pkgTagSection
256 {
257 void TrimRecord(bool BeforeRecord, const char* &End)
258 {
259 for (; Stop < End && (Stop[0] == '\n' || Stop[0] == '\r' || Stop[0] == '#'); Stop++)
260 if (Stop[0] == '#')
261 Stop = (const char*) memchr(Stop,'\n',End-Stop);
262 }
263 };
264 /*}}}*/
265 // ReadPinFile - Load the pin file into a Policy /*{{{*/
266 // ---------------------------------------------------------------------
267 /* I'd like to see the preferences file store more than just pin information
268 but right now that is the only stuff I have to store. Later there will
269 have to be some kind of combined super parser to get the data into all
270 the right classes.. */
271 bool ReadPinFile(pkgPolicy &Plcy,string File)
272 {
273 if (File.empty() == true)
274 File = _config->FindFile("Dir::Etc::Preferences");
275
276 if (FileExists(File) == false)
277 return true;
278
279 FileFd Fd(File,FileFd::ReadOnly);
280 pkgTagFile TF(&Fd);
281 if (_error->PendingError() == true)
282 return false;
283
284 PreferenceSection Tags;
285 while (TF.Step(Tags) == true)
286 {
287 string Name = Tags.FindS("Package");
288 if (Name.empty() == true)
289 return _error->Error(_("Invalid record in the preferences file, no Package header"));
290 if (Name == "*")
291 Name = string();
292
293 const char *Start;
294 const char *End;
295 if (Tags.Find("Pin",Start,End) == false)
296 continue;
297
298 const char *Word = Start;
299 for (; Word != End && isspace(*Word) == 0; Word++);
300
301 // Parse the type..
302 pkgVersionMatch::MatchType Type;
303 if (stringcasecmp(Start,Word,"version") == 0 && Name.empty() == false)
304 Type = pkgVersionMatch::Version;
305 else if (stringcasecmp(Start,Word,"release") == 0)
306 Type = pkgVersionMatch::Release;
307 else if (stringcasecmp(Start,Word,"origin") == 0)
308 Type = pkgVersionMatch::Origin;
309 else
310 {
311 _error->Warning(_("Did not understand pin type %s"),string(Start,Word).c_str());
312 continue;
313 }
314 for (; Word != End && isspace(*Word) != 0; Word++);
315
316 short int priority = Tags.FindI("Pin-Priority", 0);
317 if (priority == 0)
318 {
319 _error->Warning(_("No priority (or zero) specified for pin"));
320 continue;
321 }
322
323 istringstream s(Name);
324 string pkg;
325 while(!s.eof())
326 {
327 s >> pkg;
328 Plcy.CreatePin(Type, pkg, string(Word,End),priority);
329 };
330 }
331
332 Plcy.InitDefaults();
333 return true;
334 }
335 /*}}}*/