9 #include <rpm/rpmtypes.h>
10 #include <rpm/rpmtd.h>
11 #include <rpm/rpmds.h>
12 #include <rpm/rpmfi.h>
13 #include <rpm/rpmstring.h>
15 #include "rpmio/digest.h"
16 #include "lib/manifest.h"
21 * Define header tag output formats.
24 struct headerFormatFunc_s {
25 rpmtdFormats fmt; /*!< Value of extension */
26 const char *name; /*!< Name of extension. */
27 void *func; /*!< Pointer to formatter function. */
30 /* forward declarations */
31 static const struct headerFormatFunc_s rpmHeaderFormats[];
33 void *rpmHeaderFormatFuncByName(const char *fmt);
34 void *rpmHeaderFormatFuncByValue(rpmtdFormats fmt);
37 * barebones string representation with no extra formatting
38 * @param td tag data container
39 * @param formatPrefix sprintf format string
40 * @return formatted string
42 static char * stringFormat(rpmtd td, char *formatPrefix)
44 const char *str = NULL;
45 char *val = NULL, *buf = NULL;
47 switch (rpmtdClass(td)) {
48 case RPM_NUMERIC_CLASS:
49 strcat(formatPrefix, PRIu64);
50 rasprintf(&val, formatPrefix, rpmtdGetNumber(td));
52 case RPM_STRING_CLASS:
53 str = rpmtdGetString(td);
54 strcat(formatPrefix, "s");
55 rasprintf(&val, formatPrefix, str);
57 case RPM_BINARY_CLASS:
58 buf = pgpHexStr(td->data, td->count);
59 strcat(formatPrefix, "s");
60 rasprintf(&val, formatPrefix, buf);
64 val = xstrdup("(unknown type)");
70 static char * numFormat(rpmtd td, char * formatPrefix, char *format)
74 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
75 val = xstrdup(_("(not a number)"));
77 strcat(formatPrefix, format);
78 rasprintf(&val, formatPrefix, rpmtdGetNumber(td));
85 * @param td tag data container
86 * @param formatPrefix sprintf format string
87 * @return formatted string
89 static char * octalFormat(rpmtd td, char * formatPrefix)
91 return numFormat(td, formatPrefix, "o");
96 * @param td tag data container
97 * @param formatPrefix sprintf format string
98 * @return formatted string
100 static char * hexFormat(rpmtd td, char * formatPrefix)
102 return numFormat(td, formatPrefix, "x");
106 * @param td tag data container
107 * @param formatPrefix sprintf format string
108 * @return formatted string
110 static char * realDateFormat(rpmtd td, char * formatPrefix,
111 const char * strftimeFormat)
115 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
116 val = xstrdup(_("(not a number)"));
120 time_t dateint = rpmtdGetNumber(td);
121 tstruct = localtime(&dateint);
123 strcat(formatPrefix, "s");
127 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
128 rasprintf(&val, formatPrefix, buf);
136 * @param td tag data container
137 * @param formatPrefix sprintf format string
138 * @return formatted string
140 static char * dateFormat(rpmtd td, char * formatPrefix)
142 return realDateFormat(td, formatPrefix, _("%c"));
147 * @param td tag data container
148 * @param formatPrefix sprintf format string
149 * @return formatted string
151 static char * dayFormat(rpmtd td, char * formatPrefix)
153 return realDateFormat(td, formatPrefix, _("%a %b %d %Y"));
157 * Return shell escape formatted data.
158 * @param td tag data container
159 * @param formatPrefix sprintf format string
160 * @return formatted string
162 static char * shescapeFormat(rpmtd td, char * formatPrefix)
164 char * result = NULL, * dst, * src;
166 if (rpmtdClass(td) == RPM_NUMERIC_CLASS) {
167 strcat(formatPrefix, PRIu64);
168 rasprintf(&result, formatPrefix, rpmtdGetNumber(td));
171 strcat(formatPrefix, "s");
172 rasprintf(&buf, formatPrefix, rpmtdGetString(td));
174 result = dst = xmalloc(strlen(buf) * 4 + 3);
176 for (src = buf; *src != '\0'; src++) {
196 * Identify type of trigger.
197 * @param td tag data container
198 * @param formatPrefix sprintf format string
199 * @return formatted string
201 static char * triggertypeFormat(rpmtd td, char * formatPrefix)
205 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
206 val = xstrdup(_("(not a number)"));
208 uint64_t item = rpmtdGetNumber(td);
209 if (item & RPMSENSE_TRIGGERPREIN)
210 val = xstrdup("prein");
211 else if (item & RPMSENSE_TRIGGERIN)
213 else if (item & RPMSENSE_TRIGGERUN)
215 else if (item & RPMSENSE_TRIGGERPOSTUN)
216 val = xstrdup("postun");
224 * Identify type of dependency.
225 * @param td tag data container
226 * @param formatPrefix sprintf format string
227 * @return formatted string
229 static char * deptypeFormat(rpmtd td, char * formatPrefix)
232 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
233 val = xstrdup(_("(not a number)"));
236 uint64_t item = rpmtdGetNumber(td);
238 if (item & RPMSENSE_SCRIPT_PRE)
239 argvAdd(&sdeps, "pre");
240 if (item & RPMSENSE_SCRIPT_POST)
241 argvAdd(&sdeps, "post");
242 if (item & RPMSENSE_SCRIPT_PREUN)
243 argvAdd(&sdeps, "preun");
244 if (item & RPMSENSE_SCRIPT_POSTUN)
245 argvAdd(&sdeps, "postun");
246 if (item & RPMSENSE_SCRIPT_VERIFY)
247 argvAdd(&sdeps, "verify");
250 val = argvJoin(sdeps, ",");
253 if (item & RPMSENSE_RPMLIB)
254 val = xstrdup("rpmlib");
255 else if (item & RPMSENSE_INTERP)
256 val = xstrdup("interp");
257 else if ((item & RPMSENSE_FIND_REQUIRES) ||
258 (item & RPMSENSE_FIND_PROVIDES))
259 val = xstrdup("auto");
260 else if (item & RPMSENSE_PREREQ)
261 val = xstrdup("prereq");
263 val = xstrdup("manual");
270 * Format file permissions for display.
271 * @param td tag data container
272 * @param formatPrefix sprintf format string
273 * @return formatted string
275 static char * permsFormat(rpmtd td, char * formatPrefix)
280 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
281 val = xstrdup(_("(not a number)"));
283 strcat(formatPrefix, "s");
284 buf = rpmPermsString(rpmtdGetNumber(td));
285 rasprintf(&val, formatPrefix, buf);
293 * Format file flags for display.
294 * @param td tag data container
295 * @param formatPrefix sprintf format string
296 * @return formatted string
298 static char * fflagsFormat(rpmtd td, char * formatPrefix)
303 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
304 val = xstrdup(_("(not a number)"));
306 uint64_t anint = rpmtdGetNumber(td);
308 if (anint & RPMFILE_DOC)
310 if (anint & RPMFILE_CONFIG)
312 if (anint & RPMFILE_SPECFILE)
314 if (anint & RPMFILE_MISSINGOK)
316 if (anint & RPMFILE_NOREPLACE)
318 if (anint & RPMFILE_GHOST)
320 if (anint & RPMFILE_LICENSE)
322 if (anint & RPMFILE_README)
325 strcat(formatPrefix, "s");
326 rasprintf(&val, formatPrefix, buf);
333 * Wrap a pubkey in ascii armor for display.
334 * @todo Permit selectable display formats (i.e. binary).
335 * @param td tag data container
336 * @param formatPrefix sprintf format string
337 * @return formatted string
339 static char * armorFormat(rpmtd td, char * formatPrefix)
342 const unsigned char * s;
343 unsigned char * bs = NULL;
348 switch (rpmtdType(td)) {
351 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
353 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
355 case RPM_STRING_TYPE:
356 case RPM_STRING_ARRAY_TYPE:
357 enc = rpmtdGetString(td);
358 if (b64decode(enc, (void **)&bs, &ns))
359 return xstrdup(_("(not base64)"));
361 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
369 case RPM_I18NSTRING_TYPE:
371 return xstrdup(_("(invalid type)"));
375 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
376 val = pgpArmorWrap(atype, s, ns);
377 if (atype == PGPARMOR_PUBKEY) {
384 * Encode binary data in base64 for display.
385 * @todo Permit selectable display formats (i.e. binary).
386 * @param td tag data container
387 * @param formatPrefix sprintf format string
388 * @return formatted string
390 static char * base64Format(rpmtd td, char * formatPrefix)
394 if (rpmtdType(td) != RPM_BIN_TYPE) {
395 val = xstrdup(_("(not a blob)"));
398 if ((enc = b64encode(td->data, td->count, -1)) != NULL) {
399 strcat(formatPrefix, "s");
400 rasprintf(&val, formatPrefix, enc ? enc : "");
409 * Wrap tag data in simple header xml markup.
410 * @param td tag data container
411 * @param formatPrefix sprintf format string
412 * @return formatted string
414 static char * xmlFormat(rpmtd td, char * formatPrefix)
416 const char *xtag = NULL;
419 rpmtdFormats fmt = RPMTD_FORMAT_STRING;
421 switch (rpmtdClass(td)) {
422 case RPM_STRING_CLASS:
425 case RPM_BINARY_CLASS:
426 fmt = RPMTD_FORMAT_BASE64;
429 case RPM_NUMERIC_CLASS:
434 return xstrdup(_("(invalid xml type)"));
438 /* XXX TODO: handle errors */
439 s = rpmtdFormat(td, fmt, NULL);
442 val = rstrscat(NULL, "\t<", xtag, "/>", NULL);
445 size_t i, s_size = strlen(s);
447 for (i=0; i<s_size; i++) {
449 case '<': rstrcat(&new_s, "<"); break;
450 case '>': rstrcat(&new_s, ">"); break;
451 case '&': rstrcat(&new_s, "&"); break;
461 val = rstrscat(NULL, "\t<", xtag, ">", new_s, "</", xtag, ">", NULL);
466 strcat(formatPrefix, "s");
471 * Display signature fingerprint and time.
472 * @param td tag data container
473 * @param formatPrefix sprintf format string
474 * @return formatted string
476 static char * pgpsigFormat(rpmtd td, char * formatPrefix)
480 if (rpmtdType(td) != RPM_BIN_TYPE) {
481 val = xstrdup(_("(not a blob)"));
483 const uint8_t * pkt = td->data;
485 unsigned int v = *pkt;
493 plen = pgpLen(pkt+1, &hlen);
495 tag = (v >> 2) & 0xf;
496 plen = (1 << (v & 0x3));
497 hlen = pgpGrab(pkt+1, plen);
500 pktlen = 1 + plen + hlen;
503 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
504 val = xstrdup(_("(not an OpenPGP signature)"));
506 pgpDig dig = pgpNewDig();
507 pgpDigParams sigp = &dig->signature;
509 char *tempstr = NULL;
511 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
516 val = t = xrealloc(val, nb + 1);
518 switch (sigp->pubkey_algo) {
519 case PGPPUBKEYALGO_DSA:
520 t = stpcpy(t, "DSA");
522 case PGPPUBKEYALGO_RSA:
523 t = stpcpy(t, "RSA");
526 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
530 if (t + 5 >= val + nb)
533 switch (sigp->hash_algo) {
534 case PGPHASHALGO_MD5:
535 t = stpcpy(t, "MD5");
537 case PGPHASHALGO_SHA1:
538 t = stpcpy(t, "SHA1");
541 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
545 if (t + strlen (", ") + 1 >= val + nb)
550 /* this is important if sizeof(int32_t) ! sizeof(time_t) */
551 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
552 struct tm * tstruct = localtime(&dateint);
554 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
557 if (t + strlen (", Key ID ") + 1 >= val + nb)
559 t = stpcpy(t, ", Key ID ");
560 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
561 if (t + strlen (tempstr) > val + nb)
563 t = stpcpy(t, tempstr);
566 dig = pgpFreeDig(dig);
574 * Format dependency flags for display.
575 * @param td tag data container
576 * @param formatPrefix sprintf format string
577 * @return formatted string
579 static char * depflagsFormat(rpmtd td, char * formatPrefix)
583 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
584 val = xstrdup(_("(not a number)"));
586 uint64_t anint = rpmtdGetNumber(td);
590 if (anint & RPMSENSE_LESS)
592 if (anint & RPMSENSE_GREATER)
594 if (anint & RPMSENSE_EQUAL)
597 strcat(formatPrefix, "s");
598 rasprintf(&val, formatPrefix, buf);
605 * Return tag container array size.
606 * @param td tag data container
607 * @param formatPrefix sprintf format string
608 * @return formatted string
610 static char * arraysizeFormat(rpmtd td, char * formatPrefix)
613 strcat(formatPrefix, "u");
614 rasprintf(&val, formatPrefix, rpmtdCount(td));
618 void *rpmHeaderFormatFuncByName(const char *fmt)
620 const struct headerFormatFunc_s * ext;
623 for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
624 if (rstreq(ext->name, fmt)) {
632 void *rpmHeaderFormatFuncByValue(rpmtdFormats fmt)
634 const struct headerFormatFunc_s * ext;
637 for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
638 if (fmt == ext->fmt) {
646 static const struct headerFormatFunc_s rpmHeaderFormats[] = {
647 { RPMTD_FORMAT_STRING, "string", stringFormat },
648 { RPMTD_FORMAT_ARMOR, "armor", armorFormat },
649 { RPMTD_FORMAT_BASE64, "base64", base64Format },
650 { RPMTD_FORMAT_PGPSIG, "pgpsig", pgpsigFormat },
651 { RPMTD_FORMAT_DEPFLAGS, "depflags", depflagsFormat },
652 { RPMTD_FORMAT_DEPTYPE, "deptype", deptypeFormat },
653 { RPMTD_FORMAT_FFLAGS, "fflags", fflagsFormat },
654 { RPMTD_FORMAT_PERMS, "perms", permsFormat },
655 { RPMTD_FORMAT_PERMS, "permissions", permsFormat },
656 { RPMTD_FORMAT_TRIGGERTYPE, "triggertype", triggertypeFormat },
657 { RPMTD_FORMAT_XML, "xml", xmlFormat },
658 { RPMTD_FORMAT_OCTAL, "octal", octalFormat },
659 { RPMTD_FORMAT_HEX, "hex", hexFormat },
660 { RPMTD_FORMAT_DATE, "date", dateFormat },
661 { RPMTD_FORMAT_DAY, "day", dayFormat },
662 { RPMTD_FORMAT_SHESCAPE, "shescape", shescapeFormat },
663 { RPMTD_FORMAT_ARRAYSIZE, "arraysize", arraysizeFormat },