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