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>
14 #include <rpm/rpmmacro.h>
15 #include <rpm/rpmbase64.h>
17 #include "rpmio/digest.h"
18 #include "lib/manifest.h"
20 #include "lib/signature.h"
25 * Define header tag output formats.
28 struct headerFormatFunc_s {
29 rpmtdFormats fmt; /*!< Value of extension */
30 const char *name; /*!< Name of extension. */
31 headerTagFormatFunction func; /*!< Pointer to formatter function. */
35 * barebones string representation with no extra formatting
36 * @param td tag data container
37 * @return formatted string
39 static char * stringFormat(rpmtd td)
43 switch (rpmtdClass(td)) {
44 case RPM_NUMERIC_CLASS:
45 rasprintf(&val, "%" PRIu64, rpmtdGetNumber(td));
47 case RPM_STRING_CLASS:
48 val = xstrdup(rpmtdGetString(td));
50 case RPM_BINARY_CLASS:
51 val = pgpHexStr(td->data, td->count);
54 val = xstrdup("(unknown type)");
60 static char * numFormat(rpmtd td, const char *format)
64 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
65 val = xstrdup(_("(not a number)"));
67 rasprintf(&val, format, rpmtdGetNumber(td));
74 * @param td tag data container
75 * @return formatted string
77 static char * octalFormat(rpmtd td)
79 return numFormat(td, "%o");
84 * @param td tag data container
85 * @return formatted string
87 static char * hexFormat(rpmtd td)
89 return numFormat(td, "%x");
93 * @param td tag data container
94 * @return formatted string
96 static char * realDateFormat(rpmtd td, const char * strftimeFormat)
100 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
101 val = xstrdup(_("(not a number)"));
105 time_t dateint = rpmtdGetNumber(td);
106 tstruct = localtime(&dateint);
108 /* XXX TODO: deal with non-fitting date string correctly */
111 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
120 * @param td tag data container
121 * @return formatted string
123 static char * dateFormat(rpmtd td)
125 return realDateFormat(td, _("%c"));
130 * @param td tag data container
131 * @return formatted string
133 static char * dayFormat(rpmtd td)
135 return realDateFormat(td, _("%a %b %d %Y"));
139 * Return shell escape formatted data.
140 * @param td tag data container
141 * @return formatted string
143 static char * shescapeFormat(rpmtd td)
145 char * result = NULL, * dst, * src;
147 if (rpmtdClass(td) == RPM_NUMERIC_CLASS) {
148 rasprintf(&result, "%" PRIu64, rpmtdGetNumber(td));
150 char *buf = xstrdup(rpmtdGetString(td));;
152 result = dst = xmalloc(strlen(buf) * 4 + 3);
154 for (src = buf; *src != '\0'; src++) {
174 * Identify type of trigger.
175 * @param td tag data container
176 * @return formatted string
178 static char * triggertypeFormat(rpmtd td)
182 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
183 val = xstrdup(_("(not a number)"));
185 uint64_t item = rpmtdGetNumber(td);
186 if (item & RPMSENSE_TRIGGERPREIN)
187 val = xstrdup("prein");
188 else if (item & RPMSENSE_TRIGGERIN)
190 else if (item & RPMSENSE_TRIGGERUN)
192 else if (item & RPMSENSE_TRIGGERPOSTUN)
193 val = xstrdup("postun");
201 * Identify type of dependency.
202 * @param td tag data container
203 * @return formatted string
205 static char * deptypeFormat(rpmtd td)
208 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
209 val = xstrdup(_("(not a number)"));
212 uint64_t item = rpmtdGetNumber(td);
214 if (item & RPMSENSE_SCRIPT_PRE)
215 argvAdd(&sdeps, "pre");
216 if (item & RPMSENSE_SCRIPT_POST)
217 argvAdd(&sdeps, "post");
218 if (item & RPMSENSE_SCRIPT_PREUN)
219 argvAdd(&sdeps, "preun");
220 if (item & RPMSENSE_SCRIPT_POSTUN)
221 argvAdd(&sdeps, "postun");
222 if (item & RPMSENSE_SCRIPT_VERIFY)
223 argvAdd(&sdeps, "verify");
224 if (item & RPMSENSE_INTERP)
225 argvAdd(&sdeps, "interp");
226 if (item & RPMSENSE_RPMLIB)
227 argvAdd(&sdeps, "rpmlib");
228 if ((item & RPMSENSE_FIND_REQUIRES) || (item & RPMSENSE_FIND_PROVIDES))
229 argvAdd(&sdeps, "auto");
230 if (item & RPMSENSE_PREREQ)
231 argvAdd(&sdeps, "prereq");
232 if (item & RPMSENSE_PRETRANS)
233 argvAdd(&sdeps, "pretrans");
234 if (item & RPMSENSE_POSTTRANS)
235 argvAdd(&sdeps, "posttrans");
236 if (item & RPMSENSE_CONFIG)
237 argvAdd(&sdeps, "config");
238 if (item & RPMSENSE_MISSINGOK)
239 argvAdd(&sdeps, "missingok");
242 val = argvJoin(sdeps, ",");
244 val = xstrdup("manual");
253 * Format file permissions for display.
254 * @param td tag data container
255 * @return formatted string
257 static char * permsFormat(rpmtd td)
261 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
262 val = xstrdup(_("(not a number)"));
264 val = rpmPermsString(rpmtdGetNumber(td));
271 * Format file flags for display.
272 * @param td tag data container
273 * @return formatted string
275 static char * fflagsFormat(rpmtd td)
279 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
280 val = xstrdup(_("(not a number)"));
282 val = rpmFFlagsString(rpmtdGetNumber(td), "");
289 * Wrap a pubkey in ascii armor for display.
290 * @todo Permit selectable display formats (i.e. binary).
291 * @param td tag data container
292 * @return formatted string
294 static char * armorFormat(rpmtd td)
297 const unsigned char * s;
298 unsigned char * bs = NULL;
303 switch (rpmtdType(td)) {
306 /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
308 atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
310 case RPM_STRING_TYPE:
311 case RPM_STRING_ARRAY_TYPE:
312 enc = rpmtdGetString(td);
313 if (rpmBase64Decode(enc, (void **)&bs, &ns))
314 return xstrdup(_("(not base64)"));
316 atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
324 case RPM_I18NSTRING_TYPE:
326 return xstrdup(_("(invalid type)"));
330 /* XXX this doesn't use padding directly, assumes enough slop in retval. */
331 val = pgpArmorWrap(atype, s, ns);
332 if (atype == PGPARMOR_PUBKEY) {
339 * Encode binary data in base64 for display.
340 * @todo Permit selectable display formats (i.e. binary).
341 * @param td tag data container
342 * @return formatted string
344 static char * base64Format(rpmtd td)
348 if (rpmtdType(td) != RPM_BIN_TYPE) {
349 val = xstrdup(_("(not a blob)"));
351 val = rpmBase64Encode(td->data, td->count, -1);
360 * Wrap tag data in simple header xml markup.
361 * @param td tag data container
362 * @return formatted string
364 static char * xmlFormat(rpmtd td)
366 const char *xtag = NULL;
369 rpmtdFormats fmt = RPMTD_FORMAT_STRING;
371 switch (rpmtdClass(td)) {
372 case RPM_STRING_CLASS:
375 case RPM_BINARY_CLASS:
376 fmt = RPMTD_FORMAT_BASE64;
379 case RPM_NUMERIC_CLASS:
384 return xstrdup(_("(invalid xml type)"));
388 /* XXX TODO: handle errors */
389 s = rpmtdFormat(td, fmt, NULL);
392 val = rstrscat(NULL, "\t<", xtag, "/>", NULL);
395 size_t i, s_size = strlen(s);
397 for (i=0; i<s_size; i++) {
399 case '<': rstrcat(&new_s, "<"); break;
400 case '>': rstrcat(&new_s, ">"); break;
401 case '&': rstrcat(&new_s, "&"); break;
411 val = rstrscat(NULL, "\t<", xtag, ">", new_s, "</", xtag, ">", NULL);
420 * Display signature fingerprint and time.
421 * @param td tag data container
422 * @return formatted string
424 static char * pgpsigFormat(rpmtd td)
428 if (rpmtdType(td) != RPM_BIN_TYPE) {
429 val = xstrdup(_("(not a blob)"));
431 pgpDigParams sigp = NULL;
433 if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) {
434 val = xstrdup(_("(not an OpenPGP signature)"));
437 char *keyid = pgpHexStr(sigp->signid, sizeof(sigp->signid));
438 unsigned int dateint = pgpGrab(sigp->time, sizeof(sigp->time));
439 time_t date = dateint;
440 struct tm * tms = localtime(&date);
441 unsigned int key_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
442 unsigned int hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
444 if (!(tms && strftime(dbuf, sizeof(dbuf), "%c", tms) > 0)) {
445 snprintf(dbuf, sizeof(dbuf),
446 _("Invalid date %u"), dateint);
447 dbuf[sizeof(dbuf)-1] = '\0';
450 rasprintf(&val, "%s/%s, %s, Key ID %s",
451 pgpValString(PGPVAL_PUBKEYALGO, key_algo),
452 pgpValString(PGPVAL_HASHALGO, hash_algo),
456 pgpDigParamsFree(sigp);
464 * Format dependency flags for display.
465 * @param td tag data container
466 * @return formatted string
468 static char * depflagsFormat(rpmtd td)
472 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
473 val = xstrdup(_("(not a number)"));
475 uint64_t anint = rpmtdGetNumber(td);
478 if (anint & RPMSENSE_LESS)
480 if (anint & RPMSENSE_GREATER)
482 if (anint & RPMSENSE_EQUAL)
489 static char * depflag_strongFormat(rpmtd td)
493 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
494 val = xstrdup(_("(not a number)"));
496 uint64_t anint = rpmtdGetNumber(td);
497 val = xstrdup(anint & RPMSENSE_STRONG ? "strong" : "");
503 * Return tag container array size.
504 * @param td tag data container
505 * @return formatted string
507 static char * arraysizeFormat(rpmtd td)
510 rasprintf(&val, "%u", rpmtdCount(td));
514 static char * fstateFormat(rpmtd td)
518 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
519 val = xstrdup(_("(not a number)"));
522 rpmfileState fstate = rpmtdGetNumber(td);
524 case RPMFILE_STATE_NORMAL:
527 case RPMFILE_STATE_REPLACED:
530 case RPMFILE_STATE_NOTINSTALLED:
531 str = _("not installed");
533 case RPMFILE_STATE_NETSHARED:
534 str = _("net shared");
536 case RPMFILE_STATE_WRONGCOLOR:
537 str = _("wrong color");
539 case RPMFILE_STATE_MISSING:
543 str = _("(unknown)");
552 static char * verifyFlags(rpmtd td, const char *pad)
556 if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
557 val = xstrdup(_("(not a number)"));
559 val = rpmVerifyString(rpmtdGetNumber(td), pad);
564 static char * vflagsFormat(rpmtd td)
566 return verifyFlags(td, "");
569 static char * fstatusFormat(rpmtd td)
571 return verifyFlags(td, ".");
574 static char * expandFormat(rpmtd td)
577 if (rpmtdClass(td) != RPM_STRING_CLASS) {
578 val = xstrdup(_("(not a string)"));
580 val = rpmExpand(td->data, NULL);
585 static const struct headerFormatFunc_s rpmHeaderFormats[] = {
586 { RPMTD_FORMAT_STRING, "string", stringFormat },
587 { RPMTD_FORMAT_ARMOR, "armor", armorFormat },
588 { RPMTD_FORMAT_BASE64, "base64", base64Format },
589 { RPMTD_FORMAT_PGPSIG, "pgpsig", pgpsigFormat },
590 { RPMTD_FORMAT_DEPFLAGS, "depflags", depflagsFormat },
591 { RPMTD_FORMAT_DEPTYPE, "deptype", deptypeFormat },
592 { RPMTD_FORMAT_FFLAGS, "fflags", fflagsFormat },
593 { RPMTD_FORMAT_PERMS, "perms", permsFormat },
594 { RPMTD_FORMAT_PERMS, "permissions", permsFormat },
595 { RPMTD_FORMAT_TRIGGERTYPE, "triggertype", triggertypeFormat },
596 { RPMTD_FORMAT_XML, "xml", xmlFormat },
597 { RPMTD_FORMAT_OCTAL, "octal", octalFormat },
598 { RPMTD_FORMAT_HEX, "hex", hexFormat },
599 { RPMTD_FORMAT_DATE, "date", dateFormat },
600 { RPMTD_FORMAT_DAY, "day", dayFormat },
601 { RPMTD_FORMAT_SHESCAPE, "shescape", shescapeFormat },
602 { RPMTD_FORMAT_ARRAYSIZE, "arraysize", arraysizeFormat },
603 { RPMTD_FORMAT_FSTATE, "fstate", fstateFormat },
604 { RPMTD_FORMAT_VFLAGS, "vflags", vflagsFormat },
605 { RPMTD_FORMAT_EXPAND, "expand", expandFormat },
606 { RPMTD_FORMAT_FSTATUS, "fstatus", fstatusFormat },
607 { RPMTD_FORMAT_DEPFLAG_STRONG, "depflag_strong", depflag_strongFormat },
611 headerTagFormatFunction rpmHeaderFormatFuncByName(const char *fmt)
613 const struct headerFormatFunc_s * ext;
614 headerTagFormatFunction func = NULL;
616 for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
617 if (rstreq(ext->name, fmt)) {
625 headerTagFormatFunction rpmHeaderFormatFuncByValue(rpmtdFormats fmt)
627 const struct headerFormatFunc_s * ext;
628 headerTagFormatFunction func = NULL;
630 for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
631 if (fmt == ext->fmt) {