6 #include "rpmio/digest.h"
7 #include <rpm/rpmlib.h>
9 #include <rpm/rpmmacro.h> /* XXX for %_i18ndomains */
11 #include <rpm/rpmfi.h>
13 #include "lib/manifest.h"
19 * Identify type of trigger.
20 * @param type tag type
21 * @param data tag value
22 * @param formatPrefix (unused)
23 * @param padding (unused)
24 * @param element (unused)
25 * @return formatted string
27 static char * triggertypeFormat(rpm_tagtype_t type, rpm_constdata_t data,
28 char * formatPrefix, size_t padding,
31 const int32_t * item = data;
34 if (type != RPM_INT32_TYPE)
35 val = xstrdup(_("(not a number)"));
36 else if (*item & RPMSENSE_TRIGGERPREIN)
37 val = xstrdup("prein");
38 else if (*item & RPMSENSE_TRIGGERIN)
40 else if (*item & RPMSENSE_TRIGGERUN)
42 else if (*item & RPMSENSE_TRIGGERPOSTUN)
43 val = xstrdup("postun");
50 * Format file permissions for display.
51 * @param type tag type
52 * @param data tag value
55 * @param element (unused)
56 * @return formatted string
58 static char * permsFormat(rpm_tagtype_t type, rpm_constdata_t data,
59 char * formatPrefix, size_t padding, int element)
64 if (type != RPM_INT32_TYPE) {
65 val = xstrdup(_("(not a number)"));
67 val = xmalloc(15 + padding);
68 strcat(formatPrefix, "s");
69 buf = rpmPermsString(*((const int32_t *) data));
70 sprintf(val, formatPrefix, buf);
78 * Format file flags for display.
79 * @param type tag type
80 * @param data tag value
83 * @param element (unused)
84 * @return formatted string
86 static char * fflagsFormat(rpm_tagtype_t type, rpm_constdata_t data,
87 char * formatPrefix, size_t padding, int element)
91 int anint = *((const int32_t *) data);
93 if (type != RPM_INT32_TYPE) {
94 val = xstrdup(_("(not a number)"));
97 if (anint & RPMFILE_DOC)
99 if (anint & RPMFILE_CONFIG)
101 if (anint & RPMFILE_SPECFILE)
103 if (anint & RPMFILE_MISSINGOK)
105 if (anint & RPMFILE_NOREPLACE)
107 if (anint & RPMFILE_GHOST)
109 if (anint & RPMFILE_LICENSE)
111 if (anint & RPMFILE_README)
114 val = xmalloc(5 + padding);
115 strcat(formatPrefix, "s");
116 sprintf(val, formatPrefix, buf);
123 * Wrap a pubkey in ascii armor for display.
124 * @todo Permit selectable display formats (i.e. binary).
125 * @param type tag type
126 * @param data tag value
127 * @param formatPrefix (unused)
128 * @param padding (unused)
129 * @param element no. bytes of binary data
130 * @return formatted string
132 static char * armorFormat(rpm_tagtype_t type, rpm_constdata_t data,
133 char * formatPrefix, size_t padding,
137 const unsigned char * s;
145 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
147 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
149 case RPM_STRING_TYPE:
150 case RPM_STRING_ARRAY_TYPE:
152 if (b64decode(enc, (void **)&bs, &ns))
153 return xstrdup(_("(not base64)"));
155 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
162 case RPM_I18NSTRING_TYPE:
164 return xstrdup(_("(invalid type)"));
168 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
169 return pgpArmorWrap(atype, s, ns);
173 * Encode binary data in base64 for display.
174 * @todo Permit selectable display formats (i.e. binary).
175 * @param type tag type
176 * @param data tag value
177 * @param formatPrefix (unused)
180 * @return formatted string
182 static char * base64Format(rpm_tagtype_t type, rpm_constdata_t data,
183 char * formatPrefix, size_t padding, int element)
187 if (type != RPM_BIN_TYPE) {
188 val = xstrdup(_("(not a blob)"));
192 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
196 if ((enc = b64encode(data, ns, -1)) != NULL) {
200 val = t = xmalloc(nt + padding + 1);
214 static size_t xmlstrlen(const char * s)
219 while ((c = *s++) != '\0')
222 case '<': case '>': len += 4; break;
223 case '&': len += 5; break;
224 default: len += 1; break;
232 static char * xmlstrcpy(char * t, const char * s)
237 while ((c = *s++) != '\0') {
239 case '<': te = stpcpy(te, "<"); break;
240 case '>': te = stpcpy(te, ">"); break;
241 case '&': te = stpcpy(te, "&"); break;
242 default: *te++ = c; break;
250 * Wrap tag data in simple header xml markup.
251 * @param type tag type
252 * @param data tag value
253 * @param formatPrefix
255 * @param element (unused)
256 * @return formatted string
258 static char * xmlFormat(rpm_tagtype_t type, rpm_constdata_t data,
259 char * formatPrefix, size_t padding,
262 const char * xtag = NULL;
264 char * val, * bs = NULL;
265 const char * s = NULL;
267 unsigned long anint = 0;
271 case RPM_I18NSTRING_TYPE:
272 case RPM_STRING_TYPE:
278 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
280 if ((bs = b64encode(data, ns, 0)) == NULL) {
281 /* XXX proper error handling would be better. */
282 bs = xcalloc(1, padding + (ns / 3) * 4 + 1);
289 anint = *((const uint8_t *) data);
292 anint = *((const uint16_t *) data);
295 anint = *((const uint32_t *) data);
298 case RPM_STRING_ARRAY_TYPE:
300 return xstrdup(_("(invalid xml type)"));
306 t = memset(alloca(tlen+1), 0, tlen+1);
308 xx = snprintf(t, tlen, "%lu", anint);
315 nb += strlen(xtag) + sizeof("\t</>");
317 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
319 nb += 2 * strlen(xtag) + sizeof("\t<></>");
321 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
322 te = xmlstrcpy(te, s);
324 te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
327 /* XXX s was malloc'd */
328 if (!strcmp(xtag, "base64"))
333 strcat(formatPrefix, "s");
334 xx = snprintf(val, nb, formatPrefix, t);
341 * Display signature fingerprint and time.
342 * @param type tag type
343 * @param data tag value
344 * @param formatPrefix (unused)
346 * @param element (unused)
347 * @return formatted string
349 static char * pgpsigFormat(rpm_tagtype_t type, rpm_constdata_t data,
350 char * formatPrefix, size_t padding,
355 if (type != RPM_BIN_TYPE) {
356 val = xstrdup(_("(not a blob)"));
358 const uint8_t * pkt = (const uint8_t *) data;
360 unsigned int v = *pkt;
368 plen = pgpLen(pkt+1, &hlen);
370 tag = (v >> 2) & 0xf;
371 plen = (1 << (v & 0x3));
372 hlen = pgpGrab(pkt+1, plen);
375 pktlen = 1 + plen + hlen;
378 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
379 val = xstrdup(_("(not an OpenPGP signature)"));
381 pgpDig dig = pgpNewDig();
382 pgpDigParams sigp = &dig->signature;
386 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
391 val = t = xrealloc(val, nb + 1);
393 switch (sigp->pubkey_algo) {
394 case PGPPUBKEYALGO_DSA:
395 t = stpcpy(t, "DSA");
397 case PGPPUBKEYALGO_RSA:
398 t = stpcpy(t, "RSA");
401 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
405 if (t + 5 >= val + nb)
408 switch (sigp->hash_algo) {
409 case PGPHASHALGO_MD5:
410 t = stpcpy(t, "MD5");
412 case PGPHASHALGO_SHA1:
413 t = stpcpy(t, "SHA1");
416 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
420 if (t + strlen (", ") + 1 >= val + nb)
425 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
426 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
427 struct tm * tstruct = localtime(&dateint);
429 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
432 if (t + strlen (", Key ID ") + 1 >= val + nb)
434 t = stpcpy(t, ", Key ID ");
435 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
436 if (t + strlen (tempstr) > val + nb)
438 t = stpcpy(t, tempstr);
440 dig = pgpFreeDig(dig);
448 * Format dependency flags for display.
449 * @param type tag type
450 * @param data tag value
451 * @param formatPrefix
453 * @param element (unused)
454 * @return formatted string
456 static char * depflagsFormat(rpm_tagtype_t type, rpm_constdata_t data,
457 char * formatPrefix, size_t padding, int element)
463 if (type != RPM_INT32_TYPE) {
464 val = xstrdup(_("(not a number)"));
466 anint = *((const int32_t *) data);
469 if (anint & RPMSENSE_LESS)
471 if (anint & RPMSENSE_GREATER)
473 if (anint & RPMSENSE_EQUAL)
476 val = xmalloc(5 + padding);
477 strcat(formatPrefix, "s");
478 sprintf(val, formatPrefix, buf);
485 * Retrieve mounted file system paths.
487 * @retval *type tag type
488 * @retval *data tag value
489 * @retval *count no. of data items
490 * @retval *freeData data-was-malloc'ed indicator
491 * @return 0 on success
493 static int fsnamesTag( Header h, int32_t * type,
494 rpm_data_t * data, rpm_count_t * count,
499 if (rpmGetFilesystemList(&list, count))
502 if (type) *type = RPM_STRING_ARRAY_TYPE;
503 if (data) *((const char ***) data) = list;
504 if (freeData) *freeData = 0;
510 * Retrieve install prefixes.
512 * @retval *type tag type
513 * @retval *data tag value
514 * @retval *count no. of data items
515 * @retval *freeData data-was-malloc'ed indicator
516 * @return 0 on success
518 static int instprefixTag(Header h, rpm_tagtype_t* type,
523 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
524 HFD_t hfd = headerFreeData;
528 if (hge(h, RPMTAG_INSTALLPREFIX, type, (rpm_data_t *)data, count)) {
529 if (freeData) *freeData = 0;
531 } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (rpm_data_t *) &array, count)) {
532 if (type) *type = RPM_STRING_TYPE;
533 if (data) *data = xstrdup(array[0]);
534 if (freeData) *freeData = 1;
535 array = hfd(array, ipt);
543 * Retrieve mounted file system space.
545 * @retval *type tag type
546 * @retval *data tag value
547 * @retval *count no. of data items
548 * @retval *freeData data-was-malloc'ed indicator
549 * @return 0 on success
551 static int fssizesTag(Header h, rpm_tagtype_t* type,
552 rpm_data_t * data, rpm_count_t * count,
555 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
556 const char ** filenames;
559 rpm_count_t numFiles;
561 if (!hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &filesizes, &numFiles)) {
566 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
569 if (rpmGetFilesystemList(NULL, count))
572 *type = RPM_INT32_TYPE;
575 if (filenames == NULL) {
576 usages = xcalloc((*count), sizeof(usages));
582 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
587 filenames = _free(filenames);
593 * Retrieve trigger info.
595 * @retval *type tag type
596 * @retval *data tag value
597 * @retval *count no. of data items
598 * @retval *freeData data-was-malloc'ed indicator
599 * @return 0 on success
601 static int triggercondsTag(Header h, rpm_tagtype_t* type,
602 rpm_data_t * data, rpm_count_t * count,
605 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
606 HFD_t hfd = headerFreeData;
607 rpm_tagtype_t tnt, tvt, tst;
608 int32_t * indices, * flags;
609 char ** names, ** versions;
610 rpm_count_t numNames, numScripts;
613 char * item, * flagsStr;
618 if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (rpm_data_t *) &names, &numNames)) {
623 xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, NULL);
624 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
625 xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (rpm_data_t *) &versions, NULL);
626 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
630 *data = conds = xmalloc(sizeof(*conds) * numScripts);
632 *type = RPM_STRING_ARRAY_TYPE;
633 for (i = 0; i < numScripts; i++) {
636 for (j = 0; j < numNames; j++) {
640 item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
641 if (flags[j] & RPMSENSE_SENSEMASK) {
642 buf[0] = '%', buf[1] = '\0';
643 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, 0);
644 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
645 flagsStr = _free(flagsStr);
647 strcpy(item, names[j]);
650 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
651 if (*chptr != '\0') strcat(chptr, ", ");
659 names = hfd(names, tnt);
660 versions = hfd(versions, tvt);
666 * Retrieve trigger type info.
668 * @retval *type tag type
669 * @retval *data tag value
670 * @retval *count no. of data items
671 * @retval *freeData data-was-malloc'ed indicator
672 * @return 0 on success
674 static int triggertypeTag(Header h, rpm_tagtype_t* type,
675 rpm_data_t * data, rpm_count_t * count,
678 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
679 HFD_t hfd = headerFreeData;
681 int32_t * indices, * flags;
685 rpm_count_t numScripts, numNames;
688 if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, &numNames)) {
693 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
694 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
698 *data = conds = xmalloc(sizeof(*conds) * numScripts);
700 *type = RPM_STRING_ARRAY_TYPE;
701 for (i = 0; i < numScripts; i++) {
702 for (j = 0; j < numNames; j++) {
706 if (flags[j] & RPMSENSE_TRIGGERPREIN)
707 conds[i] = xstrdup("prein");
708 else if (flags[j] & RPMSENSE_TRIGGERIN)
709 conds[i] = xstrdup("in");
710 else if (flags[j] & RPMSENSE_TRIGGERUN)
711 conds[i] = xstrdup("un");
712 else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
713 conds[i] = xstrdup("postun");
715 conds[i] = xstrdup("");
724 * Retrieve file paths.
726 * @retval *type tag type
727 * @retval *data tag value
728 * @retval *count no. of data items
729 * @retval *freeData data-was-malloc'ed indicator
730 * @return 0 on success
732 static int filenamesTag(Header h, rpm_tagtype_t* type,
733 rpm_data_t * data, rpm_count_t * count,
736 *type = RPM_STRING_ARRAY_TYPE;
737 rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
743 * Retrieve file classes.
745 * @retval *type tag type
746 * @retval *data tag value
747 * @retval *count no. of data items
748 * @retval *freeData data-was-malloc'ed indicator
749 * @return 0 on success
751 static int fileclassTag(Header h, rpm_tagtype_t* type,
752 rpm_data_t * data, rpm_count_t * count,
755 *type = RPM_STRING_ARRAY_TYPE;
756 rpmfiBuildFClasses(h, (const char ***) data, count);
762 * Retrieve file provides.
764 * @retval *type tag type
765 * @retval *data tag value
766 * @retval *count no. of data items
767 * @retval *freeData data-was-malloc'ed indicator
768 * @return 0 on success
770 static int fileprovideTag(Header h, rpm_tagtype_t* type,
771 rpm_data_t * data, rpm_count_t * count,
774 *type = RPM_STRING_ARRAY_TYPE;
775 rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
781 * Retrieve file requires.
783 * @retval *type tag type
784 * @retval *data tag value
785 * @retval *count no. of data items
786 * @retval *freeData data-was-malloc'ed indicator
787 * @return 0 on success
789 static int filerequireTag(Header h, rpm_tagtype_t* type,
790 rpm_data_t * data, rpm_count_t * count,
793 *type = RPM_STRING_ARRAY_TYPE;
794 rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
799 /* I18N look aside diversions */
801 #if defined(ENABLE_NLS)
802 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
804 static const char * language = "LANGUAGE";
806 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
809 * Retrieve i18n text.
812 * @retval *type tag type
813 * @retval *data tag value
814 * @retval *count no. of data items
815 * @retval *freeData data-was-malloc'ed indicator
816 * @return 0 on success
818 static int i18nTag(Header h, rpm_tag_t tag, rpm_tagtype_t* type,
819 rpm_data_t * data, rpm_count_t * count,
822 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
823 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
826 *type = RPM_STRING_TYPE;
831 if (dstring && *dstring) {
833 const char * langval;
837 { const char * tn = rpmTagGetName(tag);
840 size_t nb = sizeof("()");
842 xx = headerNVR(h, &n, NULL, NULL);
843 if (tn) nb += strlen(tn);
844 if (n) nb += strlen(n);
846 sprintf(mk, "%s(%s)", n, tn);
850 /* change to en_US for msgkey -> msgid resolution */
851 langval = getenv(language);
852 (void) setenv(language, "en_US", 1);
853 #if defined(ENABLE_NLS)
858 for (domain = dstring; domain != NULL; domain = de) {
859 de = strchr(domain, ':');
860 if (de) *de++ = '\0';
861 msgid = dgettext(domain, msgkey);
862 if (msgid != msgkey) break;
865 /* restore previous environment for msgid -> msgstr resolution */
867 (void) setenv(language, langval, 1);
870 #if defined(ENABLE_NLS)
874 if (domain && msgid) {
875 *data = dgettext(domain, msgid);
876 *data = xstrdup(*data); /* XXX xstrdup has side effects. */
880 dstring = _free(dstring);
885 dstring = _free(dstring);
887 rc = hge(h, tag, type, data, count);
889 if (rc && (*data) != NULL) {
890 *data = xstrdup(*data);
902 * Retrieve summary text.
904 * @retval *type tag type
905 * @retval *data tag value
906 * @retval *count no. of data items
907 * @retval *freeData data-was-malloc'ed indicator
908 * @return 0 on success
910 static int summaryTag(Header h, rpm_tagtype_t* type,
911 rpm_data_t * data, rpm_count_t * count,
914 return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
918 * Retrieve description text.
920 * @retval *type tag type
921 * @retval *data tag value
922 * @retval *count no. of data items
923 * @retval *freeData data-was-malloc'ed indicator
924 * @return 0 on success
926 static int descriptionTag(Header h, rpm_tagtype_t* type,
927 rpm_data_t * data, rpm_count_t * count,
930 return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
934 * Retrieve group text.
936 * @retval *type tag type
937 * @retval *data tag value
938 * @retval *count no. of data items
939 * @retval *freeData data-was-malloc'ed indicator
940 * @return 0 on success
942 static int groupTag(Header h, rpm_tagtype_t* type,
943 rpm_data_t * data, rpm_count_t * count,
946 return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
950 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
951 { HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } },
952 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } },
953 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } },
954 { HEADER_EXT_TAG, "RPMTAG_FILECLASS", { fileclassTag } },
955 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } },
956 { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE", { fileprovideTag } },
957 { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE", { filerequireTag } },
958 { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } },
959 { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } },
960 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } },
961 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } },
962 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } },
963 { HEADER_EXT_FORMAT, "armor", { armorFormat } },
964 { HEADER_EXT_FORMAT, "base64", { base64Format } },
965 { HEADER_EXT_FORMAT, "pgpsig", { pgpsigFormat } },
966 { HEADER_EXT_FORMAT, "depflags", { depflagsFormat } },
967 { HEADER_EXT_FORMAT, "fflags", { fflagsFormat } },
968 { HEADER_EXT_FORMAT, "perms", { permsFormat } },
969 { HEADER_EXT_FORMAT, "permissions", { permsFormat } },
970 { HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } },
971 { HEADER_EXT_FORMAT, "xml", { xmlFormat } },
972 { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } }