/** \ingroup header * \file lib/formats.c */ #include "system.h" #include "rpmio_internal.h" #include #include /* XXX for %_i18ndomains */ #include #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, "<"); /*@switchbreak@*/ break; case '>': te = stpcpy(te, ">"); /*@switchbreak@*/ break; case '&': te = stpcpy(te, "&"); /*@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, ""); } /* 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; size_t nb = sizeof("()"); int xx; xx = headerNVR(h, &n, NULL, NULL); if (tn) nb += strlen(tn); if (n) nb += strlen(n); mk = alloca(nb); 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@*/