Discussion:
problem comparing capability version strings
Dave Peterson
2008-04-10 02:11:24 UTC
Permalink
Hi,

I have a question about capability version string comparisons.
Using RPM library calls, I examine the following Centos 5
packages:

package A: GConf2-devel-2.14.0-9.el5.i386.rpm
package B: GConf2-2.14.0-9.el5.i386.rpm

I see that one capability required by A is the following:

capability name: GConf2
capability version: 2.14.0
flags: RPMSENSE_EQUAL

I also see that one capability provided by B is the following:

capability name: GConf2
capability version: 2.14.0-9.el5
flags: RPMSENSE_EQUAL

To see if the GConf2 capability provided by B satisfies A's
requirement, I call rpmvercmp() as follows:

int result = rpmvercmp("2.14.0", "2.14.0-9.el5");

The return value is -1, indicating that "2.14.0-9.el5" is newer
than "2.14.0". Since the "flags" value for A is RPMSENSE_EQUAL,
and rpmvercmp() says that the version strings are not equal, I
conclude that the GConf2 capability provided by B does not
satisfy the GConf2 dependency required by A. Looking at the
packages installed on my own machine, I observe the following:

$ rpm -qa | grep GConf2
GConf2-2.14.0-9.el5
GConf2-devel-2.14.0-9.el5
$
$ rpm -q --provides GConf2-2.14.0-9.el5 | grep '^GConf2'
GConf2 = 2.14.0-9.el5
$
$ rpm -q --requires GConf2-devel-2.14.0-9.el5 | grep '^GConf2'
GConf2 = 2.14.0
$
$ rpm -q --whatprovides GConf2
GConf2-2.14.0-9.el5
$
$ rpm -V GConf2-devel-2.14.0-9.el5
$

It looks like B is the only installed package that provides the
GConf2 capability, and the RPM command doesn't complain that A is
missing any dependencies.

What is going on here? I suspect that the capability versions
"2.14.0" and "2.14.0-9.el5" should be considered equal due to
some usage convention(s) that I am unaware of. Is this correct?
What is the proper way to compare two capability version strings
in order to determine whether a package dependency is satisfied?
Is there one way that is guaranteed to work across all distros,
or does it vary from one distro to another?

Thanks,
Dave
devzero2000
2008-04-10 10:40:22 UTC
Permalink
This situation you describe is normal.

A package -dev generally requires only the NV capability of the primary
package: it generally doesn't depends of the particolar Package Release eg.
the rpm package lifecycle versus principal program lifecycle .

In this case Name=Gconf2 and Version is 2.14.0 (release is 0.el5). So the
package A required dependency (on Version) is OK.

hth
Post by Dave Peterson
Hi,
I have a question about capability version string comparisons.
Using RPM library calls, I examine the following Centos 5
package A: GConf2-devel-2.14.0-9.el5.i386.rpm
package B: GConf2-2.14.0-9.el5.i386.rpm
capability name: GConf2
capability version: 2.14.0
flags: RPMSENSE_EQUAL
capability name: GConf2
capability version: 2.14.0-9.el5
flags: RPMSENSE_EQUAL
To see if the GConf2 capability provided by B satisfies A's
int result = rpmvercmp("2.14.0", "2.14.0-9.el5");
The return value is -1, indicating that "2.14.0-9.el5" is newer
than "2.14.0". Since the "flags" value for A is RPMSENSE_EQUAL,
and rpmvercmp() says that the version strings are not equal, I
conclude that the GConf2 capability provided by B does not
satisfy the GConf2 dependency required by A. Looking at the
$ rpm -qa | grep GConf2
GConf2-2.14.0-9.el5
GConf2-devel-2.14.0-9.el5
$
$ rpm -q --provides GConf2-2.14.0-9.el5 | grep '^GConf2'
GConf2 = 2.14.0-9.el5
$
$ rpm -q --requires GConf2-devel-2.14.0-9.el5 | grep '^GConf2'
GConf2 = 2.14.0
$
$ rpm -q --whatprovides GConf2
GConf2-2.14.0-9.el5
$
$ rpm -V GConf2-devel-2.14.0-9.el5
$
It looks like B is the only installed package that provides the
GConf2 capability, and the RPM command doesn't complain that A is
missing any dependencies.
What is going on here? I suspect that the capability versions
"2.14.0" and "2.14.0-9.el5" should be considered equal due to
some usage convention(s) that I am unaware of. Is this correct?
What is the proper way to compare two capability version strings
in order to determine whether a package dependency is satisfied?
Is there one way that is guaranteed to work across all distros,
or does it vary from one distro to another?
Thanks,
Dave
_______________________________________________
Rpm-list mailing list
https://www.redhat.com/mailman/listinfo/rpm-list
Jeff Johnson
2008-04-19 19:30:08 UTC
Permalink
Post by Dave Peterson
To see if the GConf2 capability provided by B satisfies A's
int result = rpmvercmp("2.14.0", "2.14.0-9.el5");
The problem is likely conceptual.

rpmvercmp compares strings according to rpm's comparison rules.

However rpm uses the triple {Epoch,Version,Release} to determine newer.

That means that rpmvercmp is called multiple times (Epoch is always a digit
string,
strcmp on zero-padded strings is used for infinite precision, but the
comparison
rules for digit-only strings do not need to use rpmvercmp). rpmvervmp is
definitely
called for each of Version and Release.

Your example is comparing a Version "2.14.0" with a Version-Release
"2.14.0-9.el5".

That needs to be done by splitting on the '-' in "2.14.0-9.el5" and calling
rpmvercmp
twice.

You are still likely to be surprised by the results.

rpmvercmp basically tries to compare alphas with alphas, and digits with
digits,
because originally (before YYYYMMDDhhmmss digit strings were noticed to
exceed 32 bits) compared by converting to ints.

That's the sensible part.

The scwewy part(s) of rpmvercmp include the following:
1) leading 0's are ignored. e.g. 5.000000000003 is greater than 5.2
because 3 > 2
2) all punctuation is ignored and treated as equivalent. so 5.2 and 5_2
are equal.
and (finally, this is the one that you will be surprised at)
3) mixed mode (as in digit string compared to something other than digit
string) is reversed
from the comparison order one would expect. But its very hard to expect a
result from
a comparison between something and nothing, consider what happens to
strcmp
if fed NULL or "", two forms of expressing nothing.

All well known flaws, been there forever, nothing can be done without
coordinating the
change, which is bloody unlikely to happen.

hth

73 de Jeff
Dave Peterson
2008-04-24 00:08:21 UTC
Permalink
Ok, thanks for the info! I recently discovered that I can use
rpmdsSingle()
to manufacture an rpmds object, and then compare rpmds objects using
rpmdsCompare(). My code looks roughly like this (with some error
checking
omitted to keep it short):

struct DepInfo
{ rpmTag tag;
const char* n; // name
const char* evr; // epoch version release
int_32 flags;
};

int compare(struct DepInfo* d1, struct DepInfo* d2)
{ rpmds ds1, ds2;
int result;

ds1 = rpmdsSingle(d1->tag, d1->n, d1->evr, d1->flags);
ds2 = rpmdsSingle(d2->tag, d2->n, d2->evr, d2->flags);
ds1 = rpmdsInit(ds1); rpmdsNext(ds1);
ds2 = rpmdsInit(ds2); rpmdsNext(ds2);
result = rpmdsCompare(ds1, ds2);
rpmdsFree(ds1); rpmdsFree(ds2);
return result;
}

This type of approach seems to work for me. I guess rpmdsCompare()
is probably calling rpmvercmp() internally to compare pieces of the
capability version strings.

Dave
Post by Jeff Johnson
The problem is likely conceptual.
rpmvercmp compares strings according to rpm's comparison rules.
However rpm uses the triple {Epoch,Version,Release} to determine newer.
That means that rpmvercmp is called multiple times (Epoch is always a
digit string,
Post by Jeff Johnson
strcmp on zero-padded strings is used for infinite precision, but the
comparison
Post by Jeff Johnson
rules for digit-only strings do not need to use rpmvercmp). rpmvervmp
is definitely
Post by Jeff Johnson
called for each of Version and Release.
Your example is comparing a Version "2.14.0" with a Version-Release
"2.14.0-9.el5".
Post by Jeff Johnson
That needs to be done by splitting on the '-' in "2.14.0-9.el5" and
calling rpmvercmp
Post by Jeff Johnson
twice.
You are still likely to be surprised by the results.
rpmvercmp basically tries to compare alphas with alphas, and digits
with digits,
Post by Jeff Johnson
because originally (before YYYYMMDDhhmmss digit strings were noticed to
exceed 32 bits) compared by converting to ints.
That's the sensible part.
1) leading 0's are ignored. e.g. 5.000000000003 is greater than 5.2
because 3 > 2
Post by Jeff Johnson
2) all punctuation is ignored and treated as equivalent. so 5.2 and
5_2 are equal.
Post by Jeff Johnson
and (finally, this is the one that you will be surprised at)
3) mixed mode (as in digit string compared to something other than
digit string) is reversed
Post by Jeff Johnson
from the comparison order one would expect. But its very hard to
expect a result from
Post by Jeff Johnson
a comparison between something and nothing, consider what happens
to strcmp
Post by Jeff Johnson
if fed NULL or "", two forms of expressing nothing.
All well known flaws, been there forever, nothing can be done without
coordinating the
Post by Jeff Johnson
change, which is bloody unlikely to happen.
hth
73 de Jeff
Loading...