rpm/lib/formats.c

1179 lines
31 KiB
C

/** \ingroup header
* \file lib/formats.c
*/
#include "system.h"
#include "rpmio_internal.h"
#include <rpmlib.h>
#include <rpmmacro.h> /* XXX for %_i18ndomains */
#include <rpmfi.h>
#include "legacy.h"
#include "manifest.h"
#include "misc.h"
#include "debug.h"
/*@access pgpDig @*/
/*@access pgpDigParams @*/
/**
* Identify type of trigger.
* @param type tag type
* @param data tag value
* @param formatPrefix (unused)
* @param padding (unused)
* @param element (unused)
* @return formatted string
*/
static /*@only@*/ char * triggertypeFormat(int_32 type, const void * data,
/*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
/*@unused@*/ int element)
/*@requires maxRead(data) >= 0 @*/
{
const int_32 * item = data;
char * val;
if (type != RPM_INT32_TYPE)
val = xstrdup(_("(not a number)"));
else if (*item & RPMSENSE_TRIGGERPREIN)
val = xstrdup("prein");
else if (*item & RPMSENSE_TRIGGERIN)
val = xstrdup("in");
else if (*item & RPMSENSE_TRIGGERUN)
val = xstrdup("un");
else if (*item & RPMSENSE_TRIGGERPOSTUN)
val = xstrdup("postun");
else
val = xstrdup("");
return val;
}
/**
* Format file permissions for display.
* @param type tag type
* @param data tag value
* @param formatPrefix
* @param padding
* @param element (unused)
* @return formatted string
*/
static /*@only@*/ char * permsFormat(int_32 type, const void * data,
char * formatPrefix, int padding, /*@unused@*/ int element)
/*@modifies formatPrefix @*/
/*@requires maxRead(data) >= 0 @*/
{
char * val;
char * buf;
if (type != RPM_INT32_TYPE) {
val = xstrdup(_("(not a number)"));
} else {
val = xmalloc(15 + padding);
/*@-boundswrite@*/
strcat(formatPrefix, "s");
/*@=boundswrite@*/
buf = rpmPermsString(*((int_32 *) data));
/*@-formatconst@*/
sprintf(val, formatPrefix, buf);
/*@=formatconst@*/
buf = _free(buf);
}
return val;
}
/**
* Format file flags for display.
* @param type tag type
* @param data tag value
* @param formatPrefix
* @param padding
* @param element (unused)
* @return formatted string
*/
static /*@only@*/ char * fflagsFormat(int_32 type, const void * data,
char * formatPrefix, int padding, /*@unused@*/ int element)
/*@modifies formatPrefix @*/
/*@requires maxRead(data) >= 0 @*/
{
char * val;
char buf[15];
int anint = *((int_32 *) data);
if (type != RPM_INT32_TYPE) {
val = xstrdup(_("(not a number)"));
} else {
buf[0] = '\0';
/*@-boundswrite@*/
if (anint & RPMFILE_DOC)
strcat(buf, "d");
if (anint & RPMFILE_CONFIG)
strcat(buf, "c");
if (anint & RPMFILE_SPECFILE)
strcat(buf, "s");
if (anint & RPMFILE_MISSINGOK)
strcat(buf, "m");
if (anint & RPMFILE_NOREPLACE)
strcat(buf, "n");
if (anint & RPMFILE_GHOST)
strcat(buf, "g");
if (anint & RPMFILE_LICENSE)
strcat(buf, "l");
if (anint & RPMFILE_README)
strcat(buf, "r");
/*@=boundswrite@*/
val = xmalloc(5 + padding);
/*@-boundswrite@*/
strcat(formatPrefix, "s");
/*@=boundswrite@*/
/*@-formatconst@*/
sprintf(val, formatPrefix, buf);
/*@=formatconst@*/
}
return val;
}
/**
* Wrap a pubkey in ascii armor for display.
* @todo Permit selectable display formats (i.e. binary).
* @param type tag type
* @param data tag value
* @param formatPrefix (unused)
* @param padding (unused)
* @param element no. bytes of binary data
* @return formatted string
*/
static /*@only@*/ char * armorFormat(int_32 type, const void * data,
/*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
int element)
/*@*/
{
const char * enc;
const unsigned char * s;
size_t ns;
int atype;
switch (type) {
case RPM_BIN_TYPE:
s = data;
/* XXX HACK ALERT: element field abused as no. bytes of binary data. */
ns = element;
atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
break;
case RPM_STRING_TYPE:
case RPM_STRING_ARRAY_TYPE:
enc = data;
if (b64decode(enc, (void **)&s, &ns))
return xstrdup(_("(not base64)"));
atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
break;
case RPM_NULL_TYPE:
case RPM_CHAR_TYPE:
case RPM_INT8_TYPE:
case RPM_INT16_TYPE:
case RPM_INT32_TYPE:
case RPM_I18NSTRING_TYPE:
default:
return xstrdup(_("(invalid type)"));
/*@notreached@*/ break;
}
/* XXX this doesn't use padding directly, assumes enough slop in retval. */
return pgpArmorWrap(atype, s, ns);
}
/**
* Encode binary data in base64 for display.
* @todo Permit selectable display formats (i.e. binary).
* @param type tag type
* @param data tag value
* @param formatPrefix (unused)
* @param padding
* @param element
* @return formatted string
*/
static /*@only@*/ char * base64Format(int_32 type, const void * data,
/*@unused@*/ char * formatPrefix, int padding, int element)
/*@*/
{
char * val;
if (type != RPM_BIN_TYPE) {
val = xstrdup(_("(not a blob)"));
} else {
const char * enc;
char * t;
int lc;
/* XXX HACK ALERT: element field abused as no. bytes of binary data. */
size_t ns = element;
size_t nt = ((ns + 2) / 3) * 4;
/*@-boundswrite@*/
/*@-globs@*/
/* Add additional bytes necessary for eol string(s). */
if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
++lc;
nt += lc * strlen(b64encode_eolstr);
}
/*@=globs@*/
val = t = xmalloc(nt + padding + 1);
*t = '\0';
if ((enc = b64encode(data, ns)) != NULL) {
t = stpcpy(t, enc);
enc = _free(enc);
}
/*@=boundswrite@*/
}
return val;
}
/**
*/
static size_t xmlstrlen(const char * s)
/*@*/
{
size_t len = 0;
int c;
/*@-boundsread@*/
while ((c = *s++) != '\0')
/*@=boundsread@*/
{
switch (c) {
case '<': case '>': len += 4; /*@switchbreak@*/ break;
case '&': len += 5; /*@switchbreak@*/ break;
default: len += 1; /*@switchbreak@*/ break;
}
}
return len;
}
/**
*/
static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
/*@modifies t @*/
{
char * te = t;
int c;
/*@-bounds@*/
while ((c = *s++) != '\0') {
switch (c) {
case '<': te = stpcpy(te, "&lt;"); /*@switchbreak@*/ break;
case '>': te = stpcpy(te, "&gt;"); /*@switchbreak@*/ break;
case '&': te = stpcpy(te, "&amp;"); /*@switchbreak@*/ break;
default: *te++ = c; /*@switchbreak@*/ break;
}
}
*te = '\0';
/*@=bounds@*/
return t;
}
/**
* Wrap tag data in simple header xml markup.
* @param type tag type
* @param data tag value
* @param formatPrefix
* @param padding
* @param element (unused)
* @return formatted string
*/
/*@-bounds@*/
static /*@only@*/ char * xmlFormat(int_32 type, const void * data,
char * formatPrefix, int padding,
/*@unused@*/ int element)
/*@modifies formatPrefix @*/
{
const char * xtag = NULL;
size_t nb;
char * val;
const char * s = NULL;
char * t, * te;
unsigned long anint = 0;
int xx;
/*@-branchstate@*/
switch (type) {
case RPM_I18NSTRING_TYPE:
case RPM_STRING_TYPE:
s = data;
xtag = "string";
break;
case RPM_BIN_TYPE:
{ int cpl = b64encode_chars_per_line;
/*@-mods@*/
b64encode_chars_per_line = 0;
/*@=mods@*/
/*@-formatconst@*/
s = base64Format(type, data, formatPrefix, padding, element);
/*@=formatconst@*/
/*@-mods@*/
b64encode_chars_per_line = cpl;
/*@=mods@*/
xtag = "base64";
} break;
case RPM_CHAR_TYPE:
case RPM_INT8_TYPE:
anint = *((uint_8 *) data);
break;
case RPM_INT16_TYPE:
anint = *((uint_16 *) data);
break;
case RPM_INT32_TYPE:
anint = *((uint_32 *) data);
break;
case RPM_NULL_TYPE:
case RPM_STRING_ARRAY_TYPE:
default:
return xstrdup(_("(invalid xml type)"));
/*@notreached@*/ break;
}
/*@=branchstate@*/
/*@-branchstate@*/
if (s == NULL) {
int tlen = 32;
t = memset(alloca(tlen+1), 0, tlen+1);
if (anint != 0)
xx = snprintf(t, tlen, "%lu", anint);
s = t;
xtag = "integer";
}
/*@=branchstate@*/
nb = xmlstrlen(s);
if (nb == 0) {
nb += strlen(xtag) + sizeof("\t</>");
te = t = alloca(nb);
te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
} else {
nb += 2 * strlen(xtag) + sizeof("\t<></>");
te = t = alloca(nb);
te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
te = xmlstrcpy(te, s);
te += strlen(te);
te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
}
/* XXX s was malloc'd */
/*@-branchstate@*/
if (!strcmp(xtag, "base64"))
s = _free(s);
/*@=branchstate@*/
nb += padding;
val = xmalloc(nb+1);
/*@-boundswrite@*/
strcat(formatPrefix, "s");
/*@=boundswrite@*/
/*@-formatconst@*/
xx = snprintf(val, nb, formatPrefix, t);
/*@=formatconst@*/
val[nb] = '\0';
return val;
}
/*@=bounds@*/
/**
* Display signature fingerprint and time.
* @param type tag type
* @param data tag value
* @param formatPrefix (unused)
* @param padding
* @param element (unused)
* @return formatted string
*/
static /*@only@*/ char * pgpsigFormat(int_32 type, const void * data,
/*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
/*@unused@*/ int element)
/*@globals fileSystem, internalState @*/
/*@modifies fileSystem, internalState @*/
{
char * val, * t;
if (type != RPM_BIN_TYPE) {
val = xstrdup(_("(not a blob)"));
} else {
unsigned char * pkt = (byte *) data;
unsigned int pktlen = 0;
/*@-boundsread@*/
unsigned int v = *pkt;
/*@=boundsread@*/
pgpTag tag = 0;
unsigned int plen;
unsigned int hlen = 0;
if (v & 0x80) {
if (v & 0x40) {
tag = (v & 0x3f);
plen = pgpLen(pkt+1, &hlen);
} else {
tag = (v >> 2) & 0xf;
plen = (1 << (v & 0x3));
hlen = pgpGrab(pkt+1, plen);
}
pktlen = 1 + plen + hlen;
}
if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
val = xstrdup(_("(not an OpenPGP signature)"));
} else {
pgpDig dig = pgpNewDig();
pgpDigParams sigp = &dig->signature;
size_t nb = 0;
const char *tempstr;
(void) pgpPrtPkts(pkt, pktlen, dig, 0);
val = NULL;
again:
nb += 100;
val = t = xrealloc(val, nb + 1);
/*@-boundswrite@*/
switch (sigp->pubkey_algo) {
case PGPPUBKEYALGO_DSA:
t = stpcpy(t, "DSA");
break;
case PGPPUBKEYALGO_RSA:
t = stpcpy(t, "RSA");
break;
default:
(void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
t += strlen(t);
break;
}
if (t + 5 >= val + nb)
goto again;
*t++ = '/';
switch (sigp->hash_algo) {
case PGPHASHALGO_MD5:
t = stpcpy(t, "MD5");
break;
case PGPHASHALGO_SHA1:
t = stpcpy(t, "SHA1");
break;
default:
(void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
t += strlen(t);
break;
}
if (t + strlen (", ") + 1 >= val + nb)
goto again;
t = stpcpy(t, ", ");
/* this is important if sizeof(int_32) ! sizeof(time_t) */
{ time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
struct tm * tstruct = localtime(&dateint);
if (tstruct)
(void) strftime(t, (nb - (t - val)), "%c", tstruct);
}
t += strlen(t);
if (t + strlen (", Key ID ") + 1 >= val + nb)
goto again;
t = stpcpy(t, ", Key ID ");
tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
if (t + strlen (tempstr) > val + nb)
goto again;
t = stpcpy(t, tempstr);
/*@=boundswrite@*/
dig = pgpFreeDig(dig);
}
}
return val;
}
/**
* Format dependency flags for display.
* @param type tag type
* @param data tag value
* @param formatPrefix
* @param padding
* @param element (unused)
* @return formatted string
*/
static /*@only@*/ char * depflagsFormat(int_32 type, const void * data,
char * formatPrefix, int padding, /*@unused@*/ int element)
/*@modifies formatPrefix @*/
/*@requires maxRead(data) >= 0 @*/
{
char * val;
char buf[10];
int anint;
if (type != RPM_INT32_TYPE) {
val = xstrdup(_("(not a number)"));
} else {
anint = *((int_32 *) data);
buf[0] = '\0';
/*@-boundswrite@*/
if (anint & RPMSENSE_LESS)
strcat(buf, "<");
if (anint & RPMSENSE_GREATER)
strcat(buf, ">");
if (anint & RPMSENSE_EQUAL)
strcat(buf, "=");
/*@=boundswrite@*/
val = xmalloc(5 + padding);
/*@-boundswrite@*/
strcat(formatPrefix, "s");
/*@=boundswrite@*/
/*@-formatconst@*/
sprintf(val, formatPrefix, buf);
/*@=formatconst@*/
}
return val;
}
/**
* Retrieve mounted file system paths.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int fsnamesTag( /*@unused@*/ Header h, /*@out@*/ int_32 * type,
/*@out@*/ void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals fileSystem, internalState @*/
/*@modifies *type, *data, *count, *freeData,
fileSystem, internalState @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
const char ** list;
/*@-boundswrite@*/
if (rpmGetFilesystemList(&list, count))
return 1;
/*@=boundswrite@*/
if (type) *type = RPM_STRING_ARRAY_TYPE;
if (data) *((const char ***) data) = list;
if (freeData) *freeData = 0;
return 0;
}
/**
* Retrieve install prefixes.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int instprefixTag(Header h, /*@null@*/ /*@out@*/ rpmTagType * type,
/*@null@*/ /*@out@*/ const void ** data,
/*@null@*/ /*@out@*/ int_32 * count,
/*@null@*/ /*@out@*/ int * freeData)
/*@modifies *type, *data, *freeData @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType ipt;
char ** array;
if (hge(h, RPMTAG_INSTALLPREFIX, type, (void **)data, count)) {
if (freeData) *freeData = 0;
return 0;
} else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &array, count)) {
if (type) *type = RPM_STRING_TYPE;
/*@-boundsread@*/
if (data) *data = xstrdup(array[0]);
/*@=boundsread@*/
if (freeData) *freeData = 1;
array = hfd(array, ipt);
return 0;
}
return 1;
}
/**
* Retrieve mounted file system space.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int fssizesTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno,
fileSystem, internalState @*/
/*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext,
fileSystem, internalState @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
const char ** filenames;
int_32 * filesizes;
uint_32 * usages;
int numFiles;
if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &filesizes, &numFiles)) {
filesizes = NULL;
numFiles = 0;
filenames = NULL;
} else {
rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
}
/*@-boundswrite@*/
if (rpmGetFilesystemList(NULL, count))
return 1;
/*@=boundswrite@*/
*type = RPM_INT32_TYPE;
*freeData = 1;
if (filenames == NULL) {
usages = xcalloc((*count), sizeof(usages));
*data = usages;
return 0;
}
/*@-boundswrite@*/
if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
return 1;
/*@=boundswrite@*/
*data = usages;
filenames = _free(filenames);
return 0;
}
/**
* Retrieve trigger info.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int triggercondsTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@modifies *type, *data, *count, *freeData @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType tnt, tvt, tst;
int_32 * indices, * flags;
char ** names, ** versions;
int numNames, numScripts;
char ** conds, ** s;
char * item, * flagsStr;
char * chptr;
int i, j, xx;
char buf[5];
if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (void **) &names, &numNames)) {
*freeData = 0;
return 0;
}
xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, NULL);
xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (void **) &versions, NULL);
xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
s = hfd(s, tst);
*freeData = 1;
*data = conds = xmalloc(sizeof(*conds) * numScripts);
*count = numScripts;
*type = RPM_STRING_ARRAY_TYPE;
/*@-bounds@*/
for (i = 0; i < numScripts; i++) {
chptr = xstrdup("");
for (j = 0; j < numNames; j++) {
if (indices[j] != i)
/*@innercontinue@*/ continue;
item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
if (flags[j] & RPMSENSE_SENSEMASK) {
buf[0] = '%', buf[1] = '\0';
flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, j);
sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
flagsStr = _free(flagsStr);
} else {
strcpy(item, names[j]);
}
chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
if (*chptr != '\0') strcat(chptr, ", ");
strcat(chptr, item);
item = _free(item);
}
conds[i] = chptr;
}
/*@=bounds@*/
names = hfd(names, tnt);
versions = hfd(versions, tvt);
return 0;
}
/**
* Retrieve trigger type info.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int triggertypeTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@modifies *type, *data, *count, *freeData @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType tst;
int_32 * indices, * flags;
const char ** conds;
const char ** s;
int i, j, xx;
int numScripts, numNames;
if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, &numNames)) {
*freeData = 0;
return 1;
}
xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
s = hfd(s, tst);
*freeData = 1;
*data = conds = xmalloc(sizeof(*conds) * numScripts);
*count = numScripts;
*type = RPM_STRING_ARRAY_TYPE;
/*@-bounds@*/
for (i = 0; i < numScripts; i++) {
for (j = 0; j < numNames; j++) {
if (indices[j] != i)
/*@innercontinue@*/ continue;
if (flags[j] & RPMSENSE_TRIGGERPREIN)
conds[i] = xstrdup("prein");
else if (flags[j] & RPMSENSE_TRIGGERIN)
conds[i] = xstrdup("in");
else if (flags[j] & RPMSENSE_TRIGGERUN)
conds[i] = xstrdup("un");
else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
conds[i] = xstrdup("postun");
else
conds[i] = xstrdup("");
/*@innerbreak@*/ break;
}
}
/*@=bounds@*/
return 0;
}
/**
* Retrieve file paths.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int filenamesTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@modifies *type, *data, *count, *freeData @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
*freeData = 1;
return 0;
}
/**
* Retrieve file classes.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int fileclassTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
/*@modifies h, *type, *data, *count, *freeData,
rpmGlobalMacroContext, fileSystem @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildFClasses(h, (const char ***) data, count);
*freeData = 1;
return 0;
}
/**
* Retrieve file contexts from header.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int filecontextsTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
/*@modifies h, *type, *data, *count, *freeData,
rpmGlobalMacroContext, fileSystem @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildFContexts(h, (const char ***) data, count);
*freeData = 1;
return 0;
}
/**
* Retrieve file contexts from file system.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int fscontextsTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
/*@modifies h, *type, *data, *count, *freeData,
rpmGlobalMacroContext, fileSystem @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildFSContexts(h, (const char ***) data, count);
*freeData = 1;
return 0;
}
/**
* Retrieve file contexts from policy RE's.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int recontextsTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
/*@modifies h, *type, *data, *count, *freeData,
rpmGlobalMacroContext, fileSystem @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildREContexts(h, (const char ***) data, count);
*freeData = 1;
return 0;
}
/**
* Retrieve file provides.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int fileprovideTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
/*@modifies h, *type, *data, *count, *freeData,
rpmGlobalMacroContext, fileSystem, internalState @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
*freeData = 1;
return 0;
}
/**
* Retrieve file requires.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int filerequireTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
/*@modifies h, *type, *data, *count, *freeData,
rpmGlobalMacroContext, fileSystem, internalState @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
*type = RPM_STRING_ARRAY_TYPE;
rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
*freeData = 1;
return 0;
}
/* I18N look aside diversions */
#if defined(ENABLE_NLS)
/*@-exportlocal -exportheadervar@*/
/*@unchecked@*/
extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
/*@=exportlocal =exportheadervar@*/
#endif
/*@observer@*/ /*@unchecked@*/
static const char * language = "LANGUAGE";
/*@observer@*/ /*@unchecked@*/
static const char * _macro_i18ndomains = "%{?_i18ndomains}";
/**
* Retrieve i18n text.
* @param h header
* @param tag tag
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int i18nTag(Header h, int_32 tag, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno @*/
/*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
char * dstring = rpmExpand(_macro_i18ndomains, NULL);
int rc;
*type = RPM_STRING_TYPE;
*data = NULL;
*count = 0;
*freeData = 0;
if (dstring && *dstring) {
char *domain, *de;
const char * langval;
const char * msgkey;
const char * msgid;
{ const char * tn = tagName(tag);
const char * n;
char * mk;
(void) headerNVR(h, &n, NULL, NULL);
mk = alloca(strlen(n) + strlen(tn) + sizeof("()"));
sprintf(mk, "%s(%s)", n, tn);
msgkey = mk;
}
/* change to en_US for msgkey -> msgid resolution */
langval = getenv(language);
(void) setenv(language, "en_US", 1);
#if defined(ENABLE_NLS)
/*@i@*/ ++_nl_msg_cat_cntr;
#endif
msgid = NULL;
/*@-branchstate@*/
for (domain = dstring; domain != NULL; domain = de) {
de = strchr(domain, ':');
if (de) *de++ = '\0';
msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/;
if (msgid != msgkey) break;
}
/*@=branchstate@*/
/* restore previous environment for msgid -> msgstr resolution */
if (langval)
(void) setenv(language, langval, 1);
else
unsetenv(language);
#if defined(ENABLE_NLS)
/*@i@*/ ++_nl_msg_cat_cntr;
#endif
if (domain && msgid) {
*data = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/;
*data = xstrdup(*data); /* XXX xstrdup has side effects. */
*count = 1;
*freeData = 1;
}
dstring = _free(dstring);
if (*data)
return 0;
}
dstring = _free(dstring);
rc = hge(h, tag, type, (void **)data, count);
if (rc && (*data) != NULL) {
*data = xstrdup(*data);
*freeData = 1;
return 0;
}
*freeData = 0;
*data = NULL;
*count = 0;
return 1;
}
/**
* Retrieve summary text.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int summaryTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno @*/
/*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
}
/**
* Retrieve description text.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int descriptionTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno @*/
/*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
}
/**
* Retrieve group text.
* @param h header
* @retval *type tag type
* @retval *data tag value
* @retval *count no. of data items
* @retval *freeData data-was-malloc'ed indicator
* @return 0 on success
*/
static int groupTag(Header h, /*@out@*/ rpmTagType * type,
/*@out@*/ const void ** data, /*@out@*/ int_32 * count,
/*@out@*/ int * freeData)
/*@globals rpmGlobalMacroContext, h_errno @*/
/*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
/*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
/\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
{
return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
}
/*@-type@*/ /* FIX: cast? */
const struct headerSprintfExtension_s rpmHeaderFormats[] = {
{ HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } },
{ HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } },
{ HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } },
{ HEADER_EXT_TAG, "RPMTAG_FILECLASS", { fileclassTag } },
{ HEADER_EXT_TAG, "RPMTAG_FILECONTEXTS", { filecontextsTag } },
{ HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } },
{ HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE", { fileprovideTag } },
{ HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE", { filerequireTag } },
{ HEADER_EXT_TAG, "RPMTAG_FSCONTEXTS", { fscontextsTag } },
{ HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } },
{ HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } },
{ HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } },
{ HEADER_EXT_TAG, "RPMTAG_RECONTEXTS", { recontextsTag } },
{ HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } },
{ HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } },
{ HEADER_EXT_FORMAT, "armor", { armorFormat } },
{ HEADER_EXT_FORMAT, "base64", { base64Format } },
{ HEADER_EXT_FORMAT, "pgpsig", { pgpsigFormat } },
{ HEADER_EXT_FORMAT, "depflags", { depflagsFormat } },
{ HEADER_EXT_FORMAT, "fflags", { fflagsFormat } },
{ HEADER_EXT_FORMAT, "perms", { permsFormat } },
{ HEADER_EXT_FORMAT, "permissions", { permsFormat } },
{ HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } },
{ HEADER_EXT_FORMAT, "xml", { xmlFormat } },
{ HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } }
} ;
/*@=type@*/