/** \ingroup header * \file lib/formats.c */ #include "system.h" #include "rpmlib.h" #include "rpmmacro.h" /* XXX for %_i18ndomains */ #include "rpmpgp.h" #include "manifest.h" #include "misc.h" #include "debug.h" /** * @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) /*@*/ { const int_32 * item = data; char * val; if (type != RPM_INT32_TYPE) val = xstrdup(_("(not a number)")); else if (*item & RPMSENSE_TRIGGERIN) val = xstrdup("in"); else val = xstrdup("un"); return val; } /** * @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 @*/ { char * val; char * buf; if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else { val = xmalloc(15 + padding); strcat(formatPrefix, "s"); buf = rpmPermsString(*((int_32 *) data)); /*@-formatconst@*/ sprintf(val, formatPrefix, buf); /*@=formatconst@*/ buf = _free(buf); } return val; } /** * @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 @*/ { char * val; char buf[15]; int anint = *((int_32 *) data); if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else { buf[0] = '\0'; 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"); val = xmalloc(5 + padding); strcat(formatPrefix, "s"); /*@-formatconst@*/ sprintf(val, formatPrefix, buf); /*@=formatconst@*/ } return val; } /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @return formatted string */ static /*@only@*/ char * armorFormat(int_32 type, const void * data, /*@unused@*/ char * formatPrefix, int padding, int element) /*@*/ { const char * enc; const char * s; char * t; char * val; int atype; int lc, ns, nt; switch (type) { case RPM_BIN_TYPE: s = 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; } nt = ((ns + 2) / 3) * 4; /*@-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@*/ nt += 512; /* XXX slop for armor and crc */ val = t = xmalloc(nt + padding + 1); *t = '\0'; t = stpcpy(t, "-----BEGIN PGP "); t = stpcpy(t, pgpValStr(pgpArmorTbl, atype)); /*@-globs@*/ t = stpcpy( stpcpy(t, "-----\nVersion: rpm-"), RPMVERSION); /*@=globs@*/ t = stpcpy(t, " (beecrypt-2.2.0)\n\n"); if ((enc = b64encode(s, ns)) != NULL) { t = stpcpy(t, enc); enc = _free(enc); if ((enc = b64crc(s, ns)) != NULL) { *t++ = '='; t = stpcpy(t, enc); enc = _free(enc); } } t = stpcpy(t, "-----END PGP "); t = stpcpy(t, pgpValStr(pgpArmorTbl, atype)); t = stpcpy(t, "-----\n"); /*@-branchstate@*/ if (s != data) s = _free(s); /*@=branchstate@*/ return val; } /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @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; int nt = ((element + 2) / 3) * 4; /*@-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, element)) != NULL) { t = stpcpy(t, enc); enc = _free(enc); } } return val; } #ifdef NOTYET /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @return formatted string */ static /*@only@*/ char * pgppktFormat(int_32 type, const void * data, char * formatPrefix, int padding, int element) /*@modifies formatPrefix @*/ { char * val; if (type != RPM_BIN_TYPE) { val = xstrdup(_("(not a blob)")); } else { } return val; } #endif /** * @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 @*/ { char * val; char buf[10]; int anint = *((int_32 *) data); if (type != RPM_INT32_TYPE) { val = xstrdup(_("(not a number)")); } else { buf[0] = '\0'; if (anint & RPMSENSE_LESS) strcat(buf, "<"); if (anint & RPMSENSE_GREATER) strcat(buf, ">"); if (anint & RPMSENSE_EQUAL) strcat(buf, "="); val = xmalloc(5 + padding); strcat(formatPrefix, "s"); /*@-formatconst@*/ sprintf(val, formatPrefix, buf); /*@=formatconst@*/ } return val; } /** * @param type tag type * @param data tag value * @param formatPrefix * @param padding * @param element (unused) * @return formatted string */ static /*@only@*/ char * nothingFormat(int_32 type, const void * data, char * formatPrefix, int padding, /*@unused@*/ int element) /*@modifies formatPrefix @*/ { /* based on depflagsFormat() code. */ char * val; val = xmalloc(2 + padding); strcat(formatPrefix, "s"); /*@-formatconst@*/ sprintf(val, formatPrefix, ""); /*@=formatconst@*/ return val; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ { const char ** list; if (rpmGetFilesystemList(&list, count)) { return 1; } *type = RPM_STRING_ARRAY_TYPE; *((const char ***) data) = list; *freeData = 0; return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ { 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 (data) *data = xstrdup(array[0]); if (freeData) *freeData = 1; if (type) *type = RPM_STRING_TYPE; array = hfd(array, ipt); return 0; } return 1; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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, fileSystem, internalState @*/ /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext, fileSystem, internalState @*/ { 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 { rpmBuildFileList(h, &filenames, &numFiles); } if (rpmGetFilesystemList(NULL, count)) { return 1; } *type = RPM_INT32_TYPE; *freeData = 1; if (filenames == NULL) { usages = xcalloc((*count), sizeof(usages)); *data = usages; return 0; } if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0)) return 1; *data = usages; filenames = _free(filenames); return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ { 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; 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; } names = hfd(names, tnt); versions = hfd(versions, tvt); return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ { 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; for (i = 0; i < numScripts; i++) { for (j = 0; j < numNames; j++) { if (indices[j] != i) /*@innercontinue@*/ continue; if (flags[j] & RPMSENSE_TRIGGERIN) conds[i] = xstrdup("in"); else if (flags[j] & RPMSENSE_TRIGGERUN) conds[i] = xstrdup("un"); else conds[i] = xstrdup("postun"); /*@innerbreak@*/ break; } } return 0; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ { *type = RPM_STRING_ARRAY_TYPE; rpmBuildFileList(h, (const char ***) data, count); *freeData = 1; *freeData = 0; /* XXX WTFO? */ return 0; } /* I18N look aside diversions */ /*@-exportlocal -exportheadervar@*/ /*@unchecked@*/ int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */ /*@=exportlocal =exportheadervar@*/ /*@observer@*/ /*@unchecked@*/ static const char * language = "LANGUAGE"; /*@observer@*/ /*@unchecked@*/ static const char *_macro_i18ndomains = "%{?_i18ndomains}"; /** * @param h header * @param tag tag * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/ { 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 = headerNVR(h, &n, NULL, NULL); if (tn) nb += strlen(tn); if (n) nb += strlen(n); mk = alloca(nb); sprintf(mk, "%s(%s)", (n?n:""), (tn?tn:"")); msgkey = mk; } /* change to en_US for msgkey -> msgid resolution */ langval = getenv(language); (void) setenv(language, "en_US", 1); /*@i@*/ ++_nl_msg_cat_cntr; 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); /*@i@*/ ++_nl_msg_cat_cntr; 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; } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/ { return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData); } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/ { return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData); } /** * @param h header * @retval type address of tag type * @retval data address of tag value pointer * @retval count address of no. of data items * @retval freeData address of 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 @*/ /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/ { 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_FILENAMES", { filenamesTag } }, { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } }, { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } }, { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } }, { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } }, { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } }, { HEADER_EXT_FORMAT, "armor", { armorFormat } }, { HEADER_EXT_FORMAT, "base64", { base64Format } }, #ifdef NOTYET { HEADER_EXT_FORMAT, "pgppkt", { pgppktFormat } }, #endif { 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, "nothing", { nothingFormat } }, { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } } } ; /*@=type@*/