8308aab64f758d99db65f38ceea9585543264a36
[apt.git] / apt-pkg / rpm / rpmsystem.cc
1 // -*- mode: cpp; 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 <rpm/rpmlib.h>
39 #include <assert.h>
40                                                                         /*}}}*/
41 #if RPM_VERSION >= 0x040201
42 extern int _rpmds_nopromote;
43 #endif
44
45 rpmSystem rpmSys;
46
47 // System::rpmSystem - Constructor                                      /*{{{*/
48 // ---------------------------------------------------------------------
49 /* */
50 rpmSystem::rpmSystem()
51 {
52    LockCount = 0;
53    RpmDB = NULL;
54    StatusFile = NULL;
55    Label = "rpm interface";
56    VS = &rpmVS;
57 }
58                                                                         /*}}}*/
59 rpmSystem::~rpmSystem()
60 {
61    delete StatusFile;
62    delete RpmDB;
63 }
64
65 RPMDBHandler *rpmSystem::GetDBHandler()
66 {
67    if (RpmDB == NULL)
68       RpmDB = new RPMDBHandler();
69    return RpmDB;
70 }
71
72 bool rpmSystem::LockRead()
73 {
74    GetDBHandler();
75    if (_error->PendingError() == true)
76       return false;
77    return true;
78 }
79
80 //
81 // System::Lock - Get the lock                                          /*{{{*/
82 // ---------------------------------------------------------------------
83 /* this will open the rpm database through rpmlib, which will lock the db */
84 bool rpmSystem::Lock()
85 {
86    if (RpmDB != NULL && RpmDB->HasWriteLock() == false)
87    {
88       delete RpmDB;
89       RpmDB = NULL;
90    }
91    if (RpmDB == NULL)
92       RpmDB = new RPMDBHandler(true);
93    if (_error->PendingError() == true)
94       return false;
95    LockCount++;
96    return true;
97 }
98                                                                         /*}}}*/
99 // System::UnLock - Drop a lock                                         /*{{{*/
100 // ---------------------------------------------------------------------
101 /* Close the rpmdb, effectively dropping it's lock */
102 bool rpmSystem::UnLock(bool NoErrors)
103 {
104    if (LockCount == 0 && NoErrors == true)
105       return false;
106    if (LockCount < 1)
107       return _error->Error("Not locked");
108    if (--LockCount == 0)
109    {
110       delete RpmDB;
111       RpmDB = NULL;
112    }
113    return true;
114 }
115                                                                         /*}}}*/
116 // System::CreatePM - Create the underlying package manager             /*{{{*/
117 // ---------------------------------------------------------------------
118 /* */
119 pkgPackageManager *rpmSystem::CreatePM(pkgDepCache *Cache) const
120 {
121    if (_config->Find("RPM::PM", "internal") == "internal")
122       return new pkgRPMLibPM(Cache);
123    else
124       return new pkgRPMExtPM(Cache);
125 }
126                                                                         /*}}}*/
127 // System::Initialize - Setup the configuration space..                 /*{{{*/
128 // ---------------------------------------------------------------------
129 /* These are the rpm specific configuration variables.. */
130 bool rpmSystem::Initialize(Configuration &Cnf)
131 {
132    Cnf.CndSet("Dir::Bin::rpm","/bin/rpm");
133    Cnf.CndSet("Dir::Etc::rpmpriorities", "rpmpriorities");
134    Cnf.CndSet("Dir::Etc::translatelist", "translate.list");
135    Cnf.CndSet("Dir::Etc::translateparts", "translate.list.d");
136    Cnf.CndSet("Dir::State::prefetch", "prefetch");
137    Cnf.CndSet("Dir::Locale","/usr/share/locale");
138    Cnf.CndSet("Acquire::DistroID","Conectiva"); // hee hee
139    Cnf.CndSet("Acquire::CDROM::Mount", "/mnt/cdrom");
140    Cnf.CndSet("Acquire::CDROM::Copy-All", "true");
141
142    // Compatibility with obsoleted options
143    if (Cnf.Exists("APT::PostInstall"))
144    {
145       _error->Warning("Rename obsoleted option APT::PostInstall to APT::Post-Install");
146       Cnf.CndSet("APT::Post-Install::Clean",
147                  Cnf.Find("APT::PostInstall::Clean","false"));
148       Cnf.CndSet("APT::Post-Install::AutoClean",
149                  Cnf.Find("APT::PostInstall::AutoClean","false"));
150    }
151    const Configuration::Item *Top;
152    Top = _config->Tree("RPM::HoldPkgs");
153    if (Top != 0)
154    {
155       _error->Warning("Rename obsoleted option RPM::HoldPkgs to RPM::Hold");
156       for (Top = Top->Child; Top != 0; Top = Top->Next)
157          Cnf.Set("RPM::Hold::", Top->Value.c_str());
158    }
159    Top = _config->Tree("RPM::AllowedDupPkgs");
160    if (Top != 0)
161    {
162       _error->Warning("Rename obsoleted option RPM::AllowedDupPkgs to RPM::Allow-Duplicated");
163       for (Top = Top->Child; Top != 0; Top = Top->Next)
164          Cnf.Set("RPM::Allow-Duplicated::", Top->Value.c_str());
165    }
166    Top = _config->Tree("RPM::IgnorePkgs");
167    if (Top != 0)
168    {
169       _error->Warning("Rename obsoleted option RPM::IgnorePkgs to RPM::Ignore");
170       for (Top = (Top == 0?0:Top->Child); Top != 0; Top = Top->Next)
171          Cnf.Set("RPM::Ignore::", Top->Value.c_str());
172    }
173    if (Cnf.Exists("RPM::Force"))
174    {
175       _error->Warning("RPM::Force is obsoleted. Add \"--force\" to RPM::Options instead.");
176       if (Cnf.FindB("RPM::Force",false))
177          Cnf.Set("RPM::Options::", "--force");
178    }
179    if (Cnf.Exists("RPM::NoDeps"))
180    {
181       _error->Warning("RPM::NoDeps is obsoleted. Add \"--nodeps\" to RPM::Options and RPM::Erase-Options instead.");
182       if (Cnf.FindB("RPM::NoDeps",false))
183          Cnf.Set("RPM::Options::", "--nodeps");
184    }
185
186 #if RPM_VERSION >= 0x040201
187    const char *RPMOptions[] =
188    {
189       "RPM::Options",
190       "RPM::Install-Options",
191       "RPM::Erase-Options",
192       NULL,
193    };
194    int NoPromote = 1;
195    const char **Opt = RPMOptions;
196    while (*Opt && NoPromote)
197    {
198       Top = _config->Tree(*Opt);
199       if (Top != 0)
200       {
201          for (Top = Top->Child; Top != 0; Top = Top->Next)
202             if (Top->Value == "--promoteepoch") {
203                NoPromote = 0;
204                break;
205             }
206       }
207       Opt++;
208    }
209    _rpmds_nopromote = NoPromote;
210 #endif
211
212    return true;
213 }
214                                                                         /*}}}*/
215 // System::ArchiveSupported - Is a file format supported                /*{{{*/
216 // ---------------------------------------------------------------------
217 /* The standard name for a rpm is 'rpm'.. There are no seperate versions
218    of .rpm to worry about.. */
219 bool rpmSystem::ArchiveSupported(const char *Type)
220 {
221    if (strcmp(Type,"rpm") == 0)
222       return true;
223    return false;
224 }
225                                                                         /*}}}*/
226 // System::Score - Determine how Re**at'ish this sys is..               /*{{{*/
227 // ---------------------------------------------------------------------
228 /* Check some symptoms that this is a Re**at like system */
229 signed rpmSystem::Score(Configuration const &Cnf)
230 {
231    signed Score = 0;
232
233    rpmReadConfigFiles(NULL, NULL);
234    if (FileExists(RPMDBHandler::DataPath(false)))
235       Score += 10;
236    if (FileExists(Cnf.FindFile("Dir::Bin::rpm","/bin/rpm")) == true)
237       Score += 10;
238
239    return Score;
240 }
241                                                                         /*}}}*/
242 // System::AddStatusFiles - Register the status files                   /*{{{*/
243 // ---------------------------------------------------------------------
244 /* */
245 bool rpmSystem::AddStatusFiles(vector<pkgIndexFile *> &List)
246 {
247    if (StatusFile == NULL)
248       StatusFile = new rpmDatabaseIndex();
249    List.push_back(StatusFile);
250    return true;
251 }
252                                                                         /*}}}*/
253 // System::AddSourceFiles - Register aditional source files             /*{{{*/
254 // ---------------------------------------------------------------------
255 /* */
256 bool rpmSystem::AddSourceFiles(vector<pkgIndexFile *> &List)
257 {
258    const Configuration::Item *Top;
259    Top = _config->Tree("APT::Arguments");
260    if (Top != 0)
261    {
262       for (Top = Top->Child; Top != 0; Top = Top->Next) {
263          const string &S = Top->Value;
264          if (FileExists(S) && flExtension(S) == "rpm")
265          {
266             if (S.length() > 8 && string(S, S.length()-8) == ".src.rpm")
267                List.push_back(new rpmSingleSrcIndex(S));
268             else
269                List.push_back(new rpmSinglePkgIndex(S));
270          }
271       }
272    }
273    return true;
274 }
275                                                                         /*}}}*/
276 #ifdef OLD_FILEDEPS
277 static void gatherFileDependencies(map<string,int> &filedeps, Header header)
278 {
279    int type, count;
280    char **namel;
281    //char **verl;
282    //int *flagl;
283    int res;
284    
285    res = headerGetEntry(header, RPMTAG_REQUIRENAME, &type,
286                         (void **)&namel, &count);
287    /*
288    res = headerGetEntry(header, RPMTAG_REQUIREVERSION, &type, 
289                         (void **)&verl, &count);
290    res = headerGetEntry(header, RPMTAG_REQUIREFLAGS, &type,
291                         (void **)&flagl, &count);
292    */
293    
294    while (count--) 
295    {
296       if (*namel[count] == '/')
297          filedeps[string(namel[count])] = 1;
298    }
299 }
300 #endif
301
302
303 #ifdef OLD_BESTARCH
304 bool rpmSystem::processIndexFile(rpmIndexFile *Index,OpProgress &Progress)
305 {
306    Header hdr;
307    map<string,string> archmap;
308    
309    RPMHandler *Handler = Index->CreateHandler();
310    if (_error->PendingError() == true)
311       return false;
312
313    Progress.SubProgress(0, Index->Describe());
314    
315    Handler->Rewind();
316
317    while (Handler->Skip() == true)
318    {
319       int type, count, res;
320       char *arch;
321
322       hdr = Handler->GetHeader();
323       if (!hdr)
324           break;
325
326 #ifdef OLD_FILEDEPS
327       gatherFileDependencies(FileDeps, hdr);
328 #endif
329       
330       /*
331        * Make it so that for each version, we keep track of the best
332        * architecture.
333        */
334       res = headerGetEntry(hdr, RPMTAG_ARCH, &type,
335                            (void **)&arch, &count);
336       assert(type == RPM_STRING_TYPE);
337       if (res) 
338       {
339          char *name;
340          char *version;
341          char *release;
342          int_32 *epoch;
343          int res;
344          char buf[256];
345          
346          headerGetEntry(hdr, RPMTAG_NAME, &type,
347                         (void **)&name, &count);
348          headerGetEntry(hdr, RPMTAG_VERSION, &type,
349                         (void **)&version, &count);
350          headerGetEntry(hdr, RPMTAG_RELEASE, &type,
351                         (void **)&release, &count);
352          res = headerGetEntry(hdr, RPMTAG_EPOCH, &type,
353                               (void **)&epoch, &count);
354          
355          if (res == 1)
356             snprintf(buf, sizeof(buf), "%i:%s-%s", *epoch, version, release);
357          else
358             snprintf(buf, sizeof(buf), "%s-%s", version, release);
359          string n = string(name)+"#"+string(buf);
360          
361          if (archmap.find(n) != archmap.end()) 
362          {
363             if (strcmp(archmap[n].c_str(), arch) != 0) 
364             {
365                int a = rpmMachineScore(RPM_MACHTABLE_INSTARCH, archmap[n].c_str());
366                int b = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
367                
368                if (b < a) 
369                {
370                   MultiArchPkgs[n] = string(arch);
371                   // this is a multiarch pkg
372                   archmap[n] = MultiArchPkgs[n];
373                }
374                else 
375                {
376                   MultiArchPkgs[n] = archmap[n];
377                }
378             }
379          }
380          else 
381          {
382             archmap[n] = string(arch);
383          }
384       }
385    }
386    
387    if (Handler->IsDatabase() == false)
388        delete Handler;
389
390    return true;
391 }
392
393
394 bool rpmSystem::PreProcess(pkgIndexFile **Start,pkgIndexFile **End,
395                            OpProgress &Progress)
396 {
397    string ListDir = _config->FindDir("Dir::State::lists");
398    unsigned total, complete;
399    unsigned long TotalSize = 0, CurrentSize = 0;
400
401    // calculate size of files
402    
403    for (; Start != End; Start++)
404    {
405       if ((*Start)->HasPackages() == false)
406           continue;
407       
408       if ((*Start)->Exists() == false)
409           continue;
410       
411       unsigned long Size = (*Start)->Size();
412       Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
413       CurrentSize += Size;
414
415       if (processIndexFile((rpmIndexFile*)*Start,Progress) == false)
416          return false;
417    }
418   
419    return true;
420 }
421
422 string rpmSystem::BestArchForPackage(string Pkg)
423 {
424    if (MultiArchPkgs.find(Pkg) != MultiArchPkgs.end())
425       return MultiArchPkgs[Pkg];
426    else
427        return string();
428 }
429 #endif
430
431 #ifdef OLD_FILEDEPS
432 bool rpmSystem::IsFileDep(string File)
433 {
434    return (FileDeps.find(File) != FileDeps.end());
435 }
436 #endif
437
438 // System::FindIndex - Get an index file for status files               /*{{{*/
439 // ---------------------------------------------------------------------
440 /* */
441 bool rpmSystem::FindIndex(pkgCache::PkgFileIterator File,
442                           pkgIndexFile *&Found) const
443 {
444    if (StatusFile == 0)
445       return false;
446    if (StatusFile->FindInCache(*File.Cache()) == File)
447    {
448       Found = StatusFile;
449       return true;
450    }
451    
452    return false;
453 }
454                                                                         /*}}}*/
455
456 // System::ProcessCache - Do specific changes in the cache              /*{{{*/
457 // ---------------------------------------------------------------------
458 /* */
459 bool rpmSystem::ProcessCache(pkgDepCache &Cache,pkgProblemResolver &Fix)
460 {
461    RPMPackageData *rpmdata = RPMPackageData::Singleton();
462    for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++)
463    {
464       // Ignore virtual packages
465       if (I->VersionList == 0)
466          continue;
467          
468       // Do package holding
469       if (I->CurrentVer != 0)
470       {
471          if (rpmdata->HoldPackage(I.Name()))
472          {
473             Cache.MarkKeep(I);
474             Fix.Protect(I);
475          }
476       }
477    }
478    return true;
479 }
480                                                                         /*}}}*/
481
482 // System::IgnoreDep - Check if this dependency should be ignored       /*{{{*/
483 // ---------------------------------------------------------------------
484 /* For strong hearts only */
485 bool rpmSystem::IgnoreDep(pkgVersioningSystem &VS,pkgCache::DepIterator &Dep)
486 {
487    RPMPackageData *rpmdata = RPMPackageData::Singleton();
488    return rpmdata->IgnoreDep(VS,Dep);
489 }
490                                                                         /*}}}*/
491
492 // System::CacheBuilt - free caches used during cache build             /*{{{*/
493 // ---------------------------------------------------------------------
494 /* */
495 void rpmSystem::CacheBuilt()
496 {
497    RPMPackageData *rpmdata = RPMPackageData::Singleton();
498    rpmdata->CacheBuilt();
499 }
500                                                                         /*}}}*/
501
502 // System::OptionsHash - Identify options which change the cache        /*{{{*/
503 // ---------------------------------------------------------------------
504 /* */
505 static void HashString(unsigned long &Hash, const char *Str)
506 {
507    for (const char *I = Str; *I != 0; I++)
508       Hash = 5*Hash + *I;
509 }
510 static void HashEnv(unsigned long &Hash, const char *Name)
511 {
512    const char *Value = getenv(Name);
513    if (Value)
514       HashString(Hash, Value);
515 }
516 static void HashOption(unsigned long &Hash, const char *Name)
517 {
518    const Configuration::Item *Top = _config->Tree(Name);
519    if (Top != 0)
520       HashString(Hash, Top->Value.c_str());
521 }
522 static void HashOptionTree(unsigned long &Hash, const char *Name)
523 {
524    const Configuration::Item *Top = _config->Tree(Name);
525    if (Top != 0)
526       for (Top = Top->Child; Top != 0; Top = Top->Next)
527          HashString(Hash, Top->Value.c_str());
528 }
529 static void HashOptionFile(unsigned long &Hash, const char *Name)
530 {
531    string FileName = _config->FindFile(Name);
532    struct stat st;
533    stat(FileName.c_str(), &st);
534    Hash += st.st_mtime;
535 }
536 unsigned long rpmSystem::OptionsHash() const
537 {
538    unsigned long Hash = 0;
539    HashOption(Hash, "RPM::Architecture");
540    HashOptionTree(Hash, "RPM::Allow-Duplicated");
541    HashOptionTree(Hash, "RPM::Ignore");
542    HashOptionFile(Hash, "Dir::Etc::rpmpriorities");
543    HashEnv(Hash, "LANG");
544    HashEnv(Hash, "LC_ALL");
545    HashEnv(Hash, "LC_MESSAGES");
546    return Hash;
547 }
548                                                                         /*}}}*/
549
550 #endif /* HAVE_RPM */
551
552 // vim:sts=3:sw=3