RPM Community Forums

Mailing List Message of <rpm-devel>

Re: Arbitrary tags

From: Jeff Johnson <n3npq@mac.com>
Date: Mon 03 Dec 2007 - 00:36:55 CET
Message-Id: <BE8C4E1E-37AE-4A09-B645-DCBD1577C555@mac.com>
Using arbitrary tags in packages likely needs a little explanation
until someplace to document the mess can be identified.

Arbitrary tags are alphabetic strings contained in the macro
     %_arbitrary tags.

Here's what is currently configured by default macros:

     #
     # Colon separated list of permitted arbitrary tag names
     %_arbitrary_tags        Foo:Bar:Baz

To build a package with an arbitrary tag, one simply adds, say,
     Foo: foo value

The string "Foo" is canonicalized, run through a sha-1 digest,
and the least significant 30 bits are OR'd with 0x40000000
to generate the tagno to be used to save the string value in a header.

It's easier to show an example than to explain.

I've built the time package including these lines in time.spec:

     Foo: foo string
     Bar: bar string
     Baz: baz string

After building, the arbitrary tag content can be verified using --yaml
(or --xml if you wish). Here's what should be displayed (as soon
as I fix headerSprintf --yaml/--xml with unknown tags again again):

   Tag_0x47d21531: baz string
   Tag_0x64087297: bar string
   Tag_0x690929d2: foo string

All arbitrary tags whose string name(s) are known can be displayed in  
the usual
fashion using --queryformat:

$ rpm -qp --qf '%{foo}\n%{bar}\n%{baz}\n' time-1.7-30.i386.rpm
foo string
bar string
baz string

The arbitrary tag implementation is largely complete but I expect to  
have to add

     1) a convention to use "Tag_0x12345678" as an alternative nickname
      for accessing arbitrary tags when the original string is unknown.

     2) a generalization to string arrays by mentioning identical  
arbitrary
     tags multiple times

	Foo: this is the 1st value
	Foo: this is the 2nd value
	Foo: this is the 3rd value

     3) generalizations to handle non-string types either by coercion  
prefix hints
     (as YAML does), or by implicit typing rules, e.g. digit strings  
will automagically
      use RPM_UINT32_TYPE to store the value, are both relatively  
simple possibilities.

1) and 2) are likely to happen this week, dunno about 3) yet, the  
problem
of coerced/implicit typing likely needs some further thought before  
committing
to an implementation.

Enjoy!

73 de Jeff



On Dec 2, 2007, at 6:06 PM, Jeff Johnson wrote:

