Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / lib / formats.c
1 /** \ingroup header
2  * \file lib/formats.c
3  */
4
5 #include "system.h"
6
7 #include <inttypes.h>
8
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>
16
17 #include "rpmio/digest.h"
18 #include "lib/manifest.h"
19 #include "lib/misc.h"
20 #include "lib/signature.h"
21
22 #include "debug.h"
23
24 /** \ingroup header
25  * Define header tag output formats.
26  */
27
28 struct headerFormatFunc_s {
29     rpmtdFormats fmt;   /*!< Value of extension */
30     const char *name;   /*!< Name of extension. */
31     headerTagFormatFunction func;       /*!< Pointer to formatter function. */  
32 };
33
34 /**
35  * barebones string representation with no extra formatting
36  * @param td            tag data container
37  * @return              formatted string
38  */
39 static char * stringFormat(rpmtd td)
40 {
41     char *val = NULL;
42
43     switch (rpmtdClass(td)) {
44         case RPM_NUMERIC_CLASS:
45             rasprintf(&val, "%" PRIu64, rpmtdGetNumber(td));
46             break;
47         case RPM_STRING_CLASS:
48             val = xstrdup(rpmtdGetString(td));
49             break;
50         case RPM_BINARY_CLASS:
51             val = pgpHexStr(td->data, td->count);
52             break;
53         default:
54             val = xstrdup("(unknown type)");
55             break;
56     }
57     return val;
58 }
59
60 static char * numFormat(rpmtd td, const char *format)
61 {
62     char * val = NULL;
63
64     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
65         val = xstrdup(_("(not a number)"));
66     } else {
67         rasprintf(&val, format, rpmtdGetNumber(td));
68     }
69
70     return val;
71 }
72 /**
73  * octalFormat.
74  * @param td            tag data container
75  * @return              formatted string
76  */
77 static char * octalFormat(rpmtd td)
78 {
79     return numFormat(td, "%o");
80 }
81
82 /**
83  * hexFormat.
84  * @param td            tag data container
85  * @return              formatted string
86  */
87 static char * hexFormat(rpmtd td)
88 {
89     return numFormat(td, "%x");
90 }
91
92 /**
93  * @param td            tag data container
94  * @return              formatted string
95  */
96 static char * realDateFormat(rpmtd td, const char * strftimeFormat)
97 {
98     char * val = NULL;
99
100     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
101         val = xstrdup(_("(not a number)"));
102     } else {
103         struct tm * tstruct;
104         char buf[50];
105         time_t dateint = rpmtdGetNumber(td);
106         tstruct = localtime(&dateint);
107
108         /* XXX TODO: deal with non-fitting date string correctly */
109         buf[0] = '\0';
110         if (tstruct)
111             (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
112         val = xstrdup(buf);
113     }
114
115     return val;
116 }
117
118 /**
119  * Format a date.
120  * @param td            tag data container
121  * @return              formatted string
122  */
123 static char * dateFormat(rpmtd td)
124 {
125     return realDateFormat(td, _("%c"));
126 }
127
128 /**
129  * Format a day.
130  * @param td            tag data container
131  * @return              formatted string
132  */
133 static char * dayFormat(rpmtd td)
134 {
135     return realDateFormat(td, _("%a %b %d %Y"));
136 }
137
138 /**
139  * Return shell escape formatted data.
140  * @param td            tag data container
141  * @return              formatted string
142  */
143 static char * shescapeFormat(rpmtd td)
144 {
145     char * result = NULL, * dst, * src;
146
147     if (rpmtdClass(td) == RPM_NUMERIC_CLASS) {
148         rasprintf(&result, "%" PRIu64, rpmtdGetNumber(td));
149     } else {
150         char *buf = xstrdup(rpmtdGetString(td));;
151
152         result = dst = xmalloc(strlen(buf) * 4 + 3);
153         *dst++ = '\'';
154         for (src = buf; *src != '\0'; src++) {
155             if (*src == '\'') {
156                 *dst++ = '\'';
157                 *dst++ = '\\';
158                 *dst++ = '\'';
159                 *dst++ = '\'';
160             } else {
161                 *dst++ = *src;
162             }
163         }
164         *dst++ = '\'';
165         *dst = '\0';
166         free(buf);
167     }
168
169     return result;
170 }
171
172
173 /**
174  * Identify type of trigger.
175  * @param td            tag data container
176  * @return              formatted string
177  */
178 static char * triggertypeFormat(rpmtd td)
179 {
180     char * val;
181
182     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
183         val = xstrdup(_("(not a number)"));
184     } else {
185         uint64_t item = rpmtdGetNumber(td);
186         if (item & RPMSENSE_TRIGGERPREIN)
187             val = xstrdup("prein");
188         else if (item & RPMSENSE_TRIGGERIN)
189             val = xstrdup("in");
190         else if (item & RPMSENSE_TRIGGERUN)
191             val = xstrdup("un");
192         else if (item & RPMSENSE_TRIGGERPOSTUN)
193             val = xstrdup("postun");
194         else
195             val = xstrdup("");
196     }
197     return val;
198 }
199
200 /**
201  * Identify type of dependency.
202  * @param td            tag data container
203  * @return              formatted string
204  */
205 static char * deptypeFormat(rpmtd td)
206 {
207     char *val = NULL;
208     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
209         val = xstrdup(_("(not a number)"));
210     } else {
211         ARGV_t sdeps = NULL;
212         uint64_t item = rpmtdGetNumber(td);
213
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");
240
241         if (sdeps) {
242             val = argvJoin(sdeps, ",");
243         } else {
244             val = xstrdup("manual");
245         }
246
247         argvFree(sdeps);
248     }
249     return val;
250 }
251
252 /**
253  * Format file permissions for display.
254  * @param td            tag data container
255  * @return              formatted string
256  */
257 static char * permsFormat(rpmtd td)
258 {
259     char * val = NULL;
260
261     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
262         val = xstrdup(_("(not a number)"));
263     } else {
264         val = rpmPermsString(rpmtdGetNumber(td));
265     }
266
267     return val;
268 }
269
270 /**
271  * Format file flags for display.
272  * @param td            tag data container
273  * @return              formatted string
274  */
275 static char * fflagsFormat(rpmtd td)
276 {
277     char * val = NULL;
278
279     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
280         val = xstrdup(_("(not a number)"));
281     } else {
282         val = rpmFFlagsString(rpmtdGetNumber(td), "");
283     }
284
285     return val;
286 }
287
288 /**
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
293  */
294 static char * armorFormat(rpmtd td)
295 {
296     const char * enc;
297     const unsigned char * s;
298     unsigned char * bs = NULL;
299     char *val;
300     size_t ns;
301     int atype;
302
303     switch (rpmtdType(td)) {
304     case RPM_BIN_TYPE:
305         s = td->data;
306         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
307         ns = td->count;
308         atype = PGPARMOR_SIGNATURE;     /* XXX check pkt for signature */
309         break;
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)"));
315         s = bs;
316         atype = PGPARMOR_PUBKEY;        /* XXX check pkt for pubkey */
317         break;
318     case RPM_NULL_TYPE:
319     case RPM_CHAR_TYPE:
320     case RPM_INT8_TYPE:
321     case RPM_INT16_TYPE:
322     case RPM_INT32_TYPE:
323     case RPM_INT64_TYPE:
324     case RPM_I18NSTRING_TYPE:
325     default:
326         return xstrdup(_("(invalid type)"));
327         break;
328     }
329
330     /* XXX this doesn't use padding directly, assumes enough slop in retval. */
331     val = pgpArmorWrap(atype, s, ns);
332     if (atype == PGPARMOR_PUBKEY) {
333         free(bs);
334     }
335     return val;
336 }
337
338 /**
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
343  */
344 static char * base64Format(rpmtd td)
345 {
346     char * val = NULL;
347
348     if (rpmtdType(td) != RPM_BIN_TYPE) {
349         val = xstrdup(_("(not a blob)"));
350     } else {
351         val = rpmBase64Encode(td->data, td->count, -1);
352         if (val == NULL)
353             val = xstrdup("");
354     }
355
356     return val;
357 }
358
359 /**
360  * Wrap tag data in simple header xml markup.
361  * @param td            tag data container
362  * @return              formatted string
363  */
364 static char * xmlFormat(rpmtd td)
365 {
366     const char *xtag = NULL;
367     char *val = NULL;
368     char *s = NULL;
369     rpmtdFormats fmt = RPMTD_FORMAT_STRING;
370
371     switch (rpmtdClass(td)) {
372     case RPM_STRING_CLASS:
373         xtag = "string";
374         break;
375     case RPM_BINARY_CLASS:
376         fmt = RPMTD_FORMAT_BASE64;
377         xtag = "base64";
378         break;
379     case RPM_NUMERIC_CLASS:
380         xtag = "integer";
381         break;
382     case RPM_NULL_TYPE:
383     default:
384         return xstrdup(_("(invalid xml type)"));
385         break;
386     }
387
388     /* XXX TODO: handle errors */
389     s = rpmtdFormat(td, fmt, NULL);
390
391     if (s[0] == '\0') {
392         val = rstrscat(NULL, "\t<", xtag, "/>", NULL);
393     } else {
394         char *new_s = NULL;
395         size_t i, s_size = strlen(s);
396         
397         for (i=0; i<s_size; i++) {
398             switch (s[i]) {
399                 case '<':       rstrcat(&new_s, "&lt;");        break;
400                 case '>':       rstrcat(&new_s, "&gt;");        break;
401                 case '&':       rstrcat(&new_s, "&amp;");       break;
402                 default: {
403                     char c[2] = " ";
404                     *c = s[i];
405                     rstrcat(&new_s, c);
406                     break;
407                 }
408             }
409         }
410
411         val = rstrscat(NULL, "\t<", xtag, ">", new_s, "</", xtag, ">", NULL);
412         free(new_s);
413     }
414     free(s);
415
416     return val;
417 }
418
419 /**
420  * Display signature fingerprint and time.
421  * @param td            tag data container
422  * @return              formatted string
423  */
424 static char * pgpsigFormat(rpmtd td)
425 {
426     char * val = NULL;
427
428     if (rpmtdType(td) != RPM_BIN_TYPE) {
429         val = xstrdup(_("(not a blob)"));
430     } else {
431         pgpDigParams sigp = NULL;
432
433         if (pgpPrtParams(td->data, td->count, PGPTAG_SIGNATURE, &sigp)) {
434             val = xstrdup(_("(not an OpenPGP signature)"));
435         } else {
436             char dbuf[BUFSIZ];
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);
443
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';
448             }
449
450             rasprintf(&val, "%s/%s, %s, Key ID %s",
451                         pgpValString(PGPVAL_PUBKEYALGO, key_algo),
452                         pgpValString(PGPVAL_HASHALGO, hash_algo),
453                         dbuf, keyid);
454
455             free(keyid);
456             pgpDigParamsFree(sigp);
457         }
458     }
459
460     return val;
461 }
462
463 /**
464  * Format dependency flags for display.
465  * @param td            tag data container
466  * @return              formatted string
467  */
468 static char * depflagsFormat(rpmtd td)
469 {
470     char * val = NULL;
471
472     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
473         val = xstrdup(_("(not a number)"));
474     } else {
475         uint64_t anint = rpmtdGetNumber(td);
476         val = xcalloc(4, 1);
477
478         if (anint & RPMSENSE_LESS) 
479             strcat(val, "<");
480         if (anint & RPMSENSE_GREATER)
481             strcat(val, ">");
482         if (anint & RPMSENSE_EQUAL)
483             strcat(val, "=");
484     }
485
486     return val;
487 }
488
489 static char * depflag_strongFormat(rpmtd td)
490 {
491     char * val = NULL;
492
493     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
494         val = xstrdup(_("(not a number)"));
495     } else {
496         uint64_t anint = rpmtdGetNumber(td);
497         val = xstrdup(anint & RPMSENSE_STRONG ? "strong" : "");
498     }
499     return val;
500 }
501
502 /**
503  * Return tag container array size.
504  * @param td            tag data container
505  * @return              formatted string
506  */
507 static char * arraysizeFormat(rpmtd td)
508 {
509     char *val = NULL;
510     rasprintf(&val, "%u", rpmtdCount(td));
511     return val;
512 }
513
514 static char * fstateFormat(rpmtd td)
515 {
516     char * val = NULL;
517
518     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
519         val = xstrdup(_("(not a number)"));
520     } else {
521         const char * str;
522         rpmfileState fstate = rpmtdGetNumber(td);
523         switch (fstate) {
524         case RPMFILE_STATE_NORMAL:
525             str = _("normal");
526             break;
527         case RPMFILE_STATE_REPLACED:
528             str = _("replaced");
529             break;
530         case RPMFILE_STATE_NOTINSTALLED:
531             str = _("not installed");
532             break;
533         case RPMFILE_STATE_NETSHARED:
534             str = _("net shared");
535             break;
536         case RPMFILE_STATE_WRONGCOLOR:
537             str = _("wrong color");
538             break;
539         case RPMFILE_STATE_MISSING:
540             str = _("missing");
541             break;
542         default:
543             str = _("(unknown)");
544             break;
545         }
546         
547         val = xstrdup(str);
548     }
549     return val;
550 }
551
552 static char * verifyFlags(rpmtd td, const char *pad)
553 {
554     char * val = NULL;
555
556     if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
557         val = xstrdup(_("(not a number)"));
558     } else {
559         val = rpmVerifyString(rpmtdGetNumber(td), pad);
560     }
561     return val;
562 }
563
564 static char * vflagsFormat(rpmtd td)
565 {
566     return verifyFlags(td, "");
567 }
568
569 static char * fstatusFormat(rpmtd td)
570 {
571     return verifyFlags(td, ".");
572 }
573
574 static char * expandFormat(rpmtd td)
575 {
576     char *val = NULL;
577     if (rpmtdClass(td) != RPM_STRING_CLASS) {
578         val = xstrdup(_("(not a string)"));
579     } else {
580         val = rpmExpand(td->data, NULL);
581     }
582     return val;
583 }
584
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 },
608     { -1,                       NULL,           NULL }
609 };
610
611 headerTagFormatFunction rpmHeaderFormatFuncByName(const char *fmt)
612 {
613     const struct headerFormatFunc_s * ext;
614     headerTagFormatFunction func = NULL;
615
616     for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
617         if (rstreq(ext->name, fmt)) {
618             func = ext->func;
619             break;
620         }
621     }
622     return func;
623 }
624
625 headerTagFormatFunction rpmHeaderFormatFuncByValue(rpmtdFormats fmt)
626 {
627     const struct headerFormatFunc_s * ext;
628     headerTagFormatFunction func = NULL;
629
630     for (ext = rpmHeaderFormats; ext->name != NULL; ext++) {
631         if (fmt == ext->fmt) {
632             func = ext->func;
633             break;
634         }
635     }
636     return func;
637 }
638