[Rpm-maint] Rally: minor API requests

Panu Matilainen pmatilai at redhat.com
Thu Nov 15 10:52:10 UTC 2007

On Tue, 13 Nov 2007, Maxim Udushlivy wrote:

> Panu Matilainen wrote:
>>> (1)
>> Sounds entirely reasonable to me, there are a number of users (smartpm, 
>> apt-rpm ...) that would benefit. Whatever the implementation, it needs to 
>> abstract out any backend DB details (as rpm supports BDB and SQLite 
>> backends for the DB)
> The implementation may look this way:
> time_t rpmGetDbMtime(const char * root) {
>   time_t mtime= 0;
>   const char * path= rpmGenPath(root, "%{_dbpath}", 
>   struct stat buf;
>   if(path && Stat(path, &buf) == 0)
>       mtime= buf.st_mtime;
>   _free(path);
>   return mtime;
> }

The problem with this is that we're not really interested in db mtime as 
such, we're interested in "has the database changed since we last looked". 
Mtime is one (fairly unreliable) way to implement it. The way to go would 
be a more abstract rpmtsGetState() or such that returns something - maybe 
a string hash - that clients can store and compare against later on. 
Whether it internally uses mtime or something more sophisticated is 
something API users don't need to know.

> Sample usage:
> void * lock= rpmtsAcquireLock(ts);
> if(lock) {
>   if(cache_mtime != rpmGetDbMtime(NULL)) {
>       // retrieve installed package headers
>       // from RPM DB into application cache
>   }
>   rpmtsFreeLock(lock);
> }
> The remaining problem is that rpmlock.h is not public.

The above guarantees nothing, you might just as well not lock at all.
If you want to protect against rpmdb changing underneath you, explicitly 
open the DB in write-mode to guarantee exclusive access to it:

rpmts ts = rpmtsCreate()
rpmtsOpenDB(ts, O_RDWR)

...and now you have an exclusive lock on the whole db until you close it.

>>> (2)
>> There are a number of issues (API and other things) with rpm's public key 
>> handling that need addressing sooner or later .. concrete API suggestions 
>> welcome.
> The API to supply a custom keyring for rpmts is sufficient to solve (2) I 
> think:
> int rpmtsCustomKeyringAdd(rpmts ts, const byte * pkt, size_t pktlen);
> int rpmtsCustomKeyringReset(rpmts ts);
> Sample usage:
> const byte * pkt= NULL;
> size_t pktlen= 0;
> pgpReadPkts(path_to_gpg_key, &pkt, &pktlen);
> rpmtsCustomKeyringAdd(ts, pkt, pktlen);
> _free(pkt);
> rpmRC rc= rpmReadPackageFile(ts, fd, path_to_rpm, &header);
> if(header && rc==RPMRC_OK) {
>   // package was read successfully using the supplied public key
> }

The rpm "key ring" is the transaction set (and the underlying db) - so you 
should be able to do this already by opening a ts on alternative database 
you use only for the (custom) keys. Something like (from the top of my 
head, certainly not tested)

rpmts ts = rpmtsCreate()
addMacro(NULL, "_dbpath", NULL, "/path/to/custom/keydb", RMIL_DEFAULT);
rpmtsImportPubkey(ts, pkg, pktlen);
rpmRC rc= rpmReadPackageFile(ts, fd, path_to_rpm, &header);
delMacro(NULL, "_dbpath");

Nice, convenient and obvious... probably not :) But should be possible...

 	- Panu -

More information about the Rpm-maint mailing list