fb45458de4667b490d3d2f0bedc1420fd7a18f87
[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::CDROM::Mount", "/media/cdrom");
146    Cnf.CndSet("Acquire::CDROM::Copy-All", "true");
147
148 #if RPM_VERSION >= 0x040201
149    const char *RPMOptions[] =
150    {
151       "RPM::Options",
152       "RPM::Install-Options",
153       "RPM::Erase-Options",
154       NULL,
155    };
156    int NoPromote = 1;
157    const char **Opt = RPMOptions;
158    const Configuration::Item *Top;
159    while (*Opt && NoPromote)
160    {
161       Top = _config->Tree(*Opt);
162       if (Top != 0)
163       {
164          for (Top = Top->Child; Top != 0; Top = Top->Next)
165             if (Top->Value == "--promoteepoch") {
166                NoPromote = 0;
167                break;
168             }
169       }
170       Opt++;
171    }
172    _rpmds_nopromote = NoPromote;
173    HideZeroEpoch = (NoPromote == 1);
174 #else
175    HideZeroEpoch = false;
176 #endif
177
178    return true;
179 }
180                                                                         /*}}}*/
181 // System::ArchiveSupported - Is a file format supported                /*{{{*/
182 // ---------------------------------------------------------------------
183 /* The standard name for a rpm is 'rpm'.. There are no seperate versions
184    of .rpm to worry about.. */
185 bool rpmSystem::ArchiveSupported(const char *Type)
186 {
187    if (strcmp(Type,"rpm") == 0)
188       return true;
189    return false;
190 }
191                                                                         /*}}}*/
192 // System::Score - Determine how Re**at'ish this sys is..               /*{{{*/
193 // ---------------------------------------------------------------------
194 /* Check some symptoms that this is a Re**at like system */
195 signed rpmSystem::Score(Configuration const &Cnf)
196 {
197    signed Score = 0;
198
199    rpmReadConfigFiles(NULL, NULL);
200    if (FileExists(RPMDBHandler::DataPath(false)))
201       Score += 10;
202    if (FileExists(Cnf.FindFile("Dir::Bin::rpm","/bin/rpm")) == true)
203       Score += 10;
204
205    return Score;
206 }
207
208 string rpmSystem::DistroVer()
209 {
210    string DistroVerPkg = _config->Find("APT::DistroVerPkg", "");
211    if (DistroVerPkg.empty() || LockRead() == false)
212       return "";
213
214    string DistroVersion = "";
215    if (RpmDB->JumpByName(DistroVerPkg) == true) {
216       DistroVersion = RpmDB->Version();
217    } else {
218       _error->Error(_("Unable to determine version for package %s"),
219                       DistroVerPkg.c_str());
220    }
221    UnLock(true);
222
223    return DistroVersion;
224 }
225
226                                                                         /*}}}*/
227 // System::AddStatusFiles - Register the status files                   /*{{{*/
228 // ---------------------------------------------------------------------
229 /* */
230 bool rpmSystem::AddStatusFiles(vector<pkgIndexFile *> &List)
231 {
232    if (StatusFile == NULL)
233       StatusFile = new rpmDatabaseIndex();
234    List.push_back(StatusFile);
235    return true;
236 }
237                                                                         /*}}}*/
238 // System::AddSourceFiles - Register aditional source files             /*{{{*/
239 // ---------------------------------------------------------------------
240 /* */
241 bool rpmSystem::AddSourceFiles(vector<pkgIndexFile *> &List)
242 {
243    const Configuration::Item *Top;
244    Top = _config->Tree("APT::Arguments");
245    if (Top != 0)
246    {
247       for (Top = Top->Child; Top != 0; Top = Top->Next) {
248          const string &S = Top->Value;
249          if (FileExists(S) && flExtension(S) == "rpm")
250          {
251             if (S.length() > 8 && string(S, S.length()-8) == ".src.rpm")
252                List.push_back(new rpmSingleSrcIndex(S));
253             else
254                List.push_back(new rpmSinglePkgIndex(S));
255          }
256       }
257    }
258    return true;
259 }
260                                                                         /*}}}*/
261 // System::FindIndex - Get an index file for status files               /*{{{*/
262 // ---------------------------------------------------------------------
263 /* */
264 bool rpmSystem::FindIndex(pkgCache::PkgFileIterator File,
265                           pkgIndexFile *&Found) const
266 {
267    if (StatusFile == 0)
268       return false;
269    if (StatusFile->FindInCache(*File.Cache()) == File)
270    {
271       Found = StatusFile;
272       return true;
273    }
274    
275    return false;
276 }
277                                                                         /*}}}*/
278
279 // System::ProcessCache - Do specific changes in the cache              /*{{{*/
280 // ---------------------------------------------------------------------
281 /* */
282 bool rpmSystem::ProcessCache(pkgDepCache &Cache,pkgProblemResolver &Fix)
283 {
284    RPMPackageData *rpmdata = RPMPackageData::Singleton();
285    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
286    {
287       // Ignore virtual packages
288       if (I->VersionList == 0)
289          continue;
290          
291       // Do package holding
292       if (I->CurrentVer != 0)
293       {
294          if (rpmdata->HoldPackage(I.Name()))
295          {
296             Cache.MarkKeep(I);
297             Fix.Protect(I);
298          }
299       }
300    }
301    return true;
302 }
303                                                                         /*}}}*/
304
305 // System::IgnoreDep - Check if this dependency should be ignored       /*{{{*/
306 // ---------------------------------------------------------------------
307 /* For strong hearts only */
308 bool rpmSystem::IgnoreDep(pkgVersioningSystem &VS,pkgCache::DepIterator &Dep)
309 {
310    RPMPackageData *rpmdata = RPMPackageData::Singleton();
311    return rpmdata->IgnoreDep(VS,Dep);
312 }
313                                                                         /*}}}*/
314
315 // System::CacheBuilt - free caches used during cache build             /*{{{*/
316 // ---------------------------------------------------------------------
317 /* */
318 void rpmSystem::CacheBuilt()
319 {
320    RPMPackageData *rpmdata = RPMPackageData::Singleton();
321    rpmdata->CacheBuilt();
322 }
323                                                                         /*}}}*/
324
325 // System::OptionsHash - Identify options which change the cache        /*{{{*/
326 // ---------------------------------------------------------------------
327 /* */
328 static void HashString(unsigned long &Hash, const char *Str)
329 {
330    for (const char *I = Str; *I != 0; I++)
331       Hash = 5*Hash + *I;
332 }
333 static void HashEnv(unsigned long &Hash, const char *Name)
334 {
335    const char *Value = getenv(Name);
336    if (Value)
337       HashString(Hash, Value);
338 }
339 static void HashOption(unsigned long &Hash, const char *Name)
340 {
341    const Configuration::Item *Top = _config->Tree(Name);
342    if (Top != 0)
343       HashString(Hash, Top->Value.c_str());
344 }
345 static void HashOptionTree(unsigned long &Hash, const char *Name)
346 {
347    const Configuration::Item *Top = _config->Tree(Name);
348    if (Top != 0)
349       for (Top = Top->Child; Top != 0; Top = Top->Next)
350          HashString(Hash, Top->Value.c_str());
351 }
352 static void HashOptionFile(unsigned long &Hash, const char *Name)
353 {
354    string FileName = _config->FindFile(Name);
355    struct stat st;
356    stat(FileName.c_str(), &st);
357    Hash += st.st_mtime;
358 }
359
360 #if RPM_VERSION >= 0x040404
361 static void HashTime(unsigned long &Hash)
362 {
363    Hash += time(NULL);
364 }
365 #endif
366
367 unsigned long rpmSystem::OptionsHash() const
368 {
369    unsigned long Hash = 0;
370    HashOption(Hash, "RPM::Architecture");
371    HashOptionTree(Hash, "RPM::Allow-Duplicated");
372    HashOptionTree(Hash, "RPM::Ignore");
373    HashOptionFile(Hash, "Dir::Etc::rpmpriorities");
374    HashEnv(Hash, "LANG");
375    HashEnv(Hash, "LC_ALL");
376    HashEnv(Hash, "LC_MESSAGES");
377 #if RPM_VERSION >= 0x040404
378    // This is really draconian but until apt can made somehow deal with
379    // runtime dependencies the cache has to be rebuilt for each run for
380    // accuracy. Allow turning it off via configuration if not needed.
381    if (_config->FindB("RPM::RuntimeDeps", true) == true)
382       HashTime(Hash);
383 #endif
384    return Hash;
385 }
386                                                                         /*}}}*/
387
388 #endif /* HAVE_RPM */
389
390 // vim:sts=3:sw=3