libzypp  17.37.5
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() &&
75  ( PathInfo(dbdir/"Packages").isFile() || PathInfo(dbdir/"Packages.db").isFile() || PathInfo(dbdir/"rpmdb.sqlite").isFile() );
76  }
77 
78  } // namespace internal
79 
81 //
82 // CLASS NAME : librpmDb (ststic interface)
83 //
85 
87 //
88 // CLASS NAME : librpmDb::D
93 {
94  D ( const D & ) = delete; // NO COPY!
95  D & operator=( const D & ) = delete; // NO ASSIGNMENT!
96  D(D &&) = delete;
97  D &operator=(D &&) = delete;
98 public:
99 
100  const Pathname _root; // root directory for all operations
101  const Pathname _dbPath; // directory (below root) that contains the rpmdb
102  AutoDispose<rpmts> _ts; // transaction handle, includes database
103 
104  friend std::ostream & operator<<( std::ostream & str, const D & obj )
105  { return str << "{" << dumpPath( obj._root, obj._dbPath ) << "}"; }
106 
107  D( Pathname root_r, Pathname dbPath_r, bool readonly_r )
108  : _root { std::move(root_r) }
109  , _dbPath { std::move(dbPath_r) }
110  , _ts { nullptr }
111  {
112  _ts = AutoDispose<rpmts>( ::rpmtsCreate(), ::rpmtsFree );
113  ::rpmtsSetRootDir( _ts, _root.c_str() );
114 
115  // open database (creates a missing one on the fly)
116  OnScopeExit cleanup;
117  if ( _dbPath != internal::rpmDefaultDbPath() ) {
118  // temp set %{_dbpath} macro for rpmtsOpenDB
119  cleanup.setDispose( &macroResetDbpath );
121  }
122  int res = ::rpmtsOpenDB( _ts, (readonly_r ? O_RDONLY : O_RDWR ) );
123  if ( res ) {
124  ERR << "rpmdbOpen error(" << res << "): " << *this << endl;
125  ZYPP_THROW(RpmDbOpenException(_root, _dbPath));
126  }
127  }
128 
129 private:
130  static void macroSetDbpath( const Pathname & dppath_r )
131  { ::addMacro( NULL, "_dbpath", NULL, dppath_r.asString().c_str(), RMIL_CMDLINE ); }
132 
133  static void macroResetDbpath()
135 };
136 
138 
140 {
141  static bool initialized = false;
142 
143  if ( initialized )
144  return true;
145 
146  int rc = ::rpmReadConfigFiles( NULL, NULL );
147  if ( rc )
148  {
149  ERR << "rpmReadConfigFiles returned " << rc << endl;
150  return false;
151  }
152 
153  initialized = true; // Necessary to be able to use exand() in rpmDefaultDbPath().
154  const Pathname & rpmDefaultDbPath { internal::rpmDefaultDbPath() }; // init rpmDefaultDbPath()!
155  MIL << "librpm init done: (_target:" << expand( "%{_target}" ) << ") (_dbpath:" << rpmDefaultDbPath << ")" << endl;
156  return initialized;
157 }
158 
159 std::string librpmDb::expand( const std::string & macro_r )
160 {
161  if ( ! globalInit() )
162  return macro_r; // unexpanded
163 
164  AutoFREE<char> val = ::rpmExpand( macro_r.c_str(), NULL );
165  if ( val )
166  return std::string( val );
167 
168  return std::string();
169 }
170 
172 {
173  if ( ! root_r.absolute() )
174  ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
175 
176  // initialize librpm (for rpmDefaultDbPath)
177  if ( ! globalInit() )
179 
180  return internal::suggestedDbPath( root_r );
181 }
182 
183 bool librpmDb::dbExists( const Pathname & root_r, const Pathname & dbPath_r )
184 {
185  if ( ! root_r.absolute() )
186  ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
187 
188  // initialize librpm (for rpmDefaultDbPath)
189  if ( ! globalInit() )
191 
192  return internal::dbExists( root_r, dbPath_r );
193 }
194 
195 librpmDb::constPtr librpmDb::dbOpenIf( const Pathname & root_r, const Pathname & dbPath_r )
196 { return dbAccess( root_r, dbPath_r, /*create_r*/false ); }
197 
198 librpmDb::constPtr librpmDb::dbOpenCreate( const Pathname & root_r, const Pathname & dbPath_r )
199 { return dbAccess( root_r, dbPath_r, /*create_r*/true ); }
200 
201 librpmDb::constPtr librpmDb::dbAccess( const Pathname & root_r, const Pathname & dbPath_rx, bool create_r )
202 {
203  if ( ! root_r.absolute() )
204  ZYPP_THROW(RpmInvalidRootException( root_r, "" ));
205 
206  // initialize librpm (for rpmDefaultDbPath)
207  if ( ! globalInit() )
209 
210  Pathname dbPath { internal::sanitizedDbPath( root_r, dbPath_rx ) };
211  bool dbExists = internal::dbExists( root_r, dbPath );
212 
213  if ( not create_r && not dbExists ) {
214  WAR << "NoOpen not existing database " << dumpPath( root_r, dbPath ) << endl;
215  return nullptr;
216  }
217  MIL << (dbExists?"Open":"Create") << " database " << dumpPath( root_r, dbPath ) << endl;
218  return new librpmDb( root_r, dbPath, /*readonly*/true );
219 }
220 
222 //
223 // CLASS NAME : librpmDb (internal database handle interface (nonstatic))
224 //
226 
227 librpmDb::librpmDb( const Pathname & root_r, const Pathname & dbPath_r, bool readonly_r )
228 : _d( * new D( root_r, dbPath_r, readonly_r ) )
229 {}
230 
232 {
233  MIL << "Close database " << *this << endl;
234  delete &_d;
235 }
236 
237 void librpmDb::unref_to( unsigned refCount_r ) const
238 { return; } // if ( refCount_r == 1 ) { tbd if we hold a static reference as weak ptr. }
239 
240 const Pathname & librpmDb::root() const
241 { return _d._root; }
242 
243 const Pathname & librpmDb::dbPath() const
244 { return _d._dbPath; }
245 
246 std::ostream & librpmDb::dumpOn( std::ostream & str ) const
247 { return ReferenceCounted::dumpOn( str ) << _d; }
248 
250 //
251 // CLASS NAME : librpmDb::db_const_iterator::D
252 //
253 class librpmDb::db_const_iterator::D
254 {
255  D & operator=( const D & ) = delete; // NO ASSIGNMENT!
256  D ( const D & ) = delete; // NO COPY!
257  D(D &&);
258  D &operator=(D &&) = delete;
259 
260 public:
261 
265 
267  D()
268  {}
269 
271  D( const Pathname & root_r, const Pathname & dbPath_r = Pathname() )
272  {
273  try {
274  _dbptr = librpmDb::dbOpenIf( root_r, dbPath_r );
275  }
276  catch ( const RpmException & excpt_r ) {
277  ZYPP_CAUGHT(excpt_r);
278  }
279  if ( not _dbptr ) {
280  WAR << "No database access: " << dumpPath( root_r, dbPath_r ) << endl;
281  }
282  }
283 
288  bool create( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
289  {
290  destroy();
291  if ( ! _dbptr )
292  return false;
293  _mi = AutoDispose<rpmdbMatchIterator>( ::rpmtsInitIterator( _dbptr->_d._ts, rpmTag(rpmtag), keyp, keylen ), ::rpmdbFreeIterator );
294  return _mi;
295  }
296 
300  bool destroy()
301  {
302  _mi.reset();
303  _hptr.reset();
304  return false;
305  }
306 
311  bool advance()
312  {
313  if ( !_mi )
314  return false;
315  Header h = ::rpmdbNextIterator( _mi );
316  if ( ! h )
317  {
318  destroy();
319  return false;
320  }
321  _hptr = new RpmHeader( h );
322  return true;
323  }
324 
328  bool init( int rpmtag, const void * keyp = NULL, size_t keylen = 0 )
329  {
330  if ( ! create( rpmtag, keyp, keylen ) )
331  return false;
332  return advance();
333  }
334 
339  bool set( int off_r )
340  {
341  if ( ! create( RPMDBI_PACKAGES ) )
342  return false;
343 #ifdef RPMFILEITERMAX // since rpm.4.12
344  ::rpmdbAppendIterator( _mi, (const unsigned *)&off_r, 1 );
345 #else
346  ::rpmdbAppendIterator( _mi, &off_r, 1 );
347 #endif
348  return advance();
349  }
350 
351  unsigned offset()
352  {
353  return( _mi ? ::rpmdbGetIteratorOffset( _mi ) : 0 );
354  }
355 
356  int size()
357  {
358  if ( !_mi )
359  return 0;
360  int ret = ::rpmdbGetIteratorCount( _mi );
361  return( ret ? ret : -1 ); // -1: sequential access
362  }
363 };
364 
366 
368 //
369 // CLASS NAME : librpmDb::Ptr::db_const_iterator
370 //
372 
373 #if LEGACY(1735)
374 // Former ZYPP_API used this as default ctor (dbptr_r == nullptr).
375 // (dbptr_r!=nullptr) is not possible because librpmDb is not in ZYPP_API.
376 librpmDb::db_const_iterator::db_const_iterator( librpmDb::constPtr dbptr_r )
377 : db_const_iterator( "/" )
378 {}
379 #endif
380 
381 librpmDb::db_const_iterator::db_const_iterator()
382 : _d( * new D( "/" ) )
383 { findAll(); }
384 
385 librpmDb::db_const_iterator::db_const_iterator( const Pathname & root_r )
386 : _d( * new D( root_r ) )
387 { findAll(); }
388 
389 librpmDb::db_const_iterator::db_const_iterator( const Pathname & root_r, const Pathname & dbPath_r )
390 : _d( * new D( root_r, dbPath_r ) )
391 { findAll(); }
392 
393 librpmDb::db_const_iterator::db_const_iterator( std::nullptr_t )
394 : _d( * new D() )
395 {}
396 
397 librpmDb::db_const_iterator::~db_const_iterator()
398 { delete &_d; }
399 
400 bool librpmDb::db_const_iterator::hasDB() const
401 { return bool(_d._dbptr); }
402 
403 void librpmDb::db_const_iterator::operator++()
404 { _d.advance(); }
405 
406 unsigned librpmDb::db_const_iterator::dbHdrNum() const
407 { return _d.offset(); }
408 
409 const RpmHeader::constPtr & librpmDb::db_const_iterator::operator*() const
410 { return _d._hptr; }
411 
412 std::ostream & operator<<( std::ostream & str, const librpmDb::db_const_iterator & obj )
413 { return str << "db_const_iterator(" << obj._d._dbptr << ")"; }
414 
415 bool librpmDb::db_const_iterator::findAll()
416 { return _d.init( RPMDBI_PACKAGES ); }
417 
418 bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
419 { return _d.init( RPMTAG_BASENAMES, file_r.c_str() ); }
420 
421 bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
422 { return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() ); }
423 
424 bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
425 { return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() ); }
426 
427 bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
428 { return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() ); }
429 
430 bool librpmDb::db_const_iterator::findByName( const std::string & name_r )
431 { return _d.init( RPMTAG_NAME, name_r.c_str() ); }
432 
433 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r )
434 {
435  if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
436  return false;
437 
438  if ( _d.size() == 1 )
439  return true;
440 
441  // check installtime on multiple entries
442  int match = 0;
443  time_t itime = 0;
444  for ( ; operator*(); operator++() )
445  {
446  if ( operator*()->tag_installtime() > itime )
447  {
448  match = _d.offset();
449  itime = operator*()->tag_installtime();
450  }
451  }
452 
453  return _d.set( match );
454 }
455 
456 bool librpmDb::db_const_iterator::findPackage( const std::string & name_r, const Edition & ed_r )
457 {
458  if ( ! _d.init( RPMTAG_NAME, name_r.c_str() ) )
459  return false;
460 
461  for ( ; operator*(); operator++() )
462  {
463  if ( ed_r == operator*()->tag_edition() )
464  {
465  int match = _d.offset();
466  return _d.set( match );
467  }
468  }
469 
470  return _d.destroy();
471 }
472 
473 bool librpmDb::db_const_iterator::findPackage( const Package::constPtr & which_r )
474 {
475  if ( ! which_r )
476  return _d.destroy();
477 
478  return findPackage( which_r->name(), which_r->edition() );
479 }
480 
481 } // namespace rpm
482 } // namespace target
483 } // namespace zypp
static void macroResetDbpath()
Definition: librpmDb.cc:133
#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:459
static std::string expand(const std::string &macro_r)
Definition: librpmDb.cc:159
bool advance()
Advance to the first/next header in iterator.
Definition: librpmDb.cc:311
AutoDispose< rpmts > _ts
Definition: librpmDb.cc:102
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:339
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:183
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:198
static void macroSetDbpath(const Pathname &dppath_r)
Definition: librpmDb.cc:130
~librpmDb() override
Destructor.
Definition: librpmDb.cc:231
friend std::ostream & operator<<(std::ostream &str, const D &obj)
Definition: librpmDb.cc:104
#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:271
std::ostream & dumpOn(std::ostream &str) const override
Dump debug info.
Definition: librpmDb.cc:246
_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:240
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:195
D(Pathname root_r, Pathname dbPath_r, bool readonly_r)
Definition: librpmDb.cc:107
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:475
void unref_to(unsigned refCount_r) const override
Trigger from Rep, after refCount was decreased.
Definition: librpmDb.cc:237
librpmDb internal database handle
Definition: librpmDb.cc:92
AutoDispose< rpmdbMatchIterator > _mi
Definition: librpmDb.cc:263
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition: librpmDb.cc:139
D & operator=(const D &)=delete
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:225
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:243
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:328
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:171
bool create(int rpmtag, const void *keyp=NULL, size_t keylen=0)
Let iterator access a dbindex file.
Definition: librpmDb.cc:288
void operator++()
Advance to next RpmHeader::constPtr.
const Pathname & rpmDefaultDbPath()
Definition: librpmDb.cc:39