7 #include <rpm/rpmtag.h>
8 #include <rpm/rpmlib.h> /* rpmGetFilesystem*() */
10 #include <rpm/rpmmacro.h> /* XXX for %_i18ndomains */
11 #include <rpm/rpmfi.h>
13 #include "rpmio/digest.h"
14 #include "lib/manifest.h"
20 * Identify type of trigger.
21 * @param type tag type
22 * @param data tag value
23 * @param formatPrefix (unused)
24 * @param padding (unused)
25 * @param element (unused)
26 * @return formatted string
28 static char * triggertypeFormat(rpm_tagtype_t type, rpm_constdata_t data,
29 char * formatPrefix, size_t padding,
32 const int32_t * item = data;
35 if (type != RPM_INT32_TYPE)
36 val = xstrdup(_("(not a number)"));
37 else if (*item & RPMSENSE_TRIGGERPREIN)
38 val = xstrdup("prein");
39 else if (*item & RPMSENSE_TRIGGERIN)
41 else if (*item & RPMSENSE_TRIGGERUN)
43 else if (*item & RPMSENSE_TRIGGERPOSTUN)
44 val = xstrdup("postun");
51 * Format file permissions for display.
52 * @param type tag type
53 * @param data tag value
56 * @param element (unused)
57 * @return formatted string
59 static char * permsFormat(rpm_tagtype_t type, rpm_constdata_t data,
60 char * formatPrefix, size_t padding, int element)
65 if (type != RPM_INT32_TYPE) {
66 val = xstrdup(_("(not a number)"));
68 val = xmalloc(15 + padding);
69 strcat(formatPrefix, "s");
70 buf = rpmPermsString(*((const int32_t *) data));
71 sprintf(val, formatPrefix, buf);
79 * Format file flags for display.
80 * @param type tag type
81 * @param data tag value
84 * @param element (unused)
85 * @return formatted string
87 static char * fflagsFormat(rpm_tagtype_t type, rpm_constdata_t data,
88 char * formatPrefix, size_t padding, int element)
92 int anint = *((const int32_t *) data);
94 if (type != RPM_INT32_TYPE) {
95 val = xstrdup(_("(not a number)"));
98 if (anint & RPMFILE_DOC)
100 if (anint & RPMFILE_CONFIG)
102 if (anint & RPMFILE_SPECFILE)
104 if (anint & RPMFILE_MISSINGOK)
106 if (anint & RPMFILE_NOREPLACE)
108 if (anint & RPMFILE_GHOST)
110 if (anint & RPMFILE_LICENSE)
112 if (anint & RPMFILE_README)
115 val = xmalloc(5 + padding);
116 strcat(formatPrefix, "s");
117 sprintf(val, formatPrefix, buf);
124 * Wrap a pubkey in ascii armor for display.
125 * @todo Permit selectable display formats (i.e. binary).
126 * @param type tag type
127 * @param data tag value
128 * @param formatPrefix (unused)
129 * @param padding (unused)
130 * @param element no. bytes of binary data
131 * @return formatted string
133 static char * armorFormat(rpm_tagtype_t type, rpm_constdata_t data,
134 char * formatPrefix, size_t padding,
138 const unsigned char * s;
146 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
148 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
150 case RPM_STRING_TYPE:
151 case RPM_STRING_ARRAY_TYPE:
153 if (b64decode(enc, (void **)&bs, &ns))
154 return xstrdup(_("(not base64)"));
156 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
163 case RPM_I18NSTRING_TYPE:
165 return xstrdup(_("(invalid type)"));
169 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
170 return pgpArmorWrap(atype, s, ns);
174 * Encode binary data in base64 for display.
175 * @todo Permit selectable display formats (i.e. binary).
176 * @param type tag type
177 * @param data tag value
178 * @param formatPrefix (unused)
181 * @return formatted string
183 static char * base64Format(rpm_tagtype_t type, rpm_constdata_t data,
184 char * formatPrefix, size_t padding, int element)
188 if (type != RPM_BIN_TYPE) {
189 val = xstrdup(_("(not a blob)"));
193 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
197 if ((enc = b64encode(data, ns, -1)) != NULL) {
201 val = t = xmalloc(nt + padding + 1);
215 static size_t xmlstrlen(const char * s)
220 while ((c = *s++) != '\0')
223 case '<': case '>': len += 4; break;
224 case '&': len += 5; break;
225 default: len += 1; break;
233 static char * xmlstrcpy(char * t, const char * s)
238 while ((c = *s++) != '\0') {
240 case '<': te = stpcpy(te, "<"); break;
241 case '>': te = stpcpy(te, ">"); break;
242 case '&': te = stpcpy(te, "&"); break;
243 default: *te++ = c; break;
251 * Wrap tag data in simple header xml markup.
252 * @param type tag type
253 * @param data tag value
254 * @param formatPrefix
256 * @param element (unused)
257 * @return formatted string
259 static char * xmlFormat(rpm_tagtype_t type, rpm_constdata_t data,
260 char * formatPrefix, size_t padding,
263 const char * xtag = NULL;
265 char * val, * bs = NULL;
266 const char * s = NULL;
268 unsigned long anint = 0;
272 case RPM_I18NSTRING_TYPE:
273 case RPM_STRING_TYPE:
279 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
281 if ((bs = b64encode(data, ns, 0)) == NULL) {
282 /* XXX proper error handling would be better. */
283 bs = xcalloc(1, padding + (ns / 3) * 4 + 1);
290 anint = *((const uint8_t *) data);
293 anint = *((const uint16_t *) data);
296 anint = *((const uint32_t *) data);
299 case RPM_STRING_ARRAY_TYPE:
301 return xstrdup(_("(invalid xml type)"));
307 t = memset(alloca(tlen+1), 0, tlen+1);
309 xx = snprintf(t, tlen, "%lu", anint);
316 nb += strlen(xtag) + sizeof("\t</>");
318 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
320 nb += 2 * strlen(xtag) + sizeof("\t<></>");
322 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
323 te = xmlstrcpy(te, s);
325 te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
328 /* XXX s was malloc'd */
329 if (!strcmp(xtag, "base64"))
334 strcat(formatPrefix, "s");
335 xx = snprintf(val, nb, formatPrefix, t);
342 * Display signature fingerprint and time.
343 * @param type tag type
344 * @param data tag value
345 * @param formatPrefix (unused)
347 * @param element (unused)
348 * @return formatted string
350 static char * pgpsigFormat(rpm_tagtype_t type, rpm_constdata_t data,
351 char * formatPrefix, size_t padding,
356 if (type != RPM_BIN_TYPE) {
357 val = xstrdup(_("(not a blob)"));
359 const uint8_t * pkt = (const uint8_t *) data;
361 unsigned int v = *pkt;
369 plen = pgpLen(pkt+1, &hlen);
371 tag = (v >> 2) & 0xf;
372 plen = (1 << (v & 0x3));
373 hlen = pgpGrab(pkt+1, plen);
376 pktlen = 1 + plen + hlen;
379 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
380 val = xstrdup(_("(not an OpenPGP signature)"));
382 pgpDig dig = pgpNewDig();
383 pgpDigParams sigp = &dig->signature;
387 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
392 val = t = xrealloc(val, nb + 1);
394 switch (sigp->pubkey_algo) {
395 case PGPPUBKEYALGO_DSA:
396 t = stpcpy(t, "DSA");
398 case PGPPUBKEYALGO_RSA:
399 t = stpcpy(t, "RSA");
402 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
406 if (t + 5 >= val + nb)
409 switch (sigp->hash_algo) {
410 case PGPHASHALGO_MD5:
411 t = stpcpy(t, "MD5");
413 case PGPHASHALGO_SHA1:
414 t = stpcpy(t, "SHA1");
417 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
421 if (t + strlen (", ") + 1 >= val + nb)
426 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
427 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
428 struct tm * tstruct = localtime(&dateint);
430 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
433 if (t + strlen (", Key ID ") + 1 >= val + nb)
435 t = stpcpy(t, ", Key ID ");
436 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
437 if (t + strlen (tempstr) > val + nb)
439 t = stpcpy(t, tempstr);
441 dig = pgpFreeDig(dig);
449 * Format dependency flags for display.
450 * @param type tag type
451 * @param data tag value
452 * @param formatPrefix
454 * @param element (unused)
455 * @return formatted string
457 static char * depflagsFormat(rpm_tagtype_t type, rpm_constdata_t data,
458 char * formatPrefix, size_t padding, int element)
464 if (type != RPM_INT32_TYPE) {
465 val = xstrdup(_("(not a number)"));
467 anint = *((const int32_t *) data);
470 if (anint & RPMSENSE_LESS)
472 if (anint & RPMSENSE_GREATER)
474 if (anint & RPMSENSE_EQUAL)
477 val = xmalloc(5 + padding);
478 strcat(formatPrefix, "s");
479 sprintf(val, formatPrefix, buf);
486 * Retrieve mounted file system paths.
488 * @retval *type tag type
489 * @retval *data tag value
490 * @retval *count no. of data items
491 * @retval *freeData data-was-malloc'ed indicator
492 * @return 0 on success
494 static int fsnamesTag( Header h, int32_t * type,
495 rpm_data_t * data, rpm_count_t * count,
500 if (rpmGetFilesystemList(&list, count))
503 if (type) *type = RPM_STRING_ARRAY_TYPE;
504 if (data) *((const char ***) data) = list;
505 if (freeData) *freeData = 0;
511 * Retrieve install prefixes.
513 * @retval *type tag type
514 * @retval *data tag value
515 * @retval *count no. of data items
516 * @retval *freeData data-was-malloc'ed indicator
517 * @return 0 on success
519 static int instprefixTag(Header h, rpm_tagtype_t* type,
524 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
525 HFD_t hfd = headerFreeData;
529 if (hge(h, RPMTAG_INSTALLPREFIX, type, (rpm_data_t *)data, count)) {
530 if (freeData) *freeData = 0;
532 } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (rpm_data_t *) &array, count)) {
533 if (type) *type = RPM_STRING_TYPE;
534 if (data) *data = xstrdup(array[0]);
535 if (freeData) *freeData = 1;
536 array = hfd(array, ipt);
544 * Retrieve mounted file system space.
546 * @retval *type tag type
547 * @retval *data tag value
548 * @retval *count no. of data items
549 * @retval *freeData data-was-malloc'ed indicator
550 * @return 0 on success
552 static int fssizesTag(Header h, rpm_tagtype_t* type,
553 rpm_data_t * data, rpm_count_t * count,
556 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
557 const char ** filenames;
558 rpm_off_t * filesizes;
560 rpm_count_t numFiles;
562 if (!hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &filesizes, &numFiles)) {
567 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
570 if (rpmGetFilesystemList(NULL, count))
573 *type = RPM_INT32_TYPE;
576 if (filenames == NULL) {
577 usages = xcalloc((*count), sizeof(usages));
583 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
588 filenames = _free(filenames);
594 * Retrieve trigger info.
596 * @retval *type tag type
597 * @retval *data tag value
598 * @retval *count no. of data items
599 * @retval *freeData data-was-malloc'ed indicator
600 * @return 0 on success
602 static int triggercondsTag(Header h, rpm_tagtype_t* type,
603 rpm_data_t * data, rpm_count_t * count,
606 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
607 HFD_t hfd = headerFreeData;
608 rpm_tagtype_t tnt, tvt, tst;
609 int32_t * indices, * flags;
610 char ** names, ** versions;
611 rpm_count_t numNames, numScripts;
614 char * item, * flagsStr;
619 if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (rpm_data_t *) &names, &numNames)) {
624 xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, NULL);
625 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
626 xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (rpm_data_t *) &versions, NULL);
627 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
631 *data = conds = xmalloc(sizeof(*conds) * numScripts);
633 *type = RPM_STRING_ARRAY_TYPE;
634 for (i = 0; i < numScripts; i++) {
637 for (j = 0; j < numNames; j++) {
641 item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
642 if (flags[j] & RPMSENSE_SENSEMASK) {
643 buf[0] = '%', buf[1] = '\0';
644 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, 0);
645 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
646 flagsStr = _free(flagsStr);
648 strcpy(item, names[j]);
651 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
652 if (*chptr != '\0') strcat(chptr, ", ");
660 names = hfd(names, tnt);
661 versions = hfd(versions, tvt);
667 * Retrieve trigger type info.
669 * @retval *type tag type
670 * @retval *data tag value
671 * @retval *count no. of data items
672 * @retval *freeData data-was-malloc'ed indicator
673 * @return 0 on success
675 static int triggertypeTag(Header h, rpm_tagtype_t* type,
676 rpm_data_t * data, rpm_count_t * count,
679 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
680 HFD_t hfd = headerFreeData;
682 int32_t * indices, * flags;
686 rpm_count_t numScripts, numNames;
689 if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, &numNames)) {
694 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
695 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
699 *data = conds = xmalloc(sizeof(*conds) * numScripts);
701 *type = RPM_STRING_ARRAY_TYPE;
702 for (i = 0; i < numScripts; i++) {
703 for (j = 0; j < numNames; j++) {
707 if (flags[j] & RPMSENSE_TRIGGERPREIN)
708 conds[i] = xstrdup("prein");
709 else if (flags[j] & RPMSENSE_TRIGGERIN)
710 conds[i] = xstrdup("in");
711 else if (flags[j] & RPMSENSE_TRIGGERUN)
712 conds[i] = xstrdup("un");
713 else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
714 conds[i] = xstrdup("postun");
716 conds[i] = xstrdup("");
725 * Retrieve file paths.
727 * @retval *type tag type
728 * @retval *data tag value
729 * @retval *count no. of data items
730 * @retval *freeData data-was-malloc'ed indicator
731 * @return 0 on success
733 static int filenamesTag(Header h, rpm_tagtype_t* type,
734 rpm_data_t * data, rpm_count_t * count,
737 *type = RPM_STRING_ARRAY_TYPE;
738 rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
744 * Retrieve file classes.
746 * @retval *type tag type
747 * @retval *data tag value
748 * @retval *count no. of data items
749 * @retval *freeData data-was-malloc'ed indicator
750 * @return 0 on success
752 static int fileclassTag(Header h, rpm_tagtype_t* type,
753 rpm_data_t * data, rpm_count_t * count,
756 *type = RPM_STRING_ARRAY_TYPE;
757 rpmfiBuildFClasses(h, (const char ***) data, count);
763 * Retrieve file provides.
765 * @retval *type tag type
766 * @retval *data tag value
767 * @retval *count no. of data items
768 * @retval *freeData data-was-malloc'ed indicator
769 * @return 0 on success
771 static int fileprovideTag(Header h, rpm_tagtype_t* type,
772 rpm_data_t * data, rpm_count_t * count,
775 *type = RPM_STRING_ARRAY_TYPE;
776 rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
782 * Retrieve file requires.
784 * @retval *type tag type
785 * @retval *data tag value
786 * @retval *count no. of data items
787 * @retval *freeData data-was-malloc'ed indicator
788 * @return 0 on success
790 static int filerequireTag(Header h, rpm_tagtype_t* type,
791 rpm_data_t * data, rpm_count_t * count,
794 *type = RPM_STRING_ARRAY_TYPE;
795 rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
800 /* I18N look aside diversions */
802 #if defined(ENABLE_NLS)
803 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
805 static const char * language = "LANGUAGE";
807 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
810 * Retrieve i18n text.
813 * @retval *type tag type
814 * @retval *data tag value
815 * @retval *count no. of data items
816 * @retval *freeData data-was-malloc'ed indicator
817 * @return 0 on success
819 static int i18nTag(Header h, rpm_tag_t tag, rpm_tagtype_t* type,
820 rpm_data_t * data, rpm_count_t * count,
823 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
824 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
827 *type = RPM_STRING_TYPE;
832 if (dstring && *dstring) {
834 const char * langval;
838 { const char * tn = rpmTagGetName(tag);
841 size_t nb = sizeof("()");
843 xx = headerNVR(h, &n, NULL, NULL);
844 if (tn) nb += strlen(tn);
845 if (n) nb += strlen(n);
847 sprintf(mk, "%s(%s)", n, tn);
851 /* change to en_US for msgkey -> msgid resolution */
852 langval = getenv(language);
853 (void) setenv(language, "en_US", 1);
854 #if defined(ENABLE_NLS)
859 for (domain = dstring; domain != NULL; domain = de) {
860 de = strchr(domain, ':');
861 if (de) *de++ = '\0';
862 msgid = dgettext(domain, msgkey);
863 if (msgid != msgkey) break;
866 /* restore previous environment for msgid -> msgstr resolution */
868 (void) setenv(language, langval, 1);
871 #if defined(ENABLE_NLS)
875 if (domain && msgid) {
876 *data = dgettext(domain, msgid);
877 *data = xstrdup(*data); /* XXX xstrdup has side effects. */
881 dstring = _free(dstring);
886 dstring = _free(dstring);
888 rc = hge(h, tag, type, data, count);
890 if (rc && (*data) != NULL) {
891 *data = xstrdup(*data);
903 * Retrieve summary text.
905 * @retval *type tag type
906 * @retval *data tag value
907 * @retval *count no. of data items
908 * @retval *freeData data-was-malloc'ed indicator
909 * @return 0 on success
911 static int summaryTag(Header h, rpm_tagtype_t* type,
912 rpm_data_t * data, rpm_count_t * count,
915 return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
919 * Retrieve description text.
921 * @retval *type tag type
922 * @retval *data tag value
923 * @retval *count no. of data items
924 * @retval *freeData data-was-malloc'ed indicator
925 * @return 0 on success
927 static int descriptionTag(Header h, rpm_tagtype_t* type,
928 rpm_data_t * data, rpm_count_t * count,
931 return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
935 * Retrieve group text.
937 * @retval *type tag type
938 * @retval *data tag value
939 * @retval *count no. of data items
940 * @retval *freeData data-was-malloc'ed indicator
941 * @return 0 on success
943 static int groupTag(Header h, rpm_tagtype_t* type,
944 rpm_data_t * data, rpm_count_t * count,
947 return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
951 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
952 { HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } },
953 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } },
954 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } },
955 { HEADER_EXT_TAG, "RPMTAG_FILECLASS", { fileclassTag } },
956 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } },
957 { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE", { fileprovideTag } },
958 { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE", { filerequireTag } },
959 { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } },
960 { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } },
961 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } },
962 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } },
963 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } },
964 { HEADER_EXT_FORMAT, "armor", { armorFormat } },
965 { HEADER_EXT_FORMAT, "base64", { base64Format } },
966 { HEADER_EXT_FORMAT, "pgpsig", { pgpsigFormat } },
967 { HEADER_EXT_FORMAT, "depflags", { depflagsFormat } },
968 { HEADER_EXT_FORMAT, "fflags", { fflagsFormat } },
969 { HEADER_EXT_FORMAT, "perms", { permsFormat } },
970 { HEADER_EXT_FORMAT, "permissions", { permsFormat } },
971 { HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } },
972 { HEADER_EXT_FORMAT, "xml", { xmlFormat } },
973 { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } }