- i18n fixes from Ralf:
[apt.git] / apt-pkg / rpm / rpmsystem.cc
1 // -*- mode: c++; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: rpmsystem.cc,v 1.9 2002/11/25 18:25:28 niemeyer Exp $
4 /* ######################################################################
5
6    System - Abstraction for running on different systems.
7
8    RPM version of the system stuff
9    
10    ##################################################################### 
11  */
12                                                                         /*}}}*/
13 // Include Files                                                        /*{{{*/
14 #ifdef __GNUG__
15 #pragma implementation "apt-pkg/rpmsystem.h"
16 #endif
17
18 #include <config.h>
19
20 #ifdef HAVE_RPM
21
22 #include <apt-pkg/rpmsystem.h>
23 #include <apt-pkg/rpmversion.h>
24 #include <apt-pkg/rpmindexfile.h>
25 #include <apt-pkg/rpmpm.h>
26 #include <apt-pkg/rpmhandler.h>
27 #include <apt-pkg/configuration.h>
28 #include <apt-pkg/error.h>
29 #include <apt-pkg/fileutl.h>
30 #include <apt-pkg/rpmpackagedata.h>
31
32 #include <apti18n.h>
33     
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <dirent.h>
38 #include <fcntl.h>
39 #include <rpm/rpmlib.h>
40 #include <assert.h>
41 #include <time.h>
42                                                                         /*}}}*/
43 // for distrover
44 #if RPM_VERSION >= 0x040101
45 #include <rpmdb.h>
46 #endif
47
48 #if RPM_VERSION >= 0x040201
49 extern int _rpmds_nopromote;
50 #endif
51
52 rpmSystem rpmSys;
53
54 // System::rpmSystem - Constructor                                      /*{{{*/
55 // ---------------------------------------------------------------------
56 /* */
57 rpmSystem::rpmSystem()
58 {
59    LockCount = 0;
60    RpmDB = NULL;
61    StatusFile = NULL;
62    Label = "rpm interface";
63    VS = &rpmVS;
64 }
65                                                                         /*}}}*/
66 rpmSystem::~rpmSystem()
67 {
68    delete StatusFile;
69    delete RpmDB;
70 }
71
72 RPMDBHandler *rpmSystem::GetDBHandler()
73 {
74    if (RpmDB == NULL)
75       RpmDB = new RPMDBHandler();
76    return RpmDB;
77 }
78
79 bool rpmSystem::LockRead()
80 {
81    GetDBHandler();
82    LockCount++;
83    if (_error->PendingError() == true)
84       return false;
85    return true;
86 }
87
88 //
89 // System::Lock - Get the lock                                          /*{{{*/
90 // ---------------------------------------------------------------------
91 /* this will open the rpm database through rpmlib, which will lock the db */
92 bool rpmSystem::Lock()
93 {
94    if (RpmDB != NULL && RpmDB->HasWriteLock() == false)
95    {
96       delete RpmDB;
97       RpmDB = NULL;
98    }
99    if (RpmDB == NULL)
100       RpmDB = new RPMDBHandler(true);
101    if (_error->PendingError() == true)
102       return false;
103    LockCount++;
104    return true;
105 }
106                                                                         /*}}}*/
107 // System::UnLock - Drop a lock                                         /*{{{*/
108 // ---------------------------------------------------------------------
109 /* Close the rpmdb, effectively dropping it's lock */
110 bool rpmSystem::UnLock(bool NoErrors)
111 {
112    if (LockCount == 0 && NoErrors == true)
113       return false;
114    if (LockCount < 1)
115       return _error->Error("Not locked");
116    if (--LockCount == 0)
117    {
118       delete RpmDB;
119       RpmDB = NULL;
120    }
121    return true;
122 }
123                                                                         /*}}}*/
124 // System::CreatePM - Create the underlying package manager             /*{{{*/
125 // ---------------------------------------------------------------------
126 /* */
127 pkgPackageManager *rpmSystem::CreatePM(pkgDepCache *Cache) const
128 {
129    if (_config->Find("RPM::PM", "internal") == "internal")
130       return new pkgRPMLibPM(Cache);
131    else
132       return new pkgRPMExtPM(Cache);
133 }
134                                                                         /*}}}*/
135 // System::Initialize - Setup the configuration space..                 /*{{{*/
136 // ---------------------------------------------------------------------
137 /* These are the rpm specific configuration variables.. */
138 bool rpmSystem::Initialize(Configuration &Cnf)
139 {
140    Cnf.CndSet("Dir::Bin::rpm","/bin/rpm");
141    Cnf.CndSet("Dir::Etc::rpmpriorities", "rpmpriorities");
142    Cnf.CndSet("Dir::Etc::translatelist", "translate.list");
143    Cnf.CndSet("Dir::Etc::translateparts", "translate.list.d");
144    Cnf.CndSet("Dir::State::prefetch", "prefetch");
145    Cnf.CndSet("Acquire::DistroID","Conectiva"); // hee hee
146    Cnf.CndSet("Acquire::CDROM::Mount", "/mnt/cdrom");
147    Cnf.CndSet("Acquire::CDROM::Copy-All", "true");
148
149    // Compatibility with obsoleted options
150    if (Cnf.Exists("APT::PostInstall"))
151    {
152       _error->Warning("Rename obsoleted option APT::PostInstall to APT::Post-Install");
153       Cnf.CndSet("APT::Post-Install::Clean",
154                  Cnf.Find("APT::PostInstall::Clean","false"));
155       Cnf.CndSet("APT::Post-Install::AutoClean",
156                  Cnf.Find("APT::PostInstall::AutoClean","false"));
157    }
158    const Configuration::Item *Top;
159    Top = _config->Tree("RPM::HoldPkgs");
160    if (Top != 0)
161    {
162       _error->Warning("Rename obsoleted option RPM::HoldPkgs to RPM::Hold");
163       for (Top = Top->Child; Top != 0; Top = Top->Next)
164          Cnf.Set("RPM::Hold::", Top->Value.c_str());
165    }
166    Top = _config->Tree("RPM::AllowedDupPkgs");
167    if (Top != 0)
168    {
169       _error->Warning("Rename obsoleted option RPM::AllowedDupPkgs to RPM::Allow-Duplicated");
170       for (Top = Top->Child; Top != 0; Top = Top->Next)
171          Cnf.Set("RPM::Allow-Duplicated::", Top->Value.c_str());
172    }
173    Top = _config->Tree("RPM::IgnorePkgs");
174    if (Top != 0)
175    {
176       _error->Warning("Rename obsoleted option RPM::IgnorePkgs to RPM::Ignore");
177       for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
178          Cnf.Set("RPM::Ignore::", Top->Value.c_str());
179    }
180    if (Cnf.Exists("RPM::Force"))
181    {
182       _error->Warning("RPM::Force is obsoleted. Add \"--force\" to RPM::Options instead.");
183       if (Cnf.FindB("RPM::Force",false))
184          Cnf.Set("RPM::Options::", "--force");
185    }
186    if (Cnf.Exists("RPM::NoDeps"))
187    {
188       _error->Warning("RPM::NoDeps is obsoleted. Add \"--nodeps\" to RPM::Options and RPM::Erase-Options instead.");
189       if (Cnf.FindB("RPM::NoDeps",false))
190          Cnf.Set("RPM::Options::", "--nodeps");
191    }
192
193 #if RPM_VERSION >= 0x040201
194    const char *RPMOptions[] =
195    {
196       "RPM::Options",
197       "RPM::Install-Options",
198       "RPM::Erase-Options",
199       NULL,
200    };
201    int NoPromote = 1;
202    const char **Opt = RPMOptions;
203    while (*Opt && NoPromote)
204    {
205       Top = _config->Tree(*Opt);
206       if (Top != 0)
207       {
208          for (Top = Top->Child; Top != 0; Top = Top->Next)
209             if (Top->Value == "--promoteepoch") {
210                NoPromote = 0;
211                break;
212             }
213       }
214       Opt++;
215    }
216    _rpmds_nopromote = NoPromote;
217    HideZeroEpoch = (NoPromote == 1);
218 #else
219    HideZeroEpoch = false;
220 #endif
221
222    return true;
223 }
224                                                                         /*}}}*/
225 // System::ArchiveSupported - Is a file format supported                /*{{{*/
226 // ---------------------------------------------------------------------
227 /* The standard name for a rpm is 'rpm'.. There are no seperate versions
228    of .rpm to worry about.. */
229 bool rpmSystem::ArchiveSupported(const char *Type)
230 {
231    if (strcmp(Type,"rpm") == 0)
232       return true;
233    return false;
234 }
235                                                                         /*}}}*/
236 // System::Score - Determine how Re**at'ish this sys is..               /*{{{*/
237 // ---------------------------------------------------------------------
238 /* Check some symptoms that this is a Re**at like system */
239 signed rpmSystem::Score(Configuration const &Cnf)
240 {
241    signed Score = 0;
242
243    rpmReadConfigFiles(NULL, NULL);
244    if (FileExists(RPMDBHandler::DataPath(false)))
245       Score += 10;
246    if (FileExists(Cnf.FindFile("Dir::Bin::rpm","/bin/rpm")) == true)
247       Score += 10;
248
249    return Score;
250 }
251
252 string rpmSystem::DistroVer()
253 {
254    string DistroVerPkg = _config->Find("APT::DistroVerPkg", "");
255    if (DistroVerPkg.empty() || LockRead() == false)
256       return "";
257
258    string DistroVersion = "";
259    if (RpmDB->JumpByName(DistroVerPkg) == true) {
260       DistroVersion = RpmDB->Version();
261    } else {
262       _error->Error(_("Unable to determine version for package %s"),
263                       DistroVerPkg.c_str());
264    }
265    UnLock(true);
266
267    return DistroVersion;
268 }
269
270                                                                         /*}}}*/
271 // System::AddStatusFiles - Register the status files                   /*{{{*/
272 // ---------------------------------------------------------------------
273 /* */
274 bool rpmSystem::AddStatusFiles(vector<pkgIndexFile *> &List)
275 {
276    if (StatusFile == NULL)
277       StatusFile = new rpmDatabaseIndex();
278    List.push_back(StatusFile);
279    return true;
280 }
281                                                                         /*}}}*/
282 // System::AddSourceFiles - Register aditional source files             /*{{{*/
283 // ---------------------------------------------------------------------
284 /* */
285 bool rpmSystem::AddSourceFiles(vector<pkgIndexFile *> &List)
286 {
287    const Configuration::Item *Top;
288    Top = _config->Tree("APT::Arguments");
289    if (Top != 0)
290    {
291       for (Top = Top->Child; Top != 0; Top = Top->Next) {
292          const string &S = Top->Value;
293          if (FileExists(S) && flExtension(S) == "rpm")
294          {
295             if (S.length() > 8 && string(S, S.length()-8) == ".src.rpm")
296                List.push_back(new rpmSingleSrcIndex(S));
297             else
298                List.push_back(new rpmSinglePkgIndex(S));
299          }
300       }
301    }
302    return true;
303 }
304                                                                         /*}}}*/
305 // System::FindIndex - Get an index file for status files               /*{{{*/
306 // ---------------------------------------------------------------------
307 /* */
308 bool rpmSystem::FindIndex(pkgCache::PkgFileIterator File,
309                           pkgIndexFile *&Found) const
310 {
311    if (StatusFile == 0)
312       return false;
313    if (StatusFile->FindInCache(*File.Cache()) == File)
314    {
315       Found = StatusFile;
316       return true;
317    }
318    
319    return false;
320 }
321                                                                         /*}}}*/
322
323 // System::ProcessCache - Do specific changes in the cache              /*{{{*/
324 // ---------------------------------------------------------------------
325 /* */
326 bool rpmSystem::ProcessCache(pkgDepCache &Cache,pkgProblemResolver &Fix)
327 {
328    RPMPackageData *rpmdata = RPMPackageData::Singleton();
329    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
330    {
331       // Ignore virtual packages
332       if (I->VersionList == 0)
333          continue;
334          
335       // Do package holding
336       if (I->CurrentVer != 0)
337       {
338          if (rpmdata->HoldPackage(I.Name()))
339          {
340             Cache.MarkKeep(I);
341             Fix.Protect(I);
342          }
343       }
344    }
345    return true;
346 }
347                                                                         /*}}}*/
348
349 // System::IgnoreDep - Check if this dependency should be ignored       /*{{{*/
350 // ---------------------------------------------------------------------
351 /* For strong hearts only */
352 bool rpmSystem::IgnoreDep(pkgVersioningSystem &VS,pkgCache::DepIterator &Dep)
353 {
354    RPMPackageData *rpmdata = RPMPackageData::Singleton();
355    return rpmdata->IgnoreDep(VS,Dep);
356 }
357                                                                         /*}}}*/
358
359 // System::CacheBuilt - free caches used during cache build             /*{{{*/
360 // ---------------------------------------------------------------------
361 /* */
362 void rpmSystem::CacheBuilt()
363 {
364    RPMPackageData *rpmdata = RPMPackageData::Singleton();
365    rpmdata->CacheBuilt();
366 }
367                                                                         /*}}}*/
368
369 // System::OptionsHash - Identify options which change the cache        /*{{{*/
370 // ---------------------------------------------------------------------
371 /* */
372 static void HashString(unsigned long &Hash, const char *Str)
373 {
374    for (const char *I = Str; *I != 0; I++)
375       Hash = 5*Hash + *I;
376 }
377 static void HashEnv(unsigned long &Hash, const char *Name)
378 {
379    const char *Value = getenv(Name);
380    if (Value)
381       HashString(Hash, Value);
382 }
383 static void HashOption(unsigned long &Hash, const char *Name)
384 {
385    const Configuration::Item *Top = _config->Tree(Name);
386    if (Top != 0)
387       HashString(Hash, Top->Value.c_str());
388 }
389 static void HashOptionTree(unsigned long &Hash, const char *Name)
390 {
391    const Configuration::Item *Top = _config->Tree(Name);
392    if (Top != 0)
393       for (Top = Top->Child; Top != 0; Top = Top->Next)
394          HashString(Hash, Top->Value.c_str());
395 }
396 static void HashOptionFile(unsigned long &Hash, const char *Name)
397 {
398    string FileName = _config->FindFile(Name);
399    struct stat st;
400    stat(FileName.c_str(), &st);
401    Hash += st.st_mtime;
402 }
403
404 #if RPM_VERSION >= 0x040404
405 static void HashTime(unsigned long &Hash)
406 {
407    Hash += time(NULL);
408 }
409 #endif
410
411 unsigned long rpmSystem::OptionsHash() const
412 {
413    unsigned long Hash = 0;
414    HashOption(Hash, "RPM::Architecture");
415    HashOptionTree(Hash, "RPM::Allow-Duplicated");
416    HashOptionTree(Hash, "RPM::Ignore");
417    HashOptionFile(Hash, "Dir::Etc::rpmpriorities");
418    HashEnv(Hash, "LANG");
419    HashEnv(Hash, "LC_ALL");
420    HashEnv(Hash, "LC_MESSAGES");
421 #if RPM_VERSION >= 0x040404
422    // This is really draconian but until apt can made somehow deal with
423    // runtime dependencies the cache has to be rebuilt for each run for
424    // accuracy. Allow turning it off via configuration if not needed.
425    if (_config->FindB("RPM::RuntimeDeps", true) == true)
426       HashTime(Hash);
427 #endif
428    return Hash;
429 }
430                                                                         /*}}}*/
431
432 #endif /* HAVE_RPM */
433
434 // vim:sts=3:sw=3