libzypp 17.37.17
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>
23
24#undef ZYPP_BASE_LOGGER_LOGGROUP
25#define ZYPP_BASE_LOGGER_LOGGROUP "librpmDb"
26
27using std::endl;
28
29namespace zypp
30{
31namespace target
32{
33namespace 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;
98public:
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;
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;
126 }
127 }
128
129private:
130 static void macroSetDbpath( const Pathname & dppath_r )
131 { ::addMacro( NULL, "_dbpath", NULL, dppath_r.asString().c_str(), RMIL_CMDLINE ); }
132
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
159std::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
183bool 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
195librpmDb::constPtr librpmDb::dbOpenIf( const Pathname & root_r, const Pathname & dbPath_r )
196{ return dbAccess( root_r, dbPath_r, /*create_r*/false ); }
197
199{ return dbAccess( root_r, dbPath_r, /*create_r*/true ); }
200
201librpmDb::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
227librpmDb::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
237void librpmDb::unref_to( unsigned refCount_r ) const
238{ return; } // if ( refCount_r == 1 ) { tbd if we hold a static reference as weak ptr. }
239
241{ return _d._root; }
242
244{ return _d._dbPath; }
245
246std::ostream & librpmDb::dumpOn( std::ostream & str ) const
247{ return ReferenceCounted::dumpOn( str ) << _d; }
248
250//
251// CLASS NAME : librpmDb::db_const_iterator::D
252//
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
260public:
261
265
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.
377: db_const_iterator( "/" )
378{}
379#endif
380
384
386: _d( * new D( root_r ) )
387{ findAll(); }
388
390: _d( * new D( root_r, dbPath_r ) )
391{ findAll(); }
392
394: _d( * new D() )
395{}
396
399
401{ return bool(_d._dbptr); }
402
405
407{ return _d.offset(); }
408
411
412std::ostream & operator<<( std::ostream & str, const librpmDb::db_const_iterator & obj )
413{ return str << "db_const_iterator(" << obj._d._dbptr << ")"; }
414
416{ return _d.init( RPMDBI_PACKAGES ); }
417
418bool librpmDb::db_const_iterator::findByFile( const std::string & file_r )
419{ return _d.init( RPMTAG_BASENAMES, file_r.c_str() ); }
420
421bool librpmDb::db_const_iterator::findByProvides( const std::string & tag_r )
422{ return _d.init( RPMTAG_PROVIDENAME, tag_r.c_str() ); }
423
424bool librpmDb::db_const_iterator::findByRequiredBy( const std::string & tag_r )
425{ return _d.init( RPMTAG_REQUIRENAME, tag_r.c_str() ); }
426
427bool librpmDb::db_const_iterator::findByConflicts( const std::string & tag_r )
428{ return _d.init( RPMTAG_CONFLICTNAME, tag_r.c_str() ); }
429
430bool librpmDb::db_const_iterator::findByName( const std::string & name_r )
431{ return _d.init( RPMTAG_NAME, name_r.c_str() ); }
432
433bool 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
456bool 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
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
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
Edition represents [epoch:]version[-release]
Definition Edition.h:61
TraitsType::constPtrType constPtr
Definition Package.h:39
Wrapper class for stat/lstat.
Definition PathInfo.h:226
bool absolute() const
Test for an absolute path.
Definition Pathname.h:118
const std::string & asString() const
String representation.
Definition Pathname.h:93
bool empty() const
Test for an empty path.
Definition Pathname.h:116
Just inherits Exception to separate media exceptions.
Wrapper class for rpm header struct.
Definition RpmHeader.h:62
intrusive_ptr< const RpmHeader > constPtr
Definition RpmHeader.h:65
librpmDb internal database handle
Definition librpmDb.cc:93
friend std::ostream & operator<<(std::ostream &str, const D &obj)
Definition librpmDb.cc:104
D(Pathname root_r, Pathname dbPath_r, bool readonly_r)
Definition librpmDb.cc:107
AutoDispose< rpmts > _ts
Definition librpmDb.cc:102
D & operator=(const D &)=delete
static void macroSetDbpath(const Pathname &dppath_r)
Definition librpmDb.cc:130
bool create(int rpmtag, const void *keyp=NULL, size_t keylen=0)
Let iterator access a dbindex file.
Definition librpmDb.cc:288
D(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Open a specific rpmdb if it exists.
Definition librpmDb.cc:271
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
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
AutoDispose< rpmdbMatchIterator > _mi
Definition librpmDb.cc:263
bool advance()
Advance to the first/next header in iterator.
Definition librpmDb.cc:311
Subclass to retrieve rpm database content.
Definition librpmDb.h:198
unsigned dbHdrNum() const
Returns the current headers index in database, 0 if no header.
Definition librpmDb.cc:406
bool findByProvides(const std::string &tag_r)
Reset to iterate all packages that provide a certain tag.
Definition librpmDb.cc:421
bool findByName(const std::string &name_r)
Reset to iterate all packages with a certain name.
Definition librpmDb.cc:430
bool findByFile(const std::string &file_r)
Reset to iterate all packages that own a certain file.
Definition librpmDb.cc:418
std::ostream & operator<<(std::ostream &str, const librpmDb::db_const_iterator &obj) ZYPP_API
stream output
Definition librpmDb.cc:412
bool findAll()
Reset to iterate all packages.
Definition librpmDb.cc:415
bool hasDB() const
Whether an underlying rpmdb exists.
Definition librpmDb.cc:400
const RpmHeader::constPtr & operator*() const
Returns the current RpmHeader::constPtr or NULL, if no more entries available.
Definition librpmDb.cc:409
bool findByRequiredBy(const std::string &tag_r)
Reset to iterate all packages that require a certain tag.
Definition librpmDb.cc:424
bool findPackage(const std::string &name_r)
Find package by name.
Definition librpmDb.cc:433
void operator++()
Advance to next RpmHeader::constPtr.
Definition librpmDb.cc:403
bool findByConflicts(const std::string &tag_r)
Reset to iterate all packages that conflict with a certain tag.
Definition librpmDb.cc:427
db_const_iterator() ZYPP_DEPRECATED
Open the default rpmdb below the host system (at /).
Definition librpmDb.cc:381
intrusive_ptr< const librpmDb > constPtr
Definition librpmDb.h:55
const Pathname & dbPath() const
Definition librpmDb.cc:243
const Pathname & root() const
Definition librpmDb.cc:240
static bool globalInit()
Initialize lib librpm (read configfiles etc.).
Definition librpmDb.cc:139
std::ostream & dumpOn(std::ostream &str) const override
Dump debug info.
Definition librpmDb.cc:246
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 std::string expand(const std::string &macro_r)
Definition librpmDb.cc:159
librpmDb(const Pathname &root_r, const Pathname &dbPath_r, bool readonly_r=true)
Private constructor!
Definition librpmDb.cc:227
static void dbAccess(librpmDb::Ptr &ptr_r)
INTENTIONALLY UNDEFINED<\B> because of bug in Ptr classes which allows implicit conversion from librp...
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
~librpmDb() override
Destructor.
Definition librpmDb.cc:231
static Pathname suggestedDbPath(const Pathname &root_r)
Definition librpmDb.cc:171
static bool dbExists(const Pathname &root_r, const Pathname &dbPath_r=Pathname())
Definition librpmDb.cc:183
void unref_to(unsigned refCount_r) const override
Trigger from Rep, after refCount was decreased.
Definition librpmDb.cc:237
Definition Arch.h:364
String related utilities and Regular expression matching.
const Pathname & rpmDefaultDbPath()
Definition librpmDb.cc:39
Pathname suggestedDbPath(const Pathname &root_r)
Definition librpmDb.cc:52
Pathname sanitizedDbPath(const Pathname &root_r, const Pathname &dbPath_r)
Definition librpmDb.cc:68
bool dbExists(const Pathname &root_r, const Pathname &dbPath_r)
Definition librpmDb.cc:71
_dumpPath dumpPath(const Pathname &root_r, const Pathname &sub_r)
dumpPath iomaip to dump '(root_r)sub_r' output,
Definition librpmDb.h:42
Easy-to use interface to the ZYPP dependency resolver.
AutoDispose< void > OnScopeExit
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:475
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition Exception.h:459
#define MIL
Definition Logger.h:100
#define ERR
Definition Logger.h:102
#define WAR
Definition Logger.h:101