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"
21 * Identify type of trigger.
22 * @param type tag type
23 * @param data tag value
24 * @param formatPrefix (unused)
25 * @param padding (unused)
26 * @param element (unused)
27 * @return formatted string
29 static char * triggertypeFormat(rpmTagType type, rpm_constdata_t data,
30 char * formatPrefix, size_t padding,
33 const int32_t * item = data;
36 if (type != RPM_INT32_TYPE)
37 val = xstrdup(_("(not a number)"));
38 else if (*item & RPMSENSE_TRIGGERPREIN)
39 val = xstrdup("prein");
40 else if (*item & RPMSENSE_TRIGGERIN)
42 else if (*item & RPMSENSE_TRIGGERUN)
44 else if (*item & RPMSENSE_TRIGGERPOSTUN)
45 val = xstrdup("postun");
52 * Format file permissions for display.
53 * @param type tag type
54 * @param data tag value
57 * @param element (unused)
58 * @return formatted string
60 static char * permsFormat(rpmTagType type, rpm_constdata_t data,
61 char * formatPrefix, size_t padding, int element)
66 if (type != RPM_INT32_TYPE) {
67 val = xstrdup(_("(not a number)"));
69 val = xmalloc(15 + padding);
70 strcat(formatPrefix, "s");
71 buf = rpmPermsString(*((const int32_t *) data));
72 sprintf(val, formatPrefix, buf);
80 * Format file flags for display.
81 * @param type tag type
82 * @param data tag value
85 * @param element (unused)
86 * @return formatted string
88 static char * fflagsFormat(rpmTagType type, rpm_constdata_t data,
89 char * formatPrefix, size_t padding, int element)
93 rpmfileAttrs anint = *((const rpm_flag_t *) data);
95 if (type != RPM_INT32_TYPE) {
96 val = xstrdup(_("(not a number)"));
99 if (anint & RPMFILE_DOC)
101 if (anint & RPMFILE_CONFIG)
103 if (anint & RPMFILE_SPECFILE)
105 if (anint & RPMFILE_MISSINGOK)
107 if (anint & RPMFILE_NOREPLACE)
109 if (anint & RPMFILE_GHOST)
111 if (anint & RPMFILE_LICENSE)
113 if (anint & RPMFILE_README)
116 val = xmalloc(5 + padding);
117 strcat(formatPrefix, "s");
118 sprintf(val, formatPrefix, buf);
125 * Wrap a pubkey in ascii armor for display.
126 * @todo Permit selectable display formats (i.e. binary).
127 * @param type tag type
128 * @param data tag value
129 * @param formatPrefix (unused)
130 * @param padding (unused)
131 * @param element no. bytes of binary data
132 * @return formatted string
134 static char * armorFormat(rpmTagType type, rpm_constdata_t data,
135 char * formatPrefix, size_t padding,
139 const unsigned char * s;
140 unsigned char * bs = NULL;
148 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
150 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
152 case RPM_STRING_TYPE:
153 case RPM_STRING_ARRAY_TYPE:
155 if (b64decode(enc, (void **)&bs, &ns))
156 return xstrdup(_("(not base64)"));
158 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
165 case RPM_I18NSTRING_TYPE:
167 return xstrdup(_("(invalid type)"));
171 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
172 val = pgpArmorWrap(atype, s, ns);
173 if (atype == PGPARMOR_PUBKEY) {
180 * Encode binary data in base64 for display.
181 * @todo Permit selectable display formats (i.e. binary).
182 * @param type tag type
183 * @param data tag value
184 * @param formatPrefix (unused)
187 * @return formatted string
189 static char * base64Format(rpmTagType type, rpm_constdata_t data,
190 char * formatPrefix, size_t padding, int element)
194 if (type != RPM_BIN_TYPE) {
195 val = xstrdup(_("(not a blob)"));
199 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
203 if ((enc = b64encode(data, ns, -1)) != NULL) {
207 val = t = xmalloc(nt + padding + 1);
220 * Wrap tag data in simple header xml markup.
221 * @param type tag type
222 * @param data tag value
223 * @param formatPrefix
225 * @param element (unused)
226 * @return formatted string
228 static char * xmlFormat(rpmTagType type, rpm_constdata_t data,
229 char * formatPrefix, size_t padding,
232 const char *xtag = NULL;
237 unsigned long anint = 0;
241 case RPM_I18NSTRING_TYPE:
242 case RPM_STRING_TYPE:
248 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
250 if ((s = b64encode(data, ns, 0)) == NULL) {
251 return xstrdup(_("(encoding failed)"));
257 anint = *((const uint8_t *) data);
260 anint = *((const uint16_t *) data);
263 anint = *((const uint32_t *) data);
266 case RPM_STRING_ARRAY_TYPE:
268 return xstrdup(_("(invalid xml type)"));
274 rasprintf(&s, "%lu", anint);
282 t = rstrscat(NULL, "\t<", xtag, "/>", NULL);
285 size_t i, s_size = strlen(s);
287 for (i=0; i<s_size; i++) {
289 case '<': rstrcat(&new_s, "<"); break;
290 case '>': rstrcat(&new_s, ">"); break;
291 case '&': rstrcat(&new_s, "&"); break;
301 t = rstrscat(NULL, "\t<", xtag, ">", new_s, "</", xtag, ">", NULL);
305 /* XXX s was malloc'd */
306 if (!strcmp(xtag, "base64") || !strcmp(xtag, "integer"))
309 nb += strlen(t)+padding;
311 strcat(formatPrefix, "s");
312 xx = snprintf(val, nb, formatPrefix, t);
320 * Display signature fingerprint and time.
321 * @param type tag type
322 * @param data tag value
323 * @param formatPrefix (unused)
325 * @param element (unused)
326 * @return formatted string
328 static char * pgpsigFormat(rpmTagType type, rpm_constdata_t data,
329 char * formatPrefix, size_t padding,
334 if (type != RPM_BIN_TYPE) {
335 val = xstrdup(_("(not a blob)"));
337 const uint8_t * pkt = (const uint8_t *) data;
339 unsigned int v = *pkt;
347 plen = pgpLen(pkt+1, &hlen);
349 tag = (v >> 2) & 0xf;
350 plen = (1 << (v & 0x3));
351 hlen = pgpGrab(pkt+1, plen);
354 pktlen = 1 + plen + hlen;
357 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
358 val = xstrdup(_("(not an OpenPGP signature)"));
360 pgpDig dig = pgpNewDig();
361 pgpDigParams sigp = &dig->signature;
363 char *tempstr = NULL;
365 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
370 val = t = xrealloc(val, nb + 1);
372 switch (sigp->pubkey_algo) {
373 case PGPPUBKEYALGO_DSA:
374 t = stpcpy(t, "DSA");
376 case PGPPUBKEYALGO_RSA:
377 t = stpcpy(t, "RSA");
380 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
384 if (t + 5 >= val + nb)
387 switch (sigp->hash_algo) {
388 case PGPHASHALGO_MD5:
389 t = stpcpy(t, "MD5");
391 case PGPHASHALGO_SHA1:
392 t = stpcpy(t, "SHA1");
395 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
399 if (t + strlen (", ") + 1 >= val + nb)
404 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
405 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
406 struct tm * tstruct = localtime(&dateint);
408 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
411 if (t + strlen (", Key ID ") + 1 >= val + nb)
413 t = stpcpy(t, ", Key ID ");
414 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
415 if (t + strlen (tempstr) > val + nb)
417 t = stpcpy(t, tempstr);
420 dig = pgpFreeDig(dig);
428 * Format dependency flags for display.
429 * @param type tag type
430 * @param data tag value
431 * @param formatPrefix
433 * @param element (unused)
434 * @return formatted string
436 static char * depflagsFormat(rpmTagType type, rpm_constdata_t data,
437 char * formatPrefix, size_t padding, int element)
443 if (type != RPM_INT32_TYPE) {
444 val = xstrdup(_("(not a number)"));
446 anint = *((const rpm_flag_t *) data);
449 if (anint & RPMSENSE_LESS)
451 if (anint & RPMSENSE_GREATER)
453 if (anint & RPMSENSE_EQUAL)
456 val = xmalloc(5 + padding);
457 strcat(formatPrefix, "s");
458 sprintf(val, formatPrefix, buf);
465 * Retrieve mounted file system paths.
467 * @retval *type tag type
468 * @retval *data tag value
469 * @retval *count no. of data items
470 * @retval *freeData data-was-malloc'ed indicator
471 * @return 0 on success
473 static int fsnamesTag( Header h, int32_t * type,
474 rpm_data_t * data, rpm_count_t * count,
479 if (rpmGetFilesystemList(&list, count))
482 if (type) *type = RPM_STRING_ARRAY_TYPE;
483 if (data) *((const char ***) data) = list;
484 if (freeData) *freeData = 0;
490 * Retrieve install prefixes.
492 * @retval *type tag type
493 * @retval *data tag value
494 * @retval *count no. of data items
495 * @retval *freeData data-was-malloc'ed indicator
496 * @return 0 on success
498 static int instprefixTag(Header h, rpmTagType* type,
503 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
504 HFD_t hfd = headerFreeData;
508 if (hge(h, RPMTAG_INSTALLPREFIX, type, (rpm_data_t *)data, count)) {
509 if (freeData) *freeData = 0;
511 } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (rpm_data_t *) &array, count)) {
512 if (type) *type = RPM_STRING_TYPE;
513 if (data) *data = xstrdup(array[0]);
514 if (freeData) *freeData = 1;
515 array = hfd(array, ipt);
523 * Retrieve mounted file system space.
525 * @retval *type tag type
526 * @retval *data tag value
527 * @retval *count no. of data items
528 * @retval *freeData data-was-malloc'ed indicator
529 * @return 0 on success
531 static int fssizesTag(Header h, rpmTagType* type,
532 rpm_data_t * data, rpm_count_t * count,
535 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
536 const char ** filenames;
537 rpm_off_t * filesizes;
539 rpm_count_t numFiles;
541 if (!hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &filesizes, &numFiles)) {
546 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
549 if (rpmGetFilesystemList(NULL, count))
552 *type = RPM_INT32_TYPE;
555 if (filenames == NULL) {
556 usages = xcalloc((*count), sizeof(usages));
562 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
567 filenames = _free(filenames);
573 * Retrieve trigger info.
575 * @retval *type tag type
576 * @retval *data tag value
577 * @retval *count no. of data items
578 * @retval *freeData data-was-malloc'ed indicator
579 * @return 0 on success
581 static int triggercondsTag(Header h, rpmTagType* type,
582 rpm_data_t * data, rpm_count_t * count,
585 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
586 HFD_t hfd = headerFreeData;
587 rpmTagType tnt, tvt, tst;
589 char ** names, ** versions;
590 rpm_count_t numNames, numScripts;
594 char * item, * flagsStr;
599 if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (rpm_data_t *) &names, &numNames)) {
604 xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, NULL);
605 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
606 xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (rpm_data_t *) &versions, NULL);
607 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
611 *data = conds = xmalloc(sizeof(*conds) * numScripts);
613 *type = RPM_STRING_ARRAY_TYPE;
614 for (i = 0; i < numScripts; i++) {
617 for (j = 0; j < numNames; j++) {
621 item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
622 if (flags[j] & RPMSENSE_SENSEMASK) {
623 buf[0] = '%', buf[1] = '\0';
624 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, 0);
625 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
626 flagsStr = _free(flagsStr);
628 strcpy(item, names[j]);
631 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
632 if (*chptr != '\0') strcat(chptr, ", ");
640 names = hfd(names, tnt);
641 versions = hfd(versions, tvt);
647 * Retrieve trigger type info.
649 * @retval *type tag type
650 * @retval *data tag value
651 * @retval *count no. of data items
652 * @retval *freeData data-was-malloc'ed indicator
653 * @return 0 on success
655 static int triggertypeTag(Header h, rpmTagType* type,
656 rpm_data_t * data, rpm_count_t * count,
659 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
660 HFD_t hfd = headerFreeData;
666 rpm_count_t numScripts, numNames;
670 if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, &numNames)) {
675 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
676 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
680 *data = conds = xmalloc(sizeof(*conds) * numScripts);
682 *type = RPM_STRING_ARRAY_TYPE;
683 for (i = 0; i < numScripts; i++) {
684 for (j = 0; j < numNames; j++) {
688 if (flags[j] & RPMSENSE_TRIGGERPREIN)
689 conds[i] = xstrdup("prein");
690 else if (flags[j] & RPMSENSE_TRIGGERIN)
691 conds[i] = xstrdup("in");
692 else if (flags[j] & RPMSENSE_TRIGGERUN)
693 conds[i] = xstrdup("un");
694 else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
695 conds[i] = xstrdup("postun");
697 conds[i] = xstrdup("");
706 * Retrieve file paths.
708 * @retval *type tag type
709 * @retval *data tag value
710 * @retval *count no. of data items
711 * @retval *freeData data-was-malloc'ed indicator
712 * @return 0 on success
714 static int filenamesTag(Header h, rpmTagType* type,
715 rpm_data_t * data, rpm_count_t * count,
718 *type = RPM_STRING_ARRAY_TYPE;
719 rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
725 * Retrieve file classes.
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 fileclassTag(Header h, rpmTagType* type,
734 rpm_data_t * data, rpm_count_t * count,
737 *type = RPM_STRING_ARRAY_TYPE;
738 rpmfiBuildFClasses(h, (const char ***) data, count);
744 * Retrieve file provides.
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 fileprovideTag(Header h, rpmTagType* type,
753 rpm_data_t * data, rpm_count_t * count,
756 *type = RPM_STRING_ARRAY_TYPE;
757 rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
763 * Retrieve file requires.
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 filerequireTag(Header h, rpmTagType* type,
772 rpm_data_t * data, rpm_count_t * count,
775 *type = RPM_STRING_ARRAY_TYPE;
776 rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
781 /* I18N look aside diversions */
783 #if defined(ENABLE_NLS)
784 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
786 static const char * const language = "LANGUAGE";
788 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
791 * Retrieve i18n text.
794 * @retval *type tag type
795 * @retval *data tag value
796 * @retval *count no. of data items
797 * @retval *freeData data-was-malloc'ed indicator
798 * @return 0 on success
800 static int i18nTag(Header h, rpmTag tag, rpmTagType* type,
801 rpm_data_t * data, rpm_count_t * count,
804 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
805 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
808 *type = RPM_STRING_TYPE;
813 if (dstring && *dstring) {
815 const char * langval;
821 xx = headerNVR(h, &n, NULL, NULL);
822 rasprintf(&msgkey, "%s(%s)", n, rpmTagGetName(tag));
824 /* change to en_US for msgkey -> msgid resolution */
825 langval = getenv(language);
826 (void) setenv(language, "en_US", 1);
827 #if defined(ENABLE_NLS)
832 for (domain = dstring; domain != NULL; domain = de) {
833 de = strchr(domain, ':');
834 if (de) *de++ = '\0';
835 msgid = dgettext(domain, msgkey);
836 if (msgid != msgkey) break;
839 /* restore previous environment for msgid -> msgstr resolution */
841 (void) setenv(language, langval, 1);
844 #if defined(ENABLE_NLS)
848 if (domain && msgid) {
849 *data = dgettext(domain, msgid);
850 *data = xstrdup(*data); /* XXX xstrdup has side effects. */
854 dstring = _free(dstring);
860 dstring = _free(dstring);
862 rc = hge(h, tag, type, data, count);
864 if (rc && (*data) != NULL) {
865 *data = xstrdup(*data);
877 * Retrieve summary text.
879 * @retval *type tag type
880 * @retval *data tag value
881 * @retval *count no. of data items
882 * @retval *freeData data-was-malloc'ed indicator
883 * @return 0 on success
885 static int summaryTag(Header h, rpmTagType* type,
886 rpm_data_t * data, rpm_count_t * count,
889 return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
893 * Retrieve description text.
895 * @retval *type tag type
896 * @retval *data tag value
897 * @retval *count no. of data items
898 * @retval *freeData data-was-malloc'ed indicator
899 * @return 0 on success
901 static int descriptionTag(Header h, rpmTagType* type,
902 rpm_data_t * data, rpm_count_t * count,
905 return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
909 * Retrieve group text.
911 * @retval *type tag type
912 * @retval *data tag value
913 * @retval *count no. of data items
914 * @retval *freeData data-was-malloc'ed indicator
915 * @return 0 on success
917 static int groupTag(Header h, rpmTagType* type,
918 rpm_data_t * data, rpm_count_t * count,
921 return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
925 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
926 { HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } },
927 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } },
928 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } },
929 { HEADER_EXT_TAG, "RPMTAG_FILECLASS", { fileclassTag } },
930 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } },
931 { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE", { fileprovideTag } },
932 { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE", { filerequireTag } },
933 { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } },
934 { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } },
935 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } },
936 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } },
937 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } },
938 { HEADER_EXT_FORMAT, "armor", { armorFormat } },
939 { HEADER_EXT_FORMAT, "base64", { base64Format } },
940 { HEADER_EXT_FORMAT, "pgpsig", { pgpsigFormat } },
941 { HEADER_EXT_FORMAT, "depflags", { depflagsFormat } },
942 { HEADER_EXT_FORMAT, "fflags", { fflagsFormat } },
943 { HEADER_EXT_FORMAT, "perms", { permsFormat } },
944 { HEADER_EXT_FORMAT, "permissions", { permsFormat } },
945 { HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } },
946 { HEADER_EXT_FORMAT, "xml", { xmlFormat } },
947 { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } }