6 #include "rpmio/digest.h"
8 #include <rpmmacro.h> /* XXX for %_i18ndomains */
12 #include "lib/legacy.h" /* XXX rpmfiBuildFNames() */
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(int32_t type, const void * data,
28 char * formatPrefix, int 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(int32_t type, const void * data,
59 char * formatPrefix, int 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(*((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(int32_t type, const void * data,
87 char * formatPrefix, int padding, int element)
91 int anint = *((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(int32_t type, const void * data,
133 char * formatPrefix, int padding,
137 const unsigned char * s;
144 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
146 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
148 case RPM_STRING_TYPE:
149 case RPM_STRING_ARRAY_TYPE:
151 if (b64decode(enc, (void **)&s, &ns))
152 return xstrdup(_("(not base64)"));
153 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
160 case RPM_I18NSTRING_TYPE:
162 return xstrdup(_("(invalid type)"));
166 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
167 return pgpArmorWrap(atype, s, ns);
171 * Encode binary data in base64 for display.
172 * @todo Permit selectable display formats (i.e. binary).
173 * @param type tag type
174 * @param data tag value
175 * @param formatPrefix (unused)
178 * @return formatted string
180 static char * base64Format(int32_t type, const void * data,
181 char * formatPrefix, int padding, int element)
185 if (type != RPM_BIN_TYPE) {
186 val = xstrdup(_("(not a blob)"));
190 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
194 if ((enc = b64encode(data, ns, -1)) != NULL) {
198 val = t = xmalloc(nt + padding + 1);
212 static size_t xmlstrlen(const char * s)
217 while ((c = *s++) != '\0')
220 case '<': case '>': len += 4; break;
221 case '&': len += 5; break;
222 default: len += 1; break;
230 static char * xmlstrcpy(char * t, const char * s)
235 while ((c = *s++) != '\0') {
237 case '<': te = stpcpy(te, "<"); break;
238 case '>': te = stpcpy(te, ">"); break;
239 case '&': te = stpcpy(te, "&"); break;
240 default: *te++ = c; break;
248 * Wrap tag data in simple header xml markup.
249 * @param type tag type
250 * @param data tag value
251 * @param formatPrefix
253 * @param element (unused)
254 * @return formatted string
256 static char * xmlFormat(int32_t type, const void * data,
257 char * formatPrefix, int padding,
260 const char * xtag = NULL;
263 const char * s = NULL;
265 unsigned long anint = 0;
269 case RPM_I18NSTRING_TYPE:
270 case RPM_STRING_TYPE:
276 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
278 if ((s = b64encode(data, ns, 0)) == NULL) {
279 /* XXX proper error handling would be better. */
280 s = xcalloc(1, padding + (ns / 3) * 4 + 1);
286 anint = *((uint8_t *) data);
289 anint = *((uint16_t *) data);
292 anint = *((uint32_t *) data);
295 case RPM_STRING_ARRAY_TYPE:
297 return xstrdup(_("(invalid xml type)"));
303 t = memset(alloca(tlen+1), 0, tlen+1);
305 xx = snprintf(t, tlen, "%lu", anint);
312 nb += strlen(xtag) + sizeof("\t</>");
314 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
316 nb += 2 * strlen(xtag) + sizeof("\t<></>");
318 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
319 te = xmlstrcpy(te, s);
321 te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
324 /* XXX s was malloc'd */
325 if (!strcmp(xtag, "base64"))
330 strcat(formatPrefix, "s");
331 xx = snprintf(val, nb, formatPrefix, t);
338 * Display signature fingerprint and time.
339 * @param type tag type
340 * @param data tag value
341 * @param formatPrefix (unused)
343 * @param element (unused)
344 * @return formatted string
346 static char * pgpsigFormat(int32_t type, const void * data,
347 char * formatPrefix, int padding,
352 if (type != RPM_BIN_TYPE) {
353 val = xstrdup(_("(not a blob)"));
355 uint8_t * pkt = (uint8_t *) data;
356 unsigned int pktlen = 0;
357 unsigned int v = *pkt;
360 unsigned int hlen = 0;
365 plen = pgpLen(pkt+1, &hlen);
367 tag = (v >> 2) & 0xf;
368 plen = (1 << (v & 0x3));
369 hlen = pgpGrab(pkt+1, plen);
372 pktlen = 1 + plen + hlen;
375 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
376 val = xstrdup(_("(not an OpenPGP signature)"));
378 pgpDig dig = pgpNewDig();
379 pgpDigParams sigp = &dig->signature;
383 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
388 val = t = xrealloc(val, nb + 1);
390 switch (sigp->pubkey_algo) {
391 case PGPPUBKEYALGO_DSA:
392 t = stpcpy(t, "DSA");
394 case PGPPUBKEYALGO_RSA:
395 t = stpcpy(t, "RSA");
398 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
402 if (t + 5 >= val + nb)
405 switch (sigp->hash_algo) {
406 case PGPHASHALGO_MD5:
407 t = stpcpy(t, "MD5");
409 case PGPHASHALGO_SHA1:
410 t = stpcpy(t, "SHA1");
413 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
417 if (t + strlen (", ") + 1 >= val + nb)
422 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
423 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
424 struct tm * tstruct = localtime(&dateint);
426 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
429 if (t + strlen (", Key ID ") + 1 >= val + nb)
431 t = stpcpy(t, ", Key ID ");
432 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
433 if (t + strlen (tempstr) > val + nb)
435 t = stpcpy(t, tempstr);
437 dig = pgpFreeDig(dig);
445 * Format dependency flags for display.
446 * @param type tag type
447 * @param data tag value
448 * @param formatPrefix
450 * @param element (unused)
451 * @return formatted string
453 static char * depflagsFormat(int32_t type, const void * data,
454 char * formatPrefix, int padding, int element)
460 if (type != RPM_INT32_TYPE) {
461 val = xstrdup(_("(not a number)"));
463 anint = *((int32_t *) data);
466 if (anint & RPMSENSE_LESS)
468 if (anint & RPMSENSE_GREATER)
470 if (anint & RPMSENSE_EQUAL)
473 val = xmalloc(5 + padding);
474 strcat(formatPrefix, "s");
475 sprintf(val, formatPrefix, buf);
482 * Retrieve mounted file system paths.
484 * @retval *type tag type
485 * @retval *data tag value
486 * @retval *count no. of data items
487 * @retval *freeData data-was-malloc'ed indicator
488 * @return 0 on success
490 static int fsnamesTag( Header h, int32_t * type,
491 void ** data, int32_t * count,
496 if (rpmGetFilesystemList(&list, count))
499 if (type) *type = RPM_STRING_ARRAY_TYPE;
500 if (data) *((const char ***) data) = list;
501 if (freeData) *freeData = 0;
507 * Retrieve install prefixes.
509 * @retval *type tag type
510 * @retval *data tag value
511 * @retval *count no. of data items
512 * @retval *freeData data-was-malloc'ed indicator
513 * @return 0 on success
515 static int instprefixTag(Header h, rpmTagType * type,
520 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
521 HFD_t hfd = headerFreeData;
525 if (hge(h, RPMTAG_INSTALLPREFIX, type, (void **)data, count)) {
526 if (freeData) *freeData = 0;
528 } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &array, count)) {
529 if (type) *type = RPM_STRING_TYPE;
530 if (data) *data = xstrdup(array[0]);
531 if (freeData) *freeData = 1;
532 array = hfd(array, ipt);
540 * Retrieve mounted file system space.
542 * @retval *type tag type
543 * @retval *data tag value
544 * @retval *count no. of data items
545 * @retval *freeData data-was-malloc'ed indicator
546 * @return 0 on success
548 static int fssizesTag(Header h, rpmTagType * type,
549 const void ** data, int32_t * count,
552 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
553 const char ** filenames;
558 if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &filesizes, &numFiles)) {
563 rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
566 if (rpmGetFilesystemList(NULL, count))
569 *type = RPM_INT32_TYPE;
572 if (filenames == NULL) {
573 usages = xcalloc((*count), sizeof(usages));
579 if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))
584 filenames = _free(filenames);
590 * Retrieve trigger info.
592 * @retval *type tag type
593 * @retval *data tag value
594 * @retval *count no. of data items
595 * @retval *freeData data-was-malloc'ed indicator
596 * @return 0 on success
598 static int triggercondsTag(Header h, rpmTagType * type,
599 const void ** data, int32_t * count,
602 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
603 HFD_t hfd = headerFreeData;
604 rpmTagType tnt, tvt, tst;
605 int32_t * indices, * flags;
606 char ** names, ** versions;
607 int numNames, numScripts;
609 char * item, * flagsStr;
614 if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (void **) &names, &numNames)) {
619 xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, NULL);
620 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
621 xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (void **) &versions, NULL);
622 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
626 *data = conds = xmalloc(sizeof(*conds) * numScripts);
628 *type = RPM_STRING_ARRAY_TYPE;
629 for (i = 0; i < numScripts; i++) {
632 for (j = 0; j < numNames; j++) {
636 item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
637 if (flags[j] & RPMSENSE_SENSEMASK) {
638 buf[0] = '%', buf[1] = '\0';
639 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, j);
640 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
641 flagsStr = _free(flagsStr);
643 strcpy(item, names[j]);
646 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
647 if (*chptr != '\0') strcat(chptr, ", ");
655 names = hfd(names, tnt);
656 versions = hfd(versions, tvt);
662 * Retrieve trigger type info.
664 * @retval *type tag type
665 * @retval *data tag value
666 * @retval *count no. of data items
667 * @retval *freeData data-was-malloc'ed indicator
668 * @return 0 on success
670 static int triggertypeTag(Header h, rpmTagType * type,
671 const void ** data, int32_t * count,
674 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
675 HFD_t hfd = headerFreeData;
677 int32_t * indices, * flags;
681 int numScripts, numNames;
683 if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, &numNames)) {
688 xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
689 xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
693 *data = conds = xmalloc(sizeof(*conds) * numScripts);
695 *type = RPM_STRING_ARRAY_TYPE;
696 for (i = 0; i < numScripts; i++) {
697 for (j = 0; j < numNames; j++) {
701 if (flags[j] & RPMSENSE_TRIGGERPREIN)
702 conds[i] = xstrdup("prein");
703 else if (flags[j] & RPMSENSE_TRIGGERIN)
704 conds[i] = xstrdup("in");
705 else if (flags[j] & RPMSENSE_TRIGGERUN)
706 conds[i] = xstrdup("un");
707 else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
708 conds[i] = xstrdup("postun");
710 conds[i] = xstrdup("");
719 * Retrieve file paths.
721 * @retval *type tag type
722 * @retval *data tag value
723 * @retval *count no. of data items
724 * @retval *freeData data-was-malloc'ed indicator
725 * @return 0 on success
727 static int filenamesTag(Header h, rpmTagType * type,
728 const void ** data, int32_t * count,
731 *type = RPM_STRING_ARRAY_TYPE;
732 rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
738 * Retrieve file classes.
740 * @retval *type tag type
741 * @retval *data tag value
742 * @retval *count no. of data items
743 * @retval *freeData data-was-malloc'ed indicator
744 * @return 0 on success
746 static int fileclassTag(Header h, rpmTagType * type,
747 const void ** data, int32_t * count,
750 *type = RPM_STRING_ARRAY_TYPE;
751 rpmfiBuildFClasses(h, (const char ***) data, count);
757 * Retrieve file provides.
759 * @retval *type tag type
760 * @retval *data tag value
761 * @retval *count no. of data items
762 * @retval *freeData data-was-malloc'ed indicator
763 * @return 0 on success
765 static int fileprovideTag(Header h, rpmTagType * type,
766 const void ** data, int32_t * count,
769 *type = RPM_STRING_ARRAY_TYPE;
770 rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
776 * Retrieve file requires.
778 * @retval *type tag type
779 * @retval *data tag value
780 * @retval *count no. of data items
781 * @retval *freeData data-was-malloc'ed indicator
782 * @return 0 on success
784 static int filerequireTag(Header h, rpmTagType * type,
785 const void ** data, int32_t * count,
788 *type = RPM_STRING_ARRAY_TYPE;
789 rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
794 /* I18N look aside diversions */
796 #if defined(ENABLE_NLS)
797 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
799 static const char * language = "LANGUAGE";
801 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
804 * Retrieve i18n text.
807 * @retval *type tag type
808 * @retval *data tag value
809 * @retval *count no. of data items
810 * @retval *freeData data-was-malloc'ed indicator
811 * @return 0 on success
813 static int i18nTag(Header h, int32_t tag, rpmTagType * type,
814 const void ** data, int32_t * count,
817 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
818 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
821 *type = RPM_STRING_TYPE;
826 if (dstring && *dstring) {
828 const char * langval;
832 { const char * tn = rpmTagGetName(tag);
835 size_t nb = sizeof("()");
837 xx = headerNVR(h, &n, NULL, NULL);
838 if (tn) nb += strlen(tn);
839 if (n) nb += strlen(n);
841 sprintf(mk, "%s(%s)", n, tn);
845 /* change to en_US for msgkey -> msgid resolution */
846 langval = getenv(language);
847 (void) setenv(language, "en_US", 1);
848 #if defined(ENABLE_NLS)
853 for (domain = dstring; domain != NULL; domain = de) {
854 de = strchr(domain, ':');
855 if (de) *de++ = '\0';
856 msgid = dgettext(domain, msgkey);
857 if (msgid != msgkey) break;
860 /* restore previous environment for msgid -> msgstr resolution */
862 (void) setenv(language, langval, 1);
865 #if defined(ENABLE_NLS)
869 if (domain && msgid) {
870 *data = dgettext(domain, msgid);
871 *data = xstrdup(*data); /* XXX xstrdup has side effects. */
875 dstring = _free(dstring);
880 dstring = _free(dstring);
882 rc = hge(h, tag, type, (void **)data, count);
884 if (rc && (*data) != NULL) {
885 *data = xstrdup(*data);
897 * Retrieve summary text.
899 * @retval *type tag type
900 * @retval *data tag value
901 * @retval *count no. of data items
902 * @retval *freeData data-was-malloc'ed indicator
903 * @return 0 on success
905 static int summaryTag(Header h, rpmTagType * type,
906 const void ** data, int32_t * count,
909 return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
913 * Retrieve description text.
915 * @retval *type tag type
916 * @retval *data tag value
917 * @retval *count no. of data items
918 * @retval *freeData data-was-malloc'ed indicator
919 * @return 0 on success
921 static int descriptionTag(Header h, rpmTagType * type,
922 const void ** data, int32_t * count,
925 return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
929 * Retrieve group text.
931 * @retval *type tag type
932 * @retval *data tag value
933 * @retval *count no. of data items
934 * @retval *freeData data-was-malloc'ed indicator
935 * @return 0 on success
937 static int groupTag(Header h, rpmTagType * type,
938 const void ** data, int32_t * count,
941 return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
945 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
946 { HEADER_EXT_TAG, "RPMTAG_GROUP", { groupTag } },
947 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION", { descriptionTag } },
948 { HEADER_EXT_TAG, "RPMTAG_SUMMARY", { summaryTag } },
949 { HEADER_EXT_TAG, "RPMTAG_FILECLASS", { fileclassTag } },
950 { HEADER_EXT_TAG, "RPMTAG_FILENAMES", { filenamesTag } },
951 { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE", { fileprovideTag } },
952 { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE", { filerequireTag } },
953 { HEADER_EXT_TAG, "RPMTAG_FSNAMES", { fsnamesTag } },
954 { HEADER_EXT_TAG, "RPMTAG_FSSIZES", { fssizesTag } },
955 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX", { instprefixTag } },
956 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS", { triggercondsTag } },
957 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE", { triggertypeTag } },
958 { HEADER_EXT_FORMAT, "armor", { armorFormat } },
959 { HEADER_EXT_FORMAT, "base64", { base64Format } },
960 { HEADER_EXT_FORMAT, "pgpsig", { pgpsigFormat } },
961 { HEADER_EXT_FORMAT, "depflags", { depflagsFormat } },
962 { HEADER_EXT_FORMAT, "fflags", { fflagsFormat } },
963 { HEADER_EXT_FORMAT, "perms", { permsFormat } },
964 { HEADER_EXT_FORMAT, "permissions", { permsFormat } },
965 { HEADER_EXT_FORMAT, "triggertype", { triggertypeFormat } },
966 { HEADER_EXT_FORMAT, "xml", { xmlFormat } },
967 { HEADER_EXT_MORE, NULL, { (void *) headerDefaultFormats } }