7 #include <rpm/rpmtag.h>
8 #include <rpm/rpmlib.h> /* rpmGetFilesystem*() */
10 #include <rpm/rpmmacro.h> /* XXX for %_i18ndomains */
11 #include <rpm/rpmfi.h>
12 #include <rpm/rpmstring.h>
14 #include "rpmio/digest.h"
15 #include "lib/manifest.h"
20 * Define header tag output formats.
23 struct headerFormatFunc_s {
24 const char *name; /*!< Name of extension. */
25 void *func; /*!< Pointer to formatter function. */
28 struct headerTagFunc_s {
29 rpmTag tag; /*!< Tag of extension. */
30 void *func; /*!< Pointer to formatter function. */
33 /* forward declarations */
34 static const struct headerFormatFunc_s rpmHeaderFormats[];
35 static const struct headerTagFunc_s rpmHeaderTagExtensions[];
37 void *rpmHeaderFormatFunc(const char *fmt);
38 void *rpmHeaderTagFunc(rpmTag tag);
43 * @param type tag type
44 * @param data tag value
45 * @param formatPrefix sprintf format string
46 * @param padding no. additional bytes needed by format string
47 * @param element (unused)
48 * @return formatted string
50 static char * octalFormat(rpmTagType type, rpm_constdata_t data,
51 char * formatPrefix, size_t padding,int element)
55 if (type != RPM_INT32_TYPE) {
56 val = xstrdup(_("(not a number)"));
58 val = xmalloc(20 + padding);
59 strcat(formatPrefix, "o");
60 sprintf(val, formatPrefix, *((const int32_t *) data));
68 * @param type tag type
69 * @param data tag value
70 * @param formatPrefix sprintf format string
71 * @param padding no. additional bytes needed by format string
72 * @param element (unused)
73 * @return formatted string
75 static char * hexFormat(rpmTagType type, rpm_constdata_t data,
76 char * formatPrefix, size_t padding,int element)
80 if (type != RPM_INT32_TYPE) {
81 val = xstrdup(_("(not a number)"));
83 val = xmalloc(20 + padding);
84 strcat(formatPrefix, "x");
85 sprintf(val, formatPrefix, *((const int32_t *) data));
93 static char * realDateFormat(rpmTagType type, rpm_constdata_t data,
94 char * formatPrefix, size_t padding,int element,
95 const char * strftimeFormat)
99 if (type != RPM_INT32_TYPE) {
100 val = xstrdup(_("(not a number)"));
105 val = xmalloc(50 + padding);
106 strcat(formatPrefix, "s");
108 /* this is important if sizeof(rpm_time_t) ! sizeof(time_t) */
109 { time_t dateint = *((const rpm_time_t *) data);
110 tstruct = localtime(&dateint);
114 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
115 sprintf(val, formatPrefix, buf);
123 * @param type tag type
124 * @param data tag value
125 * @param formatPrefix sprintf format string
126 * @param padding no. additional bytes needed by format string
127 * @param element (unused)
128 * @return formatted string
130 static char * dateFormat(rpmTagType type, rpm_constdata_t data,
131 char * formatPrefix, size_t padding, int element)
133 return realDateFormat(type, data, formatPrefix, padding, element,
139 * @param type tag type
140 * @param data tag value
141 * @param formatPrefix sprintf format string
142 * @param padding no. additional bytes needed by format string
143 * @param element (unused)
144 * @return formatted string
146 static char * dayFormat(rpmTagType type, rpm_constdata_t data,
147 char * formatPrefix, size_t padding, int element)
149 return realDateFormat(type, data, formatPrefix, padding, element,
154 * Return shell escape formatted data.
155 * @param type tag type
156 * @param data tag value
157 * @param formatPrefix sprintf format string
158 * @param padding no. additional bytes needed by format string
159 * @param element (unused)
160 * @return formatted string
162 static char * shescapeFormat(rpmTagType type, rpm_constdata_t data,
163 char * formatPrefix, size_t padding,int element)
165 char * result, * dst, * src;
167 if (type == RPM_INT32_TYPE) {
168 result = xmalloc(padding + 20);
169 strcat(formatPrefix, "d");
170 sprintf(result, formatPrefix, *((const int32_t *) data));
173 strcat(formatPrefix, "s");
174 rasprintf(&buf, formatPrefix, data);
176 result = dst = xmalloc(strlen(buf) * 4 + 3);
178 for (src = buf; *src != '\0'; src++) {
198 * Identify type of trigger.
199 * @param type tag type
200 * @param data tag value
201 * @param formatPrefix (unused)
202 * @param padding (unused)
203 * @param element (unused)
204 * @return formatted string
206 static char * triggertypeFormat(rpmTagType type, rpm_constdata_t data,
207 char * formatPrefix, size_t padding,
210 const int32_t * item = data;
213 if (type != RPM_INT32_TYPE)
214 val = xstrdup(_("(not a number)"));
215 else if (*item & RPMSENSE_TRIGGERPREIN)
216 val = xstrdup("prein");
217 else if (*item & RPMSENSE_TRIGGERIN)
219 else if (*item & RPMSENSE_TRIGGERUN)
221 else if (*item & RPMSENSE_TRIGGERPOSTUN)
222 val = xstrdup("postun");
229 * Format file permissions for display.
230 * @param type tag type
231 * @param data tag value
232 * @param formatPrefix
234 * @param element (unused)
235 * @return formatted string
237 static char * permsFormat(rpmTagType type, rpm_constdata_t data,
238 char * formatPrefix, size_t padding, int element)
243 if (type != RPM_INT32_TYPE) {
244 val = xstrdup(_("(not a number)"));
246 val = xmalloc(15 + padding);
247 strcat(formatPrefix, "s");
248 buf = rpmPermsString(*((const int32_t *) data));
249 sprintf(val, formatPrefix, buf);
257 * Format file flags for display.
258 * @param type tag type
259 * @param data tag value
260 * @param formatPrefix
262 * @param element (unused)
263 * @return formatted string
265 static char * fflagsFormat(rpmTagType type, rpm_constdata_t data,
266 char * formatPrefix, size_t padding, int element)
270 rpmfileAttrs anint = *((const rpm_flag_t *) data);
272 if (type != RPM_INT32_TYPE) {
273 val = xstrdup(_("(not a number)"));
276 if (anint & RPMFILE_DOC)
278 if (anint & RPMFILE_CONFIG)
280 if (anint & RPMFILE_SPECFILE)
282 if (anint & RPMFILE_MISSINGOK)
284 if (anint & RPMFILE_NOREPLACE)
286 if (anint & RPMFILE_GHOST)
288 if (anint & RPMFILE_LICENSE)
290 if (anint & RPMFILE_README)
293 val = xmalloc(5 + padding);
294 strcat(formatPrefix, "s");
295 sprintf(val, formatPrefix, buf);
302 * Wrap a pubkey in ascii armor for display.
303 * @todo Permit selectable display formats (i.e. binary).
304 * @param type tag type
305 * @param data tag value
306 * @param formatPrefix (unused)
307 * @param padding (unused)
308 * @param element no. bytes of binary data
309 * @return formatted string
311 static char * armorFormat(rpmTagType type, rpm_constdata_t data,
312 char * formatPrefix, size_t padding,
316 const unsigned char * s;
317 unsigned char * bs = NULL;
325 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
327 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
329 case RPM_STRING_TYPE:
330 case RPM_STRING_ARRAY_TYPE:
332 if (b64decode(enc, (void **)&bs, &ns))
333 return xstrdup(_("(not base64)"));
335 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
342 case RPM_I18NSTRING_TYPE:
344 return xstrdup(_("(invalid type)"));
348 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
349 val = pgpArmorWrap(atype, s, ns);
350 if (atype == PGPARMOR_PUBKEY) {
357 * Encode binary data in base64 for display.
358 * @todo Permit selectable display formats (i.e. binary).
359 * @param type tag type
360 * @param data tag value
361 * @param formatPrefix (unused)
364 * @return formatted string
366 static char * base64Format(rpmTagType type, rpm_constdata_t data,
367 char * formatPrefix, size_t padding, int element)
371 if (type != RPM_BIN_TYPE) {
372 val = xstrdup(_("(not a blob)"));
376 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
380 if ((enc = b64encode(data, ns, -1)) != NULL) {
384 val = t = xmalloc(nt + padding + 1);
397 * Wrap tag data in simple header xml markup.
398 * @param type tag type
399 * @param data tag value
400 * @param formatPrefix
402 * @param element (unused)
403 * @return formatted string
405 static char * xmlFormat(rpmTagType type, rpm_constdata_t data,
406 char * formatPrefix, size_t padding,
409 const char *xtag = NULL;
414 unsigned long anint = 0;
418 case RPM_I18NSTRING_TYPE:
419 case RPM_STRING_TYPE:
425 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
427 if ((s = b64encode(data, ns, 0)) == NULL) {
428 return xstrdup(_("(encoding failed)"));
434 anint = *((const uint8_t *) data);
437 anint = *((const uint16_t *) data);
440 anint = *((const uint32_t *) data);
443 case RPM_STRING_ARRAY_TYPE:
445 return xstrdup(_("(invalid xml type)"));
451 rasprintf(&s, "%lu", anint);
459 t = rstrscat(NULL, "\t<", xtag, "/>", NULL);
462 size_t i, s_size = strlen(s);
464 for (i=0; i<s_size; i++) {
466 case '<': rstrcat(&new_s, "<"); break;
467 case '>': rstrcat(&new_s, ">"); break;
468 case '&': rstrcat(&new_s, "&"); break;
478 t = rstrscat(NULL, "\t<", xtag, ">", new_s, "</", xtag, ">", NULL);
482 /* XXX s was malloc'd */
483 if (!strcmp(xtag, "base64") || !strcmp(xtag, "integer"))
486 nb += strlen(t)+padding;
488 strcat(formatPrefix, "s");
489 xx = snprintf(val, nb, formatPrefix, t);
497 * Display signature fingerprint and time.
498 * @param type tag type
499 * @param data tag value
500 * @param formatPrefix (unused)
502 * @param element (unused)
503 * @return formatted string
505 static char * pgpsigFormat(rpmTagType type, rpm_constdata_t data,
506 char * formatPrefix, size_t padding,
511 if (type != RPM_BIN_TYPE) {
512 val = xstrdup(_("(not a blob)"));
514 const uint8_t * pkt = (const uint8_t *) data;
516 unsigned int v = *pkt;
524 plen = pgpLen(pkt+1, &hlen);
526 tag = (v >> 2) & 0xf;
527 plen = (1 << (v & 0x3));
528 hlen = pgpGrab(pkt+1, plen);
531 pktlen = 1 + plen + hlen;
534 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
535 val = xstrdup(_("(not an OpenPGP signature)"));
537 pgpDig dig = pgpNewDig();
538 pgpDigParams sigp = &dig->signature;
540 char *tempstr = NULL;
542 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
547 val = t = xrealloc(val, nb + 1);
549 switch (sigp->pubkey_algo) {
550 case PGPPUBKEYALGO_DSA:
551 t = stpcpy(t, "DSA");
553 case PGPPUBKEYALGO_RSA:
554 t = stpcpy(t, "RSA");
557 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
561 if (t + 5 >= val + nb)
564 switch (sigp->hash_algo) {
565 case PGPHASHALGO_MD5:
566 t = stpcpy(t, "MD5");
568 case PGPHASHALGO_SHA1:
569 t = stpcpy(t, "SHA1");
572 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
576 if (t + strlen (", ") + 1 >= val + nb)
581 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
582 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
583 struct tm * tstruct = localtime(&dateint);
585 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
588 if (t + strlen (", Key ID ") + 1 >= val + nb)
590 t = stpcpy(t, ", Key ID ");
591 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
592 if (t + strlen (tempstr) > val + nb)
594 t = stpcpy(t, tempstr);
597 dig = pgpFreeDig(dig);
605 * Format dependency flags for display.
606 * @param type tag type
607 * @param data tag value
608 * @param formatPrefix
610 * @param element (unused)
611 * @return formatted string
613 static char * depflagsFormat(rpmTagType type, rpm_constdata_t data,
614 char * formatPrefix, size_t padding, int element)
620 if (type != RPM_INT32_TYPE) {
621 val = xstrdup(_("(not a number)"));
623 anint = *((const rpm_flag_t *) data);
626 if (anint & RPMSENSE_LESS)
628 if (anint & RPMSENSE_GREATER)
630 if (anint & RPMSENSE_EQUAL)
633 val = xmalloc(5 + padding);
634 strcat(formatPrefix, "s");
635 sprintf(val, formatPrefix, buf);
642 * Retrieve mounted file system paths.
644 * @retval td tag data container
645 * @return 0 on success
647 static int fsnamesTag(Header h, rpmtd td)
651 if (rpmGetFilesystemList(&list, &(td->count)))
654 td->type = RPM_STRING_ARRAY_TYPE;
662 * Retrieve install prefixes.
664 * @retval td tag data container
665 * @return 0 on success
667 static int instprefixTag(Header h, rpmtd td)
669 struct rpmtd_s prefixes;
670 int flags = HEADERGET_MINMEM;
672 if (headerGet(h, RPMTAG_INSTALLPREFIX, td, flags)) {
674 } else if (headerGet(h, RPMTAG_INSTPREFIXES, &prefixes, flags)) {
675 /* only return the first prefix of the array */
676 td->type = RPM_STRING_TYPE;
677 td->data = rpmtdToString(&prefixes);
679 rpmtdFreeData(&prefixes);
687 * Retrieve mounted file system space.
689 * @retval td tag data container
690 * @return 0 on success
692 static int fssizesTag(Header h, rpmtd td)
694 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
695 const char ** filenames;
696 rpm_off_t * filesizes;
698 rpm_count_t numFiles;
700 if (!hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &filesizes, &numFiles)) {
705 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
708 if (rpmGetFilesystemList(NULL, &(td->count)))
711 td->type = RPM_INT32_TYPE;
714 if (filenames == NULL) {
715 usages = xcalloc((td->count), sizeof(usages));
721 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
726 filenames = _free(filenames);
732 * Retrieve trigger info.
734 * @retval td tag data container
735 * @return 0 on success
737 static int triggercondsTag(Header h, rpmtd td)
739 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
740 HFD_t hfd = headerFreeData;
741 rpmTagType tnt, tvt, tst;
743 char ** names, ** versions;
744 rpm_count_t numNames, numScripts;
748 char * item, * flagsStr;
753 if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (rpm_data_t *) &names, &numNames)) {
758 xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, NULL);
759 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
760 xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (rpm_data_t *) &versions, NULL);
761 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
765 td->data = conds = xmalloc(sizeof(*conds) * numScripts);
766 td->count = numScripts;
767 td->type = RPM_STRING_ARRAY_TYPE;
768 for (i = 0; i < numScripts; i++) {
771 for (j = 0; j < numNames; j++) {
775 item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
776 if (flags[j] & RPMSENSE_SENSEMASK) {
777 buf[0] = '%', buf[1] = '\0';
778 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, 0);
779 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
780 flagsStr = _free(flagsStr);
782 strcpy(item, names[j]);
785 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
786 if (*chptr != '\0') strcat(chptr, ", ");
794 names = hfd(names, tnt);
795 versions = hfd(versions, tvt);
801 * Retrieve trigger type info.
803 * @retval td tag data container
804 * @return 0 on success
806 static int triggertypeTag(Header h, rpmtd td)
808 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
809 HFD_t hfd = headerFreeData;
815 rpm_count_t numScripts, numNames;
819 if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, &numNames)) {
824 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
825 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
829 td->data = conds = xmalloc(sizeof(*conds) * numScripts);
830 td->count = numScripts;
831 td->type = RPM_STRING_ARRAY_TYPE;
832 for (i = 0; i < numScripts; i++) {
833 for (j = 0; j < numNames; j++) {
837 if (flags[j] & RPMSENSE_TRIGGERPREIN)
838 conds[i] = xstrdup("prein");
839 else if (flags[j] & RPMSENSE_TRIGGERIN)
840 conds[i] = xstrdup("in");
841 else if (flags[j] & RPMSENSE_TRIGGERUN)
842 conds[i] = xstrdup("un");
843 else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
844 conds[i] = xstrdup("postun");
846 conds[i] = xstrdup("");
855 * Retrieve file paths.
857 * @retval td tag data container
858 * @return 0 on success
860 static int filenamesTag(Header h, rpmtd td)
862 td->type = RPM_STRING_ARRAY_TYPE;
863 rpmfiBuildFNames(h, RPMTAG_BASENAMES,
864 (const char ***) &(td->data), &(td->count));
870 * Retrieve file classes.
872 * @retval td tag data container
873 * @return 0 on success
875 static int fileclassTag(Header h, rpmtd td)
877 td->type = RPM_STRING_ARRAY_TYPE;
878 rpmfiBuildFClasses(h, (const char ***) &(td->data), &(td->count));
884 * Retrieve file provides.
886 * @retval td tag data container
887 * @return 0 on success
889 static int fileprovideTag(Header h, rpmtd td)
891 td->type = RPM_STRING_ARRAY_TYPE;
892 rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME,
893 (const char ***) &(td->data), &(td->count));
899 * Retrieve file requires.
901 * @retval td tag data container
902 * @return 0 on success
904 static int filerequireTag(Header h, rpmtd td)
906 td->type = RPM_STRING_ARRAY_TYPE;
907 rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME,
908 (const char ***) &(td->data), &(td->count));
913 /* I18N look aside diversions */
915 #if defined(ENABLE_NLS)
916 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
918 static const char * const language = "LANGUAGE";
920 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
923 * Retrieve i18n text.
926 * @retval td tag data container
927 * @return 0 on success
929 static int i18nTag(Header h, rpmTag tag, rpmtd td)
931 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
934 td->type = RPM_STRING_TYPE;
939 if (dstring && *dstring) {
941 const char * langval;
947 xx = headerNVR(h, &n, NULL, NULL);
948 rasprintf(&msgkey, "%s(%s)", n, rpmTagGetName(tag));
950 /* change to en_US for msgkey -> msgid resolution */
951 langval = getenv(language);
952 (void) setenv(language, "en_US", 1);
953 #if defined(ENABLE_NLS)
958 for (domain = dstring; domain != NULL; domain = de) {
959 de = strchr(domain, ':');
960 if (de) *de++ = '\0';
961 msgid = dgettext(domain, msgkey);
962 if (msgid != msgkey) break;
965 /* restore previous environment for msgid -> msgstr resolution */
967 (void) setenv(language, langval, 1);
970 #if defined(ENABLE_NLS)
974 if (domain && msgid) {
975 td->data = dgettext(domain, msgid);
976 td->data = xstrdup(td->data); /* XXX xstrdup has side effects. */
980 dstring = _free(dstring);
986 dstring = _free(dstring);
988 rc = headerGet(h, tag, td, HEADERGET_DEFAULT);
989 /* XXX fix the mismatch between headerGet and tag format returns */
994 * Retrieve summary text.
996 * @retval td tag data container
997 * @return 0 on success
999 static int summaryTag(Header h, rpmtd td)
1001 return i18nTag(h, RPMTAG_SUMMARY, td);
1005 * Retrieve description text.
1007 * @retval td tag data container
1008 * @return 0 on success
1010 static int descriptionTag(Header h, rpmtd td)
1012 return i18nTag(h, RPMTAG_DESCRIPTION, td);
1016 * Retrieve group text.
1018 * @retval td tag data container
1019 * @return 0 on success
1021 static int groupTag(Header h, rpmtd td)
1023 return i18nTag(h, RPMTAG_GROUP, td);
1026 void *rpmHeaderTagFunc(rpmTag tag)
1028 const struct headerTagFunc_s * ext;
1031 for (ext = rpmHeaderTagExtensions; ext->func != NULL; ext++) {
1032 if (ext->tag == tag) {
1040 void *rpmHeaderFormatFunc(const char *fmt)
1042 const struct headerFormatFunc_s * ext;
1045 for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
1046 if (!strcmp(ext->name, fmt)) {
1054 static const struct headerTagFunc_s rpmHeaderTagExtensions[] = {
1055 { RPMTAG_GROUP, groupTag },
1056 { RPMTAG_DESCRIPTION, descriptionTag },
1057 { RPMTAG_SUMMARY, summaryTag },
1058 { RPMTAG_FILECLASS, fileclassTag },
1059 { RPMTAG_FILENAMES, filenamesTag },
1060 { RPMTAG_FILEPROVIDE, fileprovideTag },
1061 { RPMTAG_FILEREQUIRE, filerequireTag },
1062 { RPMTAG_FSNAMES, fsnamesTag },
1063 { RPMTAG_FSSIZES, fssizesTag },
1064 { RPMTAG_INSTALLPREFIX, instprefixTag },
1065 { RPMTAG_TRIGGERCONDS, triggercondsTag },
1066 { RPMTAG_TRIGGERTYPE, triggertypeTag },
1070 static const struct headerFormatFunc_s rpmHeaderFormats[] = {
1071 { "armor", armorFormat },
1072 { "base64", base64Format },
1073 { "pgpsig", pgpsigFormat },
1074 { "depflags", depflagsFormat },
1075 { "fflags", fflagsFormat },
1076 { "perms", permsFormat },
1077 { "permissions", permsFormat },
1078 { "triggertype", triggertypeFormat },
1079 { "xml", xmlFormat },
1080 { "octal", octalFormat },
1081 { "hex", hexFormat },
1082 { "date", dateFormat },
1083 { "day", dayFormat },
1084 { "shescape", shescapeFormat },