>   RPM Package Manager, CVS Repository
>   http://rpm5.org/cvs/
>    
> ______________________________________________________________________ 
> ______
>
>   Server: rpm5.org                         Name:   Jeff Johnson
>   Root:   /v/rpm/cvs                       Email:  jbj@rpm5.org
>   Module: rpm                              Date:   03-Dec-2007  
> 00:06:03
>   Branch: HEAD                             Handle: 2007120223060101
>
>   Modified files:
>     rpm                     CHANGES
>     rpm/build               parsePreamble.c
>     rpm/rpmdb               hdrfmt.c rpmtag.h tagname.c
>     rpm/rpmio               argv.c argv.h librpmio.vers
>
>   Log:
>     - using tagValue instead permits queries of arbitrary tags.
>     - do binary, not linear, search for tag name/type/value.
>     - lazy arbitrary tag array initialization in rpmTags methods  
> instead.
>
>   Summary:
>     Revision    Changes     Path
>     1.1908      +3  -0      rpm/CHANGES
>     2.151       +4  -19     rpm/build/parsePreamble.c
>     1.48        +13 -3      rpm/rpmdb/hdrfmt.c
>     1.20        +8  -5      rpm/rpmdb/rpmtag.h
>     1.20        +45 -7      rpm/rpmdb/tagname.c
>     1.9         +7  -0      rpm/rpmio/argv.c
>     1.6         +10 -1      rpm/rpmio/argv.h
>     2.20        +1  -0      rpm/rpmio/librpmio.vers
>    
> ______________________________________________________________________ 
> ______
>
>   patch -p0 <<'@@ .'
>   Index: rpm/CHANGES
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r1.1907 -r1.1908 CHANGES
>   --- rpm/CHANGES	2 Dec 2007 20:51:49 -0000	1.1907
>   +++ rpm/CHANGES	2 Dec 2007 23:06:01 -0000	1.1908
>   @@ -1,6 +1,9 @@
>    5.0a4 -> 5.0b1:
>
>    5.0a3 -> 5.0a4:
>   +    - jbj: using tagValue instead permits queries of arbitrary  
> tags.
>   +    - jbj: do binary, not linear, search for tag name/type/value.
>   +    - jbj: lazy arbitrary tag array initialization in rpmTags  
> methods instead.
>        - jbj: eliminate hard-wired static nameBuf for tag strings.
>        - rse: provide RPM version in API via macros RPM_ 
> {VERSION,TIMESTAMP,VENDOR} and functions rpm_ 
> {version,timestamp,vendor}
>        - jbj: pkgio: hdlist readers need RPMRC_NOTFOUND EOF indicator.
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/build/parsePreamble.c
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r2.150 -r2.151 parsePreamble.c
>   --- rpm/build/parsePreamble.c	30 Nov 2007 04:51:30 -0000	2.150
>   +++ rpm/build/parsePreamble.c	2 Dec 2007 23:06:01 -0000	2.151
>   @@ -8,6 +8,7 @@
>    #include <rpmio_internal.h>
>
>    #define	_RPMEVR_INTERNAL
>   +#define	_RPMTAG_INTERNAL	/* XXX rpmTags->aTags */
>    #include <rpmbuild.h>
>    #include "debug.h"
>
>   @@ -874,13 +875,6 @@
>        /*@=nullassign@*/
>    };
>
>   -static int argvStrcasecmp(const void * a, const void * b)
>   -{
>   -    ARGstr_t astr = *(ARGV_t)a;
>   -    ARGstr_t bstr = *(ARGV_t)b;
>   -    return xstrcasecmp(astr, bstr);
>   -}
>   -
>    /**
>     */
>    /*@-boundswrite@*/
>   @@ -909,20 +903,11 @@
>
>        /* Search for arbitrary tags. */
>        if (tagp && p->token == NULL) {
>   -	static ARGV_t aTags = NULL;
>   -	static int oneshot = 0;
>   +	ARGV_t aTags = NULL;
>    	int rc = 1;	/* assume failure */
>
>   -	if (!oneshot) {
>   -	    s = rpmExpand("%{?_arbitrary_tags}", NULL);
>   -	    if (s && *s) {
>   -		(void) argvSplit(&aTags, s, ":");
>   -		if (aTags)
>   -		    (void) argvSort(aTags, NULL);
>   -	    }
>   -	    s = _free(s);
>   -	    oneshot++;
>   -	}
>   +	(void) tagName(0); /* XXX force arbitrary tags to be  
> initialized. */
>   +	aTags = rpmTags->aTags;
>    	if (aTags != NULL && aTags[0] != NULL) {
>    	    ARGV_t av;
>    	    s = tagCanonicalize(spec->line);
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/rpmdb/hdrfmt.c
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r1.47 -r1.48 hdrfmt.c
>   --- rpm/rpmdb/hdrfmt.c	26 Nov 2007 21:05:57 -0000	1.47
>   +++ rpm/rpmdb/hdrfmt.c	2 Dec 2007 23:06:02 -0000	1.48
>   @@ -2047,7 +2047,6 @@
>
>    /**
>     * Return tag name from value.
>   - * @todo bsearch on sorted value table.
>     * @param tbl		tag table
>     * @param val		tag value to find
>     * @retval *typep	tag type (or NULL)
>   @@ -2058,10 +2057,18 @@
>    		/*@null@*/ uint32_t *typep)
>    	/*@modifies *typep @*/
>    {
>   -    static char name[128];
>   +    static char name[128];	/* XXX Ick. */
>        const char * s;
>        char *t;
>
>   +    /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
>   +    if (tbl == NULL || tbl == rpmTagTable) {
>   +	s = tagName(val);
>   +	if (s != NULL && typep != NULL)
>   +	    *typep = tagType(val);
>   +	return s;
>   +    }
>   +
>        for (; tbl->name != NULL; tbl++) {
>    	if (tbl->val == val)
>    	    break;
>   @@ -2081,7 +2088,6 @@
>
>    /**
>     * Return tag value from name.
>   - * @todo bsearch on sorted name table.
>     * @param tbl		tag table
>     * @param name		tag name to find
>     * @return		tag value, 0 on not found
>   @@ -2089,6 +2095,10 @@
>    static uint32_t myTagValue(headerTagTableEntry tbl, const char *  
> name)
>    	/*@*/
>    {
>   +    /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
>   +    if (tbl == NULL || tbl == rpmTagTable)
>   +	return tagValue(name);
>   +
>        for (; tbl->name != NULL; tbl++) {
>    	if (!xstrcasecmp(tbl->name, name))
>    	    return tbl->val;
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/rpmdb/rpmtag.h
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r1.19 -r1.20 rpmtag.h
>   --- rpm/rpmdb/rpmtag.h	29 Nov 2007 19:15:18 -0000	1.19
>   +++ rpm/rpmdb/rpmtag.h	2 Dec 2007 23:06:02 -0000	1.20
>   @@ -499,6 +499,7 @@
>     */
>    #if !defined(SWIG)
>    struct headerTagIndices_s {
>   +/*@relnull@*/
>        int (*loadIndex) (headerTagTableEntry ** ipp, int * np,
>                    int (*cmp) (const void * avp, const void * bvp))
>            /*@ modifies *ipp, *np */;	/*!< Load sorted tag index. */
>   @@ -508,23 +509,25 @@
>        int (*byNameCmp) (const void * avp, const void * bvp)
>            /*@*/;				/*!< Compare entries by name. */
>        rpmTag (*tagValue) (const char * name)
>   -	/*@*/;				/* Return value from name. */
>   +	/*@*/;				/*!< Return value from name. */
>    /*@relnull@*/
>        headerTagTableEntry * byValue;	/*!< rpmTag's sorted by  
> value. */
>        int byValueSize;			/*!< No. of entries. */
>        int (*byValueCmp) (const void * avp, const void * bvp)
>            /*@*/;				/*!< Compare entries by value. */
>        const char * (*tagName) (rpmTag value)
>   -	/*@*/;				/* Return name from value. */
>   +	/*@*/;				/*!< Return name from value. */
>        rpmTag (*tagType) (rpmTag value)
>   -	/*@*/;				/* Return type from value. */
>   +	/*@*/;				/*!< Return type from value. */
>   +    size_t nameBufLen;			/*!< No. bytes allocated for nameBuf. */
>   +    const char ** aTags;		/*!< Arbitrary tags array (ARGV_t) */
>    /*@owned@*/ /*@relnull@*/
>        char * nameBuf;			/* Name buffer. */
>    /*@only@*/
>        char * (*tagCanonicalize) (const char * s)
>   -	/*@*/;				/* Canonicalize an arbitrary string. */
>   +	/*@*/;				/*!< Canonicalize arbitrary string. */
>        rpmTag (*tagGenerate) (const char * s)
>   -	/*@*/;				/* Generate value from name. */
>   +	/*@*/;				/*!< Generate tag from string. */
>    };
>    #endif
>    #endif	/* _RPMTAG_INTERNAL */
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/rpmdb/tagname.c
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r1.19 -r1.20 tagname.c
>   --- rpm/rpmdb/tagname.c	2 Dec 2007 20:51:49 -0000	1.19
>   +++ rpm/rpmdb/tagname.c	2 Dec 2007 23:06:02 -0000	1.20
>   @@ -5,6 +5,8 @@
>    #include "system.h"
>
>    #include <rpmio_internal.h>	/* XXX DIGEST_CTX, xtolower,  
> xstrcasecmp */
>   +#include <rpmmacro.h>
>   +#include <argv.h>
>    #define	_RPMTAG_INTERNAL
>    #include <rpmtag.h>
>    #include "debug.h"
>   @@ -13,6 +15,33 @@
>    /*@access headerTagIndices @*/
>
>    /**
>   + * Load/sort arbitrary tags.
>   + * @retval *argvp	arbitrary tag array
>   + * @return		0 always
>   + */
>   +static int tagLoadATags(ARGV_t * argvp,
>   +		int (*cmp) (const void * avp, const void * bvp))
>   +	/*@modifies *ipp, *np @*/
>   +{
>   +    ARGV_t aTags = NULL;
>   +    char * s = rpmExpand("%{?_arbitrary_tags}", NULL);
>   +
>   +    if (s && *s)
>   +	(void) argvSplit(&aTags, s, ":");
>   +    else
>   +	aTags = xcalloc(1, sizeof(*aTags));
>   +    if (aTags && aTags[0])
>   +	(void) argvSort(aTags, cmp);
>   +    s = _free(s);
>   +
>   +    if (argvp)
>   +	*argvp = aTags;
>   +    else
>   +	aTags = argvFree(aTags);
>   +    return 0;
>   +}
>   +
>   +/**
>     * Compare tag table entries by name.
>     * @param *avp		tag table entry a
>     * @param *bvp		tag table entry b
>   @@ -56,7 +85,7 @@
>    	/*@modifies *ipp, *np @*/
>    {
>        headerTagTableEntry tte, *ip;
>   -    int n = 0;
>   +    size_t n = 0;
>
>        ip = xcalloc(rpmTagTableSize, sizeof(*ip));
>        n = 0;
>   @@ -135,7 +164,7 @@
>        tagLoadIndex,
>        NULL, 0, tagCmpName, _tagValue,
>        NULL, 0, tagCmpValue, _tagName, _tagType,
>   -    NULL, _tagCanonicalize, _tagGenerate
>   +    256, NULL, NULL, _tagCanonicalize, _tagGenerate
>    };
>
>    /*@-compmempass@*/
>   @@ -145,17 +174,21 @@
>
>    static const char * _tagName(rpmTag tag)
>    {
>   -    static size_t nameBufLen = 256;
>        char * nameBuf;
>        headerTagTableEntry t;
>        int comparison, i, l, u;
>        int xx;
>        char *s;
>
>   +    if (_rpmTags.aTags == NULL)
>   +	xx = tagLoadATags(&_rpmTags.aTags, NULL);
>        if (_rpmTags.byValue == NULL)
>   -	xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize,  
> tagCmpValue);
>   +	xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize,
>   +		tagCmpValue);
>   +    if (_rpmTags.nameBufLen == 0)
>   +	_rpmTags.nameBufLen = 256;
>        if (_rpmTags.nameBuf == NULL)
>   -	_rpmTags.nameBuf = xcalloc(1, nameBufLen);
>   +	_rpmTags.nameBuf = xcalloc(1, _rpmTags.nameBufLen);
>        nameBuf = _rpmTags.nameBuf;
>
>        switch (tag) {
>   @@ -217,8 +250,8 @@
>    		}
>    		t = _rpmTags.byValue[i];
>    		s = (*_rpmTags.tagCanonicalize) (t->name);
>   -		strncpy(nameBuf, s, nameBufLen);
>   -		nameBuf[nameBufLen-1] = '\0';
>   +		strncpy(nameBuf, s, _rpmTags.nameBufLen);
>   +		nameBuf[_rpmTags.nameBufLen-1] = '\0';
>    		s = _free(s);
>    		/*@loopbreak@*/ break;
>    	    }
>   @@ -234,6 +267,8 @@
>        int comparison, i, l, u;
>        int xx;
>
>   +    if (_rpmTags.aTags == NULL)
>   +	xx = tagLoadATags(&_rpmTags.aTags, NULL);
>        if (_rpmTags.byValue == NULL)
>    	xx = tagLoadIndex(&_rpmTags.byValue, &_rpmTags.byValueSize,  
> tagCmpValue);
>
>   @@ -302,6 +337,8 @@
>        if (!xstrcasecmp(tagstr, "Ftswalk"))
>    	return RPMDBI_FTSWALK;
>
>   +    if (_rpmTags.aTags == NULL)
>   +	xx = tagLoadATags(&_rpmTags.aTags, NULL);
>        if (_rpmTags.byName == NULL)
>    	xx = tagLoadIndex(&_rpmTags.byName, &_rpmTags.byNameSize,  
> tagCmpName);
>        if (_rpmTags.byName == NULL)
>   @@ -364,6 +401,7 @@
>    	_rpmTags->nameBuf = _free(_rpmTags->nameBuf);
>    	_rpmTags->byName = _free(_rpmTags->byName);
>    	_rpmTags->byValue = _free(_rpmTags->byValue);
>   +	_rpmTags->aTags = argvFree(_rpmTags->aTags);
>        }
>    }
>
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/rpmio/argv.c
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r1.8 -r1.9 argv.c
>   --- rpm/rpmio/argv.c	30 Nov 2007 04:51:30 -0000	1.8
>   +++ rpm/rpmio/argv.c	2 Dec 2007 23:06:02 -0000	1.9
>   @@ -86,6 +86,13 @@
>        return strcmp(astr, bstr);
>    }
>
>   +int argvStrcasecmp(const void * a, const void * b)
>   +{
>   +    ARGstr_t astr = *(ARGV_t)a;
>   +    ARGstr_t bstr = *(ARGV_t)b;
>   +    return xstrcasecmp(astr, bstr);
>   +}
>   +
>    int argvSort(ARGV_t argv, int (*compar)(const void *, const void  
> *))
>    {
>        if (compar == NULL)
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/rpmio/argv.h
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r1.5 -r1.6 argv.h
>   --- rpm/rpmio/argv.h	3 Nov 2007 23:44:04 -0000	1.5
>   +++ rpm/rpmio/argv.h	2 Dec 2007 23:06:02 -0000	1.6
>   @@ -83,7 +83,7 @@
>    	/*@*/;
>
>    /**
>   - * Compare argv arrays (qsort/bsearch).
>   + * Compare argv arrays using strcmp (qsort/bsearch).
>     * @param a		1st instance address
>     * @param b		2nd instance address
>     * @return		result of comparison
>   @@ -94,6 +94,15 @@
>    /*@=exportlocal@*/
>
>    /**
>   + * Compare argv arrays using strcasecmp (qsort/bsearch).
>   + * @param a		1st instance address
>   + * @param b		2nd instance address
>   + * @return		result of comparison
>   + */
>   +int argvStrcasecmp(const void * a, const void * b)
>   +	/*@*/;
>   +
>   +/**
>     * Sort an argv array.
>     * @param argv		argv array
>     * @param compar	strcmp-like comparison function, or NULL for  
> argvCmp()
>   @@ .
>   patch -p0 <<'@@ .'
>   Index: rpm/rpmio/librpmio.vers
>    
> ====================================================================== 
> ======
>   $ cvs diff -u -r2.19 -r2.20 librpmio.vers
>   --- rpm/rpmio/librpmio.vers	22 Nov 2007 17:55:29 -0000	2.19
>   +++ rpm/rpmio/librpmio.vers	2 Dec 2007 23:06:02 -0000	2.20
>   @@ -20,6 +20,7 @@
>        argvSearch;
>        argvSort;
>        argvSplit;
>   +    argvStrcasecmp;
>        avClosedir;
>        _av_debug;
>        avmagicdir;
>   @@ .
> ______________________________________________________________________
> RPM Package Manager                                    http://rpm5.org
> CVS Sources Repository                                rpm-cvs@rpm5.org
Received on Mon Dec 3 00:38:08 2007
Driven by Jeff Johnson and the RPM project team.
Hosted by OpenPKG and Ralf S. Engelschall.
Powered by FreeBSD and OpenPKG.