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