libzypp  17.35.14
librpmDb.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include "librpm.h"
13 
14 #include <iostream>
15 #include <utility>
16 
17 #include <zypp/base/Logger.h>
18 #include <zypp/PathInfo.h>
19 #include <zypp-core/AutoDispose.h>
23 
24 #undef ZYPP_BASE_LOGGER_LOGGROUP
25 #define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
26 
27 using std::endl;
28 
29 namespace zypp
30 {
31 namespace target
32 {
33 namespace rpm
34 {
35  namespace internal
36  {
37  // helper functions here expect basic checks on arguments have been performed.
38  // (globalInit done, root is absolute, dbpath not empty, ...)
39  inline const Pathname & rpmDefaultDbPath()
40  {
41  static const Pathname _val = [](){
42  Pathname ret = librpmDb::expand( "%{_dbpath}" );
43  if ( ret.empty() ) {
44  ret = "/usr/lib/sysimage/rpm";
45  WAR << "Looks like rpm has no %{_dbpath} set!?! Assuming " << ret << endl;
46  }
47  return ret;
48  }();
49  return _val;
50  }
51 
52  inline Pathname suggestedDbPath( const Pathname & root_r )
53  {
54  if ( PathInfo( root_r ).isDir() ) {
55  // If a known dbpath exsists, we continue to use it
56  for ( auto p : { "/var/lib/rpm", "/usr/lib/sysimage/rpm" } ) {
57  if ( PathInfo( root_r/p, PathInfo::LSTAT ).isDir() ) {
58  MIL << "Suggest existing database at " << dumpPath( root_r, p ) << endl;
59  return p;
60  }
61  }
62  }
63  const Pathname & defaultDbPath { rpmDefaultDbPath() };
64  MIL << "Suggest rpm dbpath " << dumpPath( root_r, defaultDbPath ) << endl;
65  return defaultDbPath;
66  }
67 
68  inline Pathname sanitizedDbPath( const Pathname & root_r, const Pathname & dbPath_r )
69  { return dbPath_r.empty() ? suggestedDbPath( root_r ) : dbPath_r; }
70 
71  inline bool dbExists( const Pathname & root_r, const Pathname & dbPath_r )
72  {
73  Pathname dbdir { root_r / sanitizedDbPath( root_r, dbPath_r ) };
74  return PathInfo(dbdir).isDir() && ( PathInfo(dbdir/"Packages").isFile() || PathInfo(dbdir/"Packages.db").isFile() );
75  }
76 
77  } // namespace internal
78 
80 //
81 // CLASS NAME : librpmDb (ststic interface)
82 //
84 
86 //
87 // CLASS NAME : librpmDb::D
92 {
93  D ( const D & ) = delete; // NO COPY!
94  D & operator=( const D & ) = delete; // NO ASSIGNMENT!
95  D(D &&) = delete;
96  D &operator=(D &&) = delete;
97 public:
98 
99  const Pathname _root; // root directory for all operations
100  const Pathname _dbPath; // directory (below root) that contains the rpmdb
101  AutoDispose<rpmts> _ts; // transaction handle, includes database
102 
103  friend std::ostream & operator<<( std::ostream & str, const D & obj )
104  { return str << "{" << dumpPath( obj._root, obj._dbPath ) << "}"; }
105 
106  D( Pathname root_r, Pathname dbPath_r, bool readonly_r )
107  : _root { std::move(root_r) }
108  , _dbPath { std::move(dbPath_r) }
109  , _ts { nullptr }
110  {
111  _ts = AutoDispose<rpmts>( ::rpmtsCreate(), ::rpmtsFree );
112  ::rpmtsSetRootDir( _ts, _root.c_str() );
113 
114  // open database (creates a missing one on the fly)
115  OnScopeExit cleanup;
116  if ( _dbPath != internal::rpmDefaultDbPath() ) {
117  // temp set %{_dbpath} macro for rpmtsOpenDB
118  cleanup.setDispose( &macroResetDbpath );
120  }
121  int res = ::rpmtsOpenDB( _ts, (readonly_r ? O_RDONLY : O_RDWR ) );
122  if ( res ) {
123  ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
124  ZYPP_THROW(RpmDbOpenException(_root, _dbPath));
125  }
126  }
127 
128 private:
129  static void macroSetDbpath( const Pathname & dppath_r )
130  { ::addMacro( NULL, "_dbpath", NULL, dppath_r.asString().c_str(), RMIL_CMDLINE ); }
131 
132  static void macroResetDbpath()
134 };
135 
137 
139 {
140  static bool initialized = false;
141 
142  if ( initialized )
143  return true;
144 
145  int rc = ::rpmReadConfigFiles( NULL, NULL );
146  if ( rc )
147  {
148  ERR << "rpmReadConfigFiles returned " << rc << endl;
149  return false;
150  }
151 
152  initialized = true; // Necessary to be able to use exand() in rpmDefaultDbPath().
153  const Pathname & rpmDefaultDbPath { internal::rpmDefaultDbPath() }; // init rpmDefaultDbPath()!
154  MIL << "librpm init done: (_target:" << expand( "%{_target}" ) << ") (_dbpath:" << rpmDefaultDbPath << ")" << endl;
155  return initialized;
156 }
157 
158 std::string librpmDb::expand( const std::string & macro_r )
159 {
160  if ( ! globalInit() )
161  return macro_r; // unexpanded
162 
163  AutoFREE<char> val = ::rpmExpand( macro_r.c_str(), NULL );
164  if ( val )
165  return std::string( val );
166 
167  return std::string();
168 }
169 
171 {
172  if ( ! root_r.absolute() )
173  ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
174 
175  // initialize librpm (for rpmDefaultDbPath)
176  if ( ! globalInit() )
178 
179  return internal::suggestedDbPath( root_r );
180 }
181 
182 bool librpmDb::dbExists( const Pathname & root_r, const Pathname & dbPath_r )
183 {
184  if ( ! root_r.absolute() )
185  ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
186 
187  // initialize librpm (for rpmDefaultDbPath)
188  if ( ! globalInit() )
190 
191  return internal::dbExists( root_r, dbPath_r );
192 }
193 
194 librpmDb::constPtr librpmDb::dbOpenIf( const Pathname & root_r, const Pathname & dbPath_r )
195 { return dbAccess( root_r, dbPath_r, /*create_r*/false ); }
196 
197 librpmDb::constPtr librpmDb::dbOpenCreate( const Pathname & root_r, const Pathname & dbPath_r )
198 { return dbAccess( root_r, dbPath_r, /*create_r*/true ); }
199 
200 librpmDb::constPtr librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_rx, bool create_r )
201 {
202  if ( ! root_r.absolute() )
203  ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
204 
205  // initialize librpm (for rpmDefaultDbPath)
206  if ( ! globalInit() )
208 
209  Pathname dbPath { internal::sanitizedDbPath( root_r, dbPath_rx ) };
210  bool dbExists = internal::dbExists( root_r, dbPath );
211 
212  if ( not create_r && not dbExists ) {
213  WAR << "NoOpen not existing database " << dumpPath( root_r, dbPath ) << endl;
214  return nullptr;
215  }
216  MIL << (dbExists?"Open":"Create") << " database " << dumpPath( root_r, dbPath ) << endl;
217  return new librpmDb( root_r, dbPath, /*readonly*/true );
218 }
219 
221 //
222 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
223 //
225 
226 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
227 : _d( * new D( root_r, dbPath_r, readonly_r ) )
228 {}
229 
231 {
232  MIL << "Close database " << *this << endl;
233  delete &_d;
234 }
235 
236 void librpmDb::unref_to( unsigned refCount_r ) const
237 { return; } // if ( refCount_r == 1 ) { tbd if we hold a static reference as weak ptr. }
238 
239 const Pathname & librpmDb::root() const
240 { return _d._root; }
241 
242 const Pathname & librpmDb::dbPath() const
243 { return _d._dbPath; }
244 
245 std::ostream & librpmDb::dumpOn( std::ostream & str ) const
246 { return ReferenceCounted::dumpOn( str ) << _d; }
247 
249 //
250 // CLASS NAME : librpmDb::db_const_iterator::D
251 //
252 class librpmDb::db_const_iterator::D
253 {
254  D & operator=( const D & ) = delete; // NO ASSIGNMENT!
255  D ( const D & ) = delete; // NO COPY!
256  D(D &&);
257  D &operator=(D &&) = delete;
258 
259 public:
260 
264 
266  D()
267  {}
268 
270  D( const Pathname & root_r, const Pathname & dbPath_r = Pathname() )
271  {
272  try {
273  _dbptr = librpmDb::dbOpenIf( root_r, dbPath_r );
274  }
275  catch ( const RpmException & excpt_r ) {
276  ZYPP_CAUGHT(excpt_r);
277  }
278  if ( not _dbptr ) {
279  WAR << "No database access: " << dumpPath( root_r, dbPath_r ) << endl;
280  }
281  }
282 
287  bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
288  {
289  destroy();
290  if ( ! _dbptr )
291  return false;
292  _mi = AutoDispose<rpmdbMatchIterator>( ::rpmtsInitIterator( _dbptr->_d._ts, rpmTag(rpmtag), keyp, keylen ), ::rpmdbFreeIterator );
293  return _mi;
294  }
295 
299  bool destroy()
300  {
301  _mi.reset();
302  _hptr.reset();
303  return false;
304  }
305 
310  bool advance()
311  {
312  if ( !_mi )
313  return false;
314  Header h = ::rpmdbNextIterator( _mi );
315  if ( ! h )
316  {
317  destroy();
318  return false;
319  }
320  _hptr = new RpmHeader( h );
321  return true;
322  }
323 
327  bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
328  {
329  if ( ! create( rpmtag, keyp, keylen ) )
330  return false;
331  return advance();
332  }
333 
338  bool set( int off_r )
339  {
340  if ( ! create( RPMDBI_PACKAGES ) )
341  return false;
342 #ifdef RPMFILEITERMAX // since rpm.4.12
343  ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
344 #else
345  ::rpmdbAppendIterator( _mi, &off_r, 1 );
346 #endif
347  return advance();
348  }
349 
350  unsigned offset()
351  {
352  return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
353  }
354 
355  int size()
356  {
357  if ( !_mi )
358  return 0;
359  int ret = ::rpmdbGetIteratorCount( _mi );
360  return( ret ? ret : -1 ); // -1: sequential access
361  }
362 };
363 
365 
367 //
368 // CLASS NAME : librpmDb::Ptr::db_const_iterator
369 //
371 
372 #if LEGACY(1735)
373 // Former ZYPP_API used this as default ctor (dbptr_r == nullptr).
374 // (dbptr_r!=nullptr) is not possible because librpmDb is not in ZYPP_API.
375 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
376 : db_const_iterator( "/" )
377 {}
378 #endif
379 
380 librpmDb::db_const_iterator::db_const_iterator()
381 : _d( * new D( "/" ) )
382 { findAll(); }
383 
384 librpmDb::db_const_iterator::db_const_iterator( const Pathname & root_r )
385 : _d( * new D( root_r ) )
386 { findAll(); }
387 
388 librpmDb::db_const_iterator::db_const_iterator( const Pathname & root_r, const Pathname & dbPath_r )
389 : _d( * new D( root_r, dbPath_r ) )
390 { findAll(); }
391 
392 librpmDb::db_const_iterator::db_const_iterator( std::nullptr_t )
393 : _d( * new D() )
394 {}
395 
396 librpmDb::db_const_iterator::~db_const_iterator()
397 { delete &_d; }
398 
399 bool librpmDb::db_const_iterator::hasDB() const
400 { return bool(_d._dbptr); }
401 
402 void librpmDb::db_const_iterator::operator++()
403 { _d.advance(); }
404 
405 unsigned librpmDb::db_const_iterator::dbHdrNum() const
406 { return _d.offset(); }
407 
408 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
409 { return _d._hptr; }
410 
411 std::ostream & operator<<( std::ostream & str, const librpmDb::db_const_iterator & obj )
412 { return str << "db_const_iterator(" << obj._d._dbptr << ")"; }
413 
414 bool librpmDb::db_const_iterator::findAll()
415 { return _d.init( RPMDBI_PACKAGES ); }
416 
417 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
418 { return _d.init( RPMTAG_BASENAMES, file_r.c_str() ); }
419 
420 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
421 { return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() ); }
422 
423 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
424 { return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() ); }
425 
426 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
427 { return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() ); }
428 
429 bool librpmDb::db_const_iterator::findByName( const std::string & name_r )
430 { return _d.init( RPMTAG_NAME, name_r.c_str() ); }
431 
432 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r )
433 {
434  if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
435  return false;
436 
437  if ( _d.size() == 1 )
438  return true;
439 
440  // check installtime on multiple entries
441  int match = 0;
442  time_t itime = 0;
443  for ( ; operator*(); operator++() )
444  {
445  if ( operator*()->tag_installtime() > itime )
446  {
447  match = _d.offset();
448  itime = operator*()->tag_installtime();
449  }
450  }
451 
452  return _d.set( match );
453 }
454 
455 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
456 {
457  if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
458  return false;
459 
460  for ( ; operator*(); operator++() )
461  {
462  if ( ed_r == operator*()->tag_edition() )
463  {
464  int match = _d.offset();
465  return _d.set( match );
466  }
467  }
468 
469  return _d.destroy();
470 }
471 
472 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
473 {
474  if ( ! which_r )
475  return _d.destroy();
476 
477  return findPackage( which_r->name(), which_r->edition() );
478 }
479 
480 } // namespace rpm
481 } // namespace target
482 } // namespace zypp
static void macroResetDbpath()
Definition: librpmDb.cc:132
#define MIL
Definition: Logger.h:100
TraitsType::constPtrType constPtr
Definition: Package.h:39
intrusive_ptr< const RpmHeader > constPtr
Definition: RpmHeader.h:65
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:424
static std::string expand(const std::string &macro_r)
Definition: librpmDb.cc:158
bool advance()
Advance to the first/next header in iterator.
Definition: librpmDb.cc:310
AutoDispose< rpmts > _ts
Definition: librpmDb.cc:101
void reset()
Reset to default Ctor values.
Definition: AutoDispose.h:150
bool set(int off_r)
Create an itertator that contains the database entry located at off_r, and advance to the 1st header...
Definition: librpmDb.cc:338
const char * c_str() const
String representation.
Definition: Pathname.h:112
String related utilities and Regular expression matching.
bool findPackage(const std::string &name_r)
Find package by name.
const RpmHeader::constPtr & operator*() const
Returns the current RpmHeader::constPtr or NULL, if no more entries available.
static bool dbExists(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Definition: librpmDb.cc:182
static librpmDb::constPtr dbOpenCreate(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Assert the rpmdb below the system at root_r exists.
Definition: librpmDb.cc:197
static void macroSetDbpath(const Pathname &dppath_r)
Definition: librpmDb.cc:129
~librpmDb() override
Destructor.
Definition: librpmDb.cc:230
friend std::ostream & operator<<(std::ostream &str, const D &obj)
Definition: librpmDb.cc:103
#define ERR
Definition: Logger.h:102
D(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Open a specific rpmdb if it exists.
Definition: librpmDb.cc:270
std::ostream & dumpOn(std::ostream &str) const override
Dump debug info.
Definition: librpmDb.cc:245
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump &#39;(root_r)sub_r&#39; output,
Definition: librpmDb.h:42
friend std::ostream & operator<<(std::ostream &str, const db_const_iterator &obj)
bool empty() const
Test for an empty path.
Definition: Pathname.h:116
bool findAll()
Reset to iterate all packages.
Subclass to retrieve rpm database content.
const std::string & asString() const
String representation.
Definition: Pathname.h:93
Pathname suggestedDbPath(const Pathname &root_r)
Definition: librpmDb.cc:52
bool dbExists(const Pathname &root_r, const Pathname &dbPath_r)
Definition: librpmDb.cc:71
#define WAR
Definition: Logger.h:101
std::ostream & dumpOn(std::ostream &str, const Capability &obj)
Definition: Capability.cc:580
bool absolute() const
Test for an absolute path.
Definition: Pathname.h:118
const Pathname & root() const
Definition: librpmDb.cc:239
Just inherits Exception to separate media exceptions.
Definition: RpmException.h:38
static librpmDb::constPtr dbOpenIf(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Open the rpmdb below the system at root_r (if it exists).
Definition: librpmDb.cc:194
D(Pathname root_r, Pathname dbPath_r, bool readonly_r)
Definition: librpmDb.cc:106
void setDispose(const Dispose &dispose_r)
Set a new dispose function.
Definition: AutoDispose.h:167
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
void unref_to(unsigned refCount_r) const override
Trigger from Rep, after refCount was decreased.
Definition: librpmDb.cc:236
librpmDb internal database handle
Definition: librpmDb.cc:91
AutoDispose< rpmdbMatchIterator > _mi
Definition: librpmDb.cc:262
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:138
D & operator=(const D &)=delete
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
Pathname sanitizedDbPath(const Pathname &root_r, const Pathname &dbPath_r)
Definition: librpmDb.cc:68
static void dbAccess(librpmDb::Ptr &ptr_r)
INTENTIONALLY UNDEFINED<> because of bug in Ptr classes which allows implicit conversion from librpmD...
const Pathname & dbPath() const
Definition: librpmDb.cc:242
bool init(int rpmtag, const void *keyp=NULL, size_t keylen=0)
Access a dbindex file and advance to the 1st header.
Definition: librpmDb.cc:327
Wrapper class for rpm header struct.
Definition: RpmHeader.h:61
intrusive_ptr< const librpmDb > constPtr
Definition: librpmDb.h:55
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
static Pathname suggestedDbPath(const Pathname &root_r)
Definition: librpmDb.cc:170
bool create(int rpmtag, const void *keyp=NULL, size_t keylen=0)
Let iterator access a dbindex file.
Definition: librpmDb.cc:287
void operator++()
Advance to next RpmHeader::constPtr.
const Pathname & rpmDefaultDbPath()
Definition: librpmDb.cc:39