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;
147 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
149 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
151 case RPM_STRING_TYPE:
152 case RPM_STRING_ARRAY_TYPE:
154 if (b64decode(enc, (void **)&bs, &ns))
155 return xstrdup(_("(not base64)"));
157 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
164 case RPM_I18NSTRING_TYPE:
166 return xstrdup(_("(invalid type)"));
170 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
171 return pgpArmorWrap(atype, s, ns);
175 * Encode binary data in base64 for display.
176 * @todo Permit selectable display formats (i.e. binary).
177 * @param type tag type
178 * @param data tag value
179 * @param formatPrefix (unused)
182 * @return formatted string
184 static char * base64Format(rpmTagType type, rpm_constdata_t data,
185 char * formatPrefix, size_t padding, int element)
189 if (type != RPM_BIN_TYPE) {
190 val = xstrdup(_("(not a blob)"));
194 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
198 if ((enc = b64encode(data, ns, -1)) != NULL) {
202 val = t = xmalloc(nt + padding + 1);
216 static size_t xmlstrlen(const char * s)
221 while ((c = *s++) != '\0')
224 case '<': case '>': len += 4; break;
225 case '&': len += 5; break;
226 default: len += 1; break;
234 static char * xmlstrcpy(char * t, const char * s)
239 while ((c = *s++) != '\0') {
241 case '<': te = stpcpy(te, "<"); break;
242 case '>': te = stpcpy(te, ">"); break;
243 case '&': te = stpcpy(te, "&"); break;
244 default: *te++ = c; break;
252 * Wrap tag data in simple header xml markup.
253 * @param type tag type
254 * @param data tag value
255 * @param formatPrefix
257 * @param element (unused)
258 * @return formatted string
260 static char * xmlFormat(rpmTagType type, rpm_constdata_t data,
261 char * formatPrefix, size_t padding,
264 const char * xtag = NULL;
266 char * val, * bs = NULL;
267 const char * s = NULL;
269 unsigned long anint = 0;
273 case RPM_I18NSTRING_TYPE:
274 case RPM_STRING_TYPE:
280 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
282 if ((bs = b64encode(data, ns, 0)) == NULL) {
283 /* XXX proper error handling would be better. */
284 bs = xcalloc(1, padding + (ns / 3) * 4 + 1);
291 anint = *((const uint8_t *) data);
294 anint = *((const uint16_t *) data);
297 anint = *((const uint32_t *) data);
300 case RPM_STRING_ARRAY_TYPE:
302 return xstrdup(_("(invalid xml type)"));
308 t = memset(alloca(tlen+1), 0, tlen+1);
310 xx = snprintf(t, tlen, "%lu", anint);
317 nb += strlen(xtag) + sizeof("\t</>");
319 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
321 nb += 2 * strlen(xtag) + sizeof("\t<></>");
323 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
324 te = xmlstrcpy(te, s);
326 te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
329 /* XXX s was malloc'd */
330 if (!strcmp(xtag, "base64"))
335 strcat(formatPrefix, "s");
336 xx = snprintf(val, nb, formatPrefix, t);
343 * Display signature fingerprint and time.
344 * @param type tag type
345 * @param data tag value
346 * @param formatPrefix (unused)
348 * @param element (unused)
349 * @return formatted string
351 static char * pgpsigFormat(rpmTagType type, rpm_constdata_t data,
352 char * formatPrefix, size_t padding,
357 if (type != RPM_BIN_TYPE) {
358 val = xstrdup(_("(not a blob)"));
360 const uint8_t * pkt = (const uint8_t *) data;
362 unsigned int v = *pkt;
370 plen = pgpLen(pkt+1, &hlen);
372 tag = (v >> 2) & 0xf;
373 plen = (1 << (v & 0x3));
374 hlen = pgpGrab(pkt+1, plen);
377 pktlen = 1 + plen + hlen;
380 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
381 val = xstrdup(_("(not an OpenPGP signature)"));
383 pgpDig dig = pgpNewDig();
384 pgpDigParams sigp = &dig->signature;
386 char *tempstr = NULL;
388 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
393 val = t = xrealloc(val, nb + 1);
395 switch (sigp->pubkey_algo) {
396 case PGPPUBKEYALGO_DSA:
397 t = stpcpy(t, "DSA");
399 case PGPPUBKEYALGO_RSA:
400 t = stpcpy(t, "RSA");
403 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
407 if (t + 5 >= val + nb)
410 switch (sigp->hash_algo) {
411 case PGPHASHALGO_MD5:
412 t = stpcpy(t, "MD5");
414 case PGPHASHALGO_SHA1:
415 t = stpcpy(t, "SHA1");
418 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
422 if (t + strlen (", ") + 1 >= val + nb)
427 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
428 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
429 struct tm * tstruct = localtime(&dateint);
431 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
434 if (t + strlen (", Key ID ") + 1 >= val + nb)
436 t = stpcpy(t, ", Key ID ");
437 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
438 if (t + strlen (tempstr) > val + nb)
440 t = stpcpy(t, tempstr);
443 dig = pgpFreeDig(dig);
451 * Format dependency flags for display.
452 * @param type tag type
453 * @param data tag value
454 * @param formatPrefix
456 * @param element (unused)
457 * @return formatted string
459 static char * depflagsFormat(rpmTagType type, rpm_constdata_t data,
460 char * formatPrefix, size_t padding, int element)
466 if (type != RPM_INT32_TYPE) {
467 val = xstrdup(_("(not a number)"));
469 anint = *((const rpm_flag_t *) data);
472 if (anint & RPMSENSE_LESS)
474 if (anint & RPMSENSE_GREATER)
476 if (anint & RPMSENSE_EQUAL)
479 val = xmalloc(5 + padding);
480 strcat(formatPrefix, "s");
481 sprintf(val, formatPrefix, buf);
488 * Retrieve mounted file system paths.
490 * @retval *type tag type
491 * @retval *data tag value
492 * @retval *count no. of data items
493 * @retval *freeData data-was-malloc'ed indicator
494 * @return 0 on success
496 static int fsnamesTag( Header h, int32_t * type,
497 rpm_data_t * data, rpm_count_t * count,
502 if (rpmGetFilesystemList(&list, count))
505 if (type) *type = RPM_STRING_ARRAY_TYPE;
506 if (data) *((const char ***) data) = list;
507 if (freeData) *freeData = 0;
513 * Retrieve install prefixes.
515 * @retval *type tag type
516 * @retval *data tag value
517 * @retval *count no. of data items
518 * @retval *freeData data-was-malloc'ed indicator
519 * @return 0 on success
521 static int instprefixTag(Header h, rpmTagType* type,
526 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
527 HFD_t hfd = headerFreeData;
531 if (hge(h, RPMTAG_INSTALLPREFIX, type, (rpm_data_t *)data, count)) {
532 if (freeData) *freeData = 0;
534 } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (rpm_data_t *) &array, count)) {
535 if (type) *type = RPM_STRING_TYPE;
536 if (data) *data = xstrdup(array[0]);
537 if (freeData) *freeData = 1;
538 array = hfd(array, ipt);
546 * Retrieve mounted file system space.
548 * @retval *type tag type
549 * @retval *data tag value
550 * @retval *count no. of data items
551 * @retval *freeData data-was-malloc'ed indicator
552 * @return 0 on success
554 static int fssizesTag(Header h, rpmTagType* type,
555 rpm_data_t * data, rpm_count_t * count,
558 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
559 const char ** filenames;
560 rpm_off_t * filesizes;
562 rpm_count_t numFiles;
564 if (!hge(h, RPMTAG_FILESIZES, NULL, (rpm_data_t *) &filesizes, &numFiles)) {
569 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
572 if (rpmGetFilesystemList(NULL, count))
575 *type = RPM_INT32_TYPE;
578 if (filenames == NULL) {
579 usages = xcalloc((*count), sizeof(usages));
585 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
590 filenames = _free(filenames);
596 * Retrieve trigger info.
598 * @retval *type tag type
599 * @retval *data tag value
600 * @retval *count no. of data items
601 * @retval *freeData data-was-malloc'ed indicator
602 * @return 0 on success
604 static int triggercondsTag(Header h, rpmTagType* type,
605 rpm_data_t * data, rpm_count_t * count,
608 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
609 HFD_t hfd = headerFreeData;
610 rpmTagType tnt, tvt, tst;
612 char ** names, ** versions;
613 rpm_count_t numNames, numScripts;
617 char * item, * flagsStr;
622 if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (rpm_data_t *) &names, &numNames)) {
627 xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, NULL);
628 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
629 xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (rpm_data_t *) &versions, NULL);
630 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
634 *data = conds = xmalloc(sizeof(*conds) * numScripts);
636 *type = RPM_STRING_ARRAY_TYPE;
637 for (i = 0; i < numScripts; i++) {
640 for (j = 0; j < numNames; j++) {
644 item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
645 if (flags[j] & RPMSENSE_SENSEMASK) {
646 buf[0] = '%', buf[1] = '\0';
647 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, 0);
648 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
649 flagsStr = _free(flagsStr);
651 strcpy(item, names[j]);
654 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
655 if (*chptr != '\0') strcat(chptr, ", ");
663 names = hfd(names, tnt);
664 versions = hfd(versions, tvt);
670 * Retrieve trigger type info.
672 * @retval *type tag type
673 * @retval *data tag value
674 * @retval *count no. of data items
675 * @retval *freeData data-was-malloc'ed indicator
676 * @return 0 on success
678 static int triggertypeTag(Header h, rpmTagType* type,
679 rpm_data_t * data, rpm_count_t * count,
682 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
683 HFD_t hfd = headerFreeData;
689 rpm_count_t numScripts, numNames;
693 if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (rpm_data_t *) &indices, &numNames)) {
698 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (rpm_data_t *) &flags, NULL);
699 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (rpm_data_t *) &s, &numScripts);
703 *data = conds = xmalloc(sizeof(*conds) * numScripts);
705 *type = RPM_STRING_ARRAY_TYPE;
706 for (i = 0; i < numScripts; i++) {
707 for (j = 0; j < numNames; j++) {
711 if (flags[j] & RPMSENSE_TRIGGERPREIN)
712 conds[i] = xstrdup("prein");
713 else if (flags[j] & RPMSENSE_TRIGGERIN)
714 conds[i] = xstrdup("in");
715 else if (flags[j] & RPMSENSE_TRIGGERUN)
716 conds[i] = xstrdup("un");
717 else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
718 conds[i] = xstrdup("postun");
720 conds[i] = xstrdup("");
729 * Retrieve file paths.
731 * @retval *type tag type
732 * @retval *data tag value
733 * @retval *count no. of data items
734 * @retval *freeData data-was-malloc'ed indicator
735 * @return 0 on success
737 static int filenamesTag(Header h, rpmTagType* type,
738 rpm_data_t * data, rpm_count_t * count,
741 *type = RPM_STRING_ARRAY_TYPE;
742 rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
748 * Retrieve file classes.
750 * @retval *type tag type
751 * @retval *data tag value
752 * @retval *count no. of data items
753 * @retval *freeData data-was-malloc'ed indicator
754 * @return 0 on success
756 static int fileclassTag(Header h, rpmTagType* type,
757 rpm_data_t * data, rpm_count_t * count,
760 *type = RPM_STRING_ARRAY_TYPE;
761 rpmfiBuildFClasses(h, (const char ***) data, count);
767 * Retrieve file provides.
769 * @retval *type tag type
770 * @retval *data tag value
771 * @retval *count no. of data items
772 * @retval *freeData data-was-malloc'ed indicator
773 * @return 0 on success
775 static int fileprovideTag(Header h, rpmTagType* type,
776 rpm_data_t * data, rpm_count_t * count,
779 *type = RPM_STRING_ARRAY_TYPE;
780 rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
786 * Retrieve file requires.
788 * @retval *type tag type
789 * @retval *data tag value
790 * @retval *count no. of data items
791 * @retval *freeData data-was-malloc'ed indicator
792 * @return 0 on success
794 static int filerequireTag(Header h, rpmTagType* type,
795 rpm_data_t * data, rpm_count_t * count,
798 *type = RPM_STRING_ARRAY_TYPE;
799 rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
804 /* I18N look aside diversions */
806 #if defined(ENABLE_NLS)
807 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
809 static const char * const language = "LANGUAGE";
811 static const char * const _macro_i18ndomains = "%{?_i18ndomains}";
814 * Retrieve i18n text.
817 * @retval *type tag type
818 * @retval *data tag value
819 * @retval *count no. of data items
820 * @retval *freeData data-was-malloc'ed indicator
821 * @return 0 on success
823 static int i18nTag(Header h, rpmTag tag, rpmTagType* type,
824 rpm_data_t * data, rpm_count_t * count,
827 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
828 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
831 *type = RPM_STRING_TYPE;
836 if (dstring && *dstring) {
838 const char * langval;
844 xx = headerNVR(h, &n, NULL, NULL);
845 rasprintf(&msgkey, "%s(%s)", n, rpmTagGetName(tag));
847 /* change to en_US for msgkey -> msgid resolution */
848 langval = getenv(language);
849 (void) setenv(language, "en_US", 1);
850 #if defined(ENABLE_NLS)
855 for (domain = dstring; domain != NULL; domain = de) {
856 de = strchr(domain, ':');
857 if (de) *de++ = '\0';
858 msgid = dgettext(domain, msgkey);
859 if (msgid != msgkey) break;
862 /* restore previous environment for msgid -> msgstr resolution */
864 (void) setenv(language, langval, 1);
867 #if defined(ENABLE_NLS)
871 if (domain && msgid) {
872 *data = dgettext(domain, msgid);
873 *data = xstrdup(*data); /* XXX xstrdup has side effects. */
877 dstring = _free(dstring);
883 dstring = _free(dstring);
885 rc = hge(h, tag, type, data, count);
887 if (rc && (*data) != NULL) {
888 *data = xstrdup(*data);
900 * Retrieve summary text.
902 * @retval *type tag type
903 * @retval *data tag value
904 * @retval *count no. of data items
905 * @retval *freeData data-was-malloc'ed indicator
906 * @return 0 on success
908 static int summaryTag(Header h, rpmTagType* type,
909 rpm_data_t * data, rpm_count_t * count,
912 return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
916 * Retrieve description text.
918 * @retval *type tag type
919 * @retval *data tag value
920 * @retval *count no. of data items
921 * @retval *freeData data-was-malloc'ed indicator
922 * @return 0 on success
924 static int descriptionTag(Header h, rpmTagType* type,
925 rpm_data_t * data, rpm_count_t * count,
928 return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
932 * Retrieve group text.
934 * @retval *type tag type
935 * @retval *data tag value
936 * @retval *count no. of data items
937 * @retval *freeData data-was-malloc'ed indicator
938 * @return 0 on success
940 static int groupTag(Header h, rpmTagType* type,
941 rpm_data_t * data, rpm_count_t * count,
944 return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
948 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
949 { HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } },
950 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } },
951 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } },
952 { HEADER_EXT_TAG, "RPMTAG_FILECLASS", { fileclassTag } },
953 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } },
954 { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE", { fileprovideTag } },
955 { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE", { filerequireTag } },
956 { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } },
957 { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } },
958 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } },
959 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } },
960 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } },
961 { HEADER_EXT_FORMAT, "armor", { armorFormat } },
962 { HEADER_EXT_FORMAT, "base64", { base64Format } },
963 { HEADER_EXT_FORMAT, "pgpsig", { pgpsigFormat } },
964 { HEADER_EXT_FORMAT, "depflags", { depflagsFormat } },
965 { HEADER_EXT_FORMAT, "fflags", { fflagsFormat } },
966 { HEADER_EXT_FORMAT, "perms", { permsFormat } },
967 { HEADER_EXT_FORMAT, "permissions", { permsFormat } },
968 { HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } },
969 { HEADER_EXT_FORMAT, "xml", { xmlFormat } },
970 { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } }