Avoid trying to set "<<none>>" file context.
[platform/upstream/rpm.git] / lib / formats.c
1 /** \ingroup header
2  * \file lib/formats.c
3  */
4
5 #include "system.h"
6 #include "rpmio_internal.h"
7 #include <rpmlib.h>
8 #include <rpmmacro.h>   /* XXX for %_i18ndomains */
9
10 #include <rpmfi.h>
11
12 #include "legacy.h"
13 #include "manifest.h"
14 #include "misc.h"
15
16 #include "debug.h"
17
18 /*@access pgpDig @*/
19 /*@access pgpDigParams @*/
20
21 /**
22  * Identify type of trigger.
23  * @param type          tag type
24  * @param data          tag value
25  * @param formatPrefix  (unused)
26  * @param padding       (unused)
27  * @param element       (unused)
28  * @return              formatted string
29  */
30 static /*@only@*/ char * triggertypeFormat(int_32 type, const void * data, 
31                 /*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
32                 /*@unused@*/ int element)
33         /*@requires maxRead(data) >= 0 @*/
34 {
35     const int_32 * item = data;
36     char * val;
37
38     if (type != RPM_INT32_TYPE)
39         val = xstrdup(_("(not a number)"));
40     else if (*item & RPMSENSE_TRIGGERPREIN)
41         val = xstrdup("prein");
42     else if (*item & RPMSENSE_TRIGGERIN)
43         val = xstrdup("in");
44     else if (*item & RPMSENSE_TRIGGERUN)
45         val = xstrdup("un");
46     else if (*item & RPMSENSE_TRIGGERPOSTUN)
47         val = xstrdup("postun");
48     else
49         val = xstrdup("");
50     return val;
51 }
52
53 /**
54  * Format file permissions for display.
55  * @param type          tag type
56  * @param data          tag value
57  * @param formatPrefix
58  * @param padding
59  * @param element       (unused)
60  * @return              formatted string
61  */
62 static /*@only@*/ char * permsFormat(int_32 type, const void * data,
63                 char * formatPrefix, int padding, /*@unused@*/ int element)
64         /*@modifies formatPrefix @*/
65         /*@requires maxRead(data) >= 0 @*/
66 {
67     char * val;
68     char * buf;
69
70     if (type != RPM_INT32_TYPE) {
71         val = xstrdup(_("(not a number)"));
72     } else {
73         val = xmalloc(15 + padding);
74 /*@-boundswrite@*/
75         strcat(formatPrefix, "s");
76 /*@=boundswrite@*/
77         buf = rpmPermsString(*((int_32 *) data));
78         /*@-formatconst@*/
79         sprintf(val, formatPrefix, buf);
80         /*@=formatconst@*/
81         buf = _free(buf);
82     }
83
84     return val;
85 }
86
87 /**
88  * Format file flags for display.
89  * @param type          tag type
90  * @param data          tag value
91  * @param formatPrefix
92  * @param padding
93  * @param element       (unused)
94  * @return              formatted string
95  */
96 static /*@only@*/ char * fflagsFormat(int_32 type, const void * data, 
97                 char * formatPrefix, int padding, /*@unused@*/ int element)
98         /*@modifies formatPrefix @*/
99         /*@requires maxRead(data) >= 0 @*/
100 {
101     char * val;
102     char buf[15];
103     int anint = *((int_32 *) data);
104
105     if (type != RPM_INT32_TYPE) {
106         val = xstrdup(_("(not a number)"));
107     } else {
108         buf[0] = '\0';
109 /*@-boundswrite@*/
110         if (anint & RPMFILE_DOC)
111             strcat(buf, "d");
112         if (anint & RPMFILE_CONFIG)
113             strcat(buf, "c");
114         if (anint & RPMFILE_SPECFILE)
115             strcat(buf, "s");
116         if (anint & RPMFILE_MISSINGOK)
117             strcat(buf, "m");
118         if (anint & RPMFILE_NOREPLACE)
119             strcat(buf, "n");
120         if (anint & RPMFILE_GHOST)
121             strcat(buf, "g");
122         if (anint & RPMFILE_LICENSE)
123             strcat(buf, "l");
124         if (anint & RPMFILE_README)
125             strcat(buf, "r");
126 /*@=boundswrite@*/
127
128         val = xmalloc(5 + padding);
129 /*@-boundswrite@*/
130         strcat(formatPrefix, "s");
131 /*@=boundswrite@*/
132         /*@-formatconst@*/
133         sprintf(val, formatPrefix, buf);
134         /*@=formatconst@*/
135     }
136
137     return val;
138 }
139
140 /**
141  * Wrap a pubkey in ascii armor for display.
142  * @todo Permit selectable display formats (i.e. binary).
143  * @param type          tag type
144  * @param data          tag value
145  * @param formatPrefix  (unused)
146  * @param padding       (unused)
147  * @param element       no. bytes of binary data
148  * @return              formatted string
149  */
150 static /*@only@*/ char * armorFormat(int_32 type, const void * data, 
151                 /*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
152                 int element)
153         /*@*/
154 {
155     const char * enc;
156     const unsigned char * s;
157     size_t ns;
158     int atype;
159
160     switch (type) {
161     case RPM_BIN_TYPE:
162         s = data;
163         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
164         ns = element;
165         atype = PGPARMOR_SIGNATURE;     /* XXX check pkt for signature */
166         break;
167     case RPM_STRING_TYPE:
168     case RPM_STRING_ARRAY_TYPE:
169         enc = data;
170         if (b64decode(enc, (void **)&s, &ns))
171             return xstrdup(_("(not base64)"));
172         atype = PGPARMOR_PUBKEY;        /* XXX check pkt for pubkey */
173         break;
174     case RPM_NULL_TYPE:
175     case RPM_CHAR_TYPE:
176     case RPM_INT8_TYPE:
177     case RPM_INT16_TYPE:
178     case RPM_INT32_TYPE:
179     case RPM_I18NSTRING_TYPE:
180     default:
181         return xstrdup(_("(invalid type)"));
182         /*@notreached@*/ break;
183     }
184
185     /* XXX this doesn't use padding directly, assumes enough slop in retval. */
186     return pgpArmorWrap(atype, s, ns);
187 }
188
189 /**
190  * Encode binary data in base64 for display.
191  * @todo Permit selectable display formats (i.e. binary).
192  * @param type          tag type
193  * @param data          tag value
194  * @param formatPrefix  (unused)
195  * @param padding
196  * @param element
197  * @return              formatted string
198  */
199 static /*@only@*/ char * base64Format(int_32 type, const void * data, 
200                 /*@unused@*/ char * formatPrefix, int padding, int element)
201         /*@*/
202 {
203     char * val;
204
205     if (type != RPM_BIN_TYPE) {
206         val = xstrdup(_("(not a blob)"));
207     } else {
208         const char * enc;
209         char * t;
210         int lc;
211         /* XXX HACK ALERT: element field abused as no. bytes of binary data. */
212         size_t ns = element;
213         size_t nt = ((ns + 2) / 3) * 4;
214
215 /*@-boundswrite@*/
216         /*@-globs@*/
217         /* Add additional bytes necessary for eol string(s). */
218         if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
219             lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
220         if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
221             ++lc;
222             nt += lc * strlen(b64encode_eolstr);
223         }
224         /*@=globs@*/
225
226         val = t = xmalloc(nt + padding + 1);
227
228         *t = '\0';
229         if ((enc = b64encode(data, ns)) != NULL) {
230             t = stpcpy(t, enc);
231             enc = _free(enc);
232         }
233 /*@=boundswrite@*/
234     }
235
236     return val;
237 }
238
239 /**
240  */
241 static size_t xmlstrlen(const char * s)
242         /*@*/
243 {
244     size_t len = 0;
245     int c;
246
247 /*@-boundsread@*/
248     while ((c = *s++) != '\0')
249 /*@=boundsread@*/
250     {
251         switch (c) {
252         case '<': case '>':     len += 4;       /*@switchbreak@*/ break;
253         case '&':               len += 5;       /*@switchbreak@*/ break;
254         default:                len += 1;       /*@switchbreak@*/ break;
255         }
256     }
257     return len;
258 }
259
260 /**
261  */
262 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
263         /*@modifies t @*/
264 {
265     char * te = t;
266     int c;
267
268 /*@-bounds@*/
269     while ((c = *s++) != '\0') {
270         switch (c) {
271         case '<':       te = stpcpy(te, "&lt;");        /*@switchbreak@*/ break;
272         case '>':       te = stpcpy(te, "&gt;");        /*@switchbreak@*/ break;
273         case '&':       te = stpcpy(te, "&amp;");       /*@switchbreak@*/ break;
274         default:        *te++ = c;                      /*@switchbreak@*/ break;
275         }
276     }
277     *te = '\0';
278 /*@=bounds@*/
279     return t;
280 }
281
282 /**
283  * Wrap tag data in simple header xml markup.
284  * @param type          tag type
285  * @param data          tag value
286  * @param formatPrefix
287  * @param padding
288  * @param element       (unused)
289  * @return              formatted string
290  */
291 /*@-bounds@*/
292 static /*@only@*/ char * xmlFormat(int_32 type, const void * data, 
293                 char * formatPrefix, int padding,
294                 /*@unused@*/ int element)
295         /*@modifies formatPrefix @*/
296 {
297     const char * xtag = NULL;
298     size_t nb;
299     char * val;
300     const char * s = NULL;
301     char * t, * te;
302     unsigned long anint = 0;
303     int xx;
304
305 /*@-branchstate@*/
306     switch (type) {
307     case RPM_I18NSTRING_TYPE:
308     case RPM_STRING_TYPE:
309         s = data;
310         xtag = "string";
311         break;
312     case RPM_BIN_TYPE:
313     {   int cpl = b64encode_chars_per_line;
314 /*@-mods@*/
315         b64encode_chars_per_line = 0;
316 /*@=mods@*/
317 /*@-formatconst@*/
318         s = base64Format(type, data, formatPrefix, padding, element);
319 /*@=formatconst@*/
320 /*@-mods@*/
321         b64encode_chars_per_line = cpl;
322 /*@=mods@*/
323         xtag = "base64";
324     }   break;
325     case RPM_CHAR_TYPE:
326     case RPM_INT8_TYPE:
327         anint = *((uint_8 *) data);
328         break;
329     case RPM_INT16_TYPE:
330         anint = *((uint_16 *) data);
331         break;
332     case RPM_INT32_TYPE:
333         anint = *((uint_32 *) data);
334         break;
335     case RPM_NULL_TYPE:
336     case RPM_STRING_ARRAY_TYPE:
337     default:
338         return xstrdup(_("(invalid xml type)"));
339         /*@notreached@*/ break;
340     }
341 /*@=branchstate@*/
342
343 /*@-branchstate@*/
344     if (s == NULL) {
345         int tlen = 32;
346         t = memset(alloca(tlen+1), 0, tlen+1);
347         xx = snprintf(t, tlen, "%lu", anint);
348         s = t;
349         xtag = "integer";
350     }
351 /*@=branchstate@*/
352
353     nb = 2 * strlen(xtag) + sizeof("\t<></>") + xmlstrlen(s);
354     te = t = alloca(nb);
355     te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
356     te = xmlstrcpy(te, s);
357     te += strlen(te);
358     te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
359
360     /* XXX s was malloc'd */
361 /*@-branchstate@*/
362     if (!strcmp(xtag, "base64"))
363         s = _free(s);
364 /*@=branchstate@*/
365
366     nb += padding;
367     val = xmalloc(nb+1);
368 /*@-boundswrite@*/
369     strcat(formatPrefix, "s");
370 /*@=boundswrite@*/
371 /*@-formatconst@*/
372     xx = snprintf(val, nb, formatPrefix, t);
373 /*@=formatconst@*/
374     val[nb] = '\0';
375
376     return val;
377 }
378 /*@=bounds@*/
379
380 /**
381  * Display signature fingerprint and time.
382  * @param type          tag type
383  * @param data          tag value
384  * @param formatPrefix  (unused)
385  * @param padding
386  * @param element       (unused)
387  * @return              formatted string
388  */
389 static /*@only@*/ char * pgpsigFormat(int_32 type, const void * data, 
390                 /*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
391                 /*@unused@*/ int element)
392         /*@globals fileSystem, internalState @*/
393         /*@modifies fileSystem, internalState @*/
394 {
395     char * val, * t;
396
397     if (type != RPM_BIN_TYPE) {
398         val = xstrdup(_("(not a blob)"));
399     } else {
400         unsigned char * pkt = (byte *) data;
401         unsigned int pktlen = 0;
402 /*@-boundsread@*/
403         unsigned int v = *pkt;
404 /*@=boundsread@*/
405         pgpTag tag = 0;
406         unsigned int plen;
407         unsigned int hlen = 0;
408
409         if (v & 0x80) {
410             if (v & 0x40) {
411                 tag = (v & 0x3f);
412                 plen = pgpLen(pkt+1, &hlen);
413             } else {
414                 tag = (v >> 2) & 0xf;
415                 plen = (1 << (v & 0x3));
416                 hlen = pgpGrab(pkt+1, plen);
417             }
418         
419             pktlen = 1 + plen + hlen;
420         }
421
422         if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
423             val = xstrdup(_("(not an OpenPGP signature)"));
424         } else {
425             pgpDig dig = pgpNewDig();
426             pgpDigParams sigp = &dig->signature;
427             size_t nb = 80;
428
429             (void) pgpPrtPkts(pkt, pktlen, dig, 0);
430
431             val = t = xmalloc(nb + 1);
432
433 /*@-boundswrite@*/
434             switch (sigp->pubkey_algo) {
435             case PGPPUBKEYALGO_DSA:
436                 t = stpcpy(t, "DSA");
437                 break;
438             case PGPPUBKEYALGO_RSA:
439                 t = stpcpy(t, "RSA");
440                 break;
441             default:
442                 sprintf(t, "%d", sigp->pubkey_algo);
443                 t += strlen(t);
444                 break;
445             }
446             *t++ = '/';
447             switch (sigp->hash_algo) {
448             case PGPHASHALGO_MD5:
449                 t = stpcpy(t, "MD5");
450                 break;
451             case PGPHASHALGO_SHA1:
452                 t = stpcpy(t, "SHA1");
453                 break;
454             default:
455                 sprintf(t, "%d", sigp->hash_algo);
456                 t += strlen(t);
457                 break;
458             }
459
460             t = stpcpy(t, ", ");
461
462             /* this is important if sizeof(int_32) ! sizeof(time_t) */
463             {   time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
464                 struct tm * tstruct = localtime(&dateint);
465                 if (tstruct)
466                     (void) strftime(t, (nb - (t - val)), "%c", tstruct);
467             }
468             t += strlen(t);
469             t = stpcpy(t, ", Key ID ");
470             t = stpcpy(t, pgpHexStr(sigp->signid, sizeof(sigp->signid)));
471 /*@=boundswrite@*/
472
473             dig = pgpFreeDig(dig);
474         }
475     }
476
477     return val;
478 }
479
480 /**
481  * Format dependency flags for display.
482  * @param type          tag type
483  * @param data          tag value
484  * @param formatPrefix
485  * @param padding
486  * @param element       (unused)
487  * @return              formatted string
488  */
489 static /*@only@*/ char * depflagsFormat(int_32 type, const void * data, 
490                 char * formatPrefix, int padding, /*@unused@*/ int element)
491         /*@modifies formatPrefix @*/
492         /*@requires maxRead(data) >= 0 @*/
493 {
494     char * val;
495     char buf[10];
496     int anint;
497
498     if (type != RPM_INT32_TYPE) {
499         val = xstrdup(_("(not a number)"));
500     } else {
501         anint = *((int_32 *) data);
502         buf[0] = '\0';
503
504 /*@-boundswrite@*/
505         if (anint & RPMSENSE_LESS) 
506             strcat(buf, "<");
507         if (anint & RPMSENSE_GREATER)
508             strcat(buf, ">");
509         if (anint & RPMSENSE_EQUAL)
510             strcat(buf, "=");
511 /*@=boundswrite@*/
512
513         val = xmalloc(5 + padding);
514 /*@-boundswrite@*/
515         strcat(formatPrefix, "s");
516 /*@=boundswrite@*/
517         /*@-formatconst@*/
518         sprintf(val, formatPrefix, buf);
519         /*@=formatconst@*/
520     }
521
522     return val;
523 }
524
525 /**
526  * Retrieve mounted file system paths.
527  * @param h             header
528  * @retval *type        tag type
529  * @retval *data        tag value
530  * @retval *count       no. of data items
531  * @retval *freeData    data-was-malloc'ed indicator
532  * @return              0 on success
533  */
534 static int fsnamesTag( /*@unused@*/ Header h, /*@out@*/ int_32 * type,
535                 /*@out@*/ void ** data, /*@out@*/ int_32 * count,
536                 /*@out@*/ int * freeData)
537         /*@globals fileSystem, internalState @*/
538         /*@modifies *type, *data, *count, *freeData,
539                 fileSystem, internalState @*/
540         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
541                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
542 {
543     const char ** list;
544
545 /*@-boundswrite@*/
546     if (rpmGetFilesystemList(&list, count))
547         return 1;
548 /*@=boundswrite@*/
549
550     if (type) *type = RPM_STRING_ARRAY_TYPE;
551     if (data) *((const char ***) data) = list;
552     if (freeData) *freeData = 0;
553
554     return 0; 
555 }
556
557 /**
558  * Retrieve install prefixes.
559  * @param h             header
560  * @retval *type        tag type
561  * @retval *data        tag value
562  * @retval *count       no. of data items
563  * @retval *freeData    data-was-malloc'ed indicator
564  * @return              0 on success
565  */
566 static int instprefixTag(Header h, /*@null@*/ /*@out@*/ rpmTagType * type,
567                 /*@null@*/ /*@out@*/ const void ** data,
568                 /*@null@*/ /*@out@*/ int_32 * count,
569                 /*@null@*/ /*@out@*/ int * freeData)
570         /*@modifies *type, *data, *freeData @*/
571         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
572                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
573 {
574     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
575     HFD_t hfd = headerFreeData;
576     rpmTagType ipt;
577     char ** array;
578
579     if (hge(h, RPMTAG_INSTALLPREFIX, type, (void **)data, count)) {
580         if (freeData) *freeData = 0;
581         return 0;
582     } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &array, count)) {
583         if (type) *type = RPM_STRING_TYPE;
584 /*@-boundsread@*/
585         if (data) *data = xstrdup(array[0]);
586 /*@=boundsread@*/
587         if (freeData) *freeData = 1;
588         array = hfd(array, ipt);
589         return 0;
590     }
591
592     return 1;
593 }
594
595 /**
596  * Retrieve mounted file system space.
597  * @param h             header
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
603  */
604 static int fssizesTag(Header h, /*@out@*/ rpmTagType * type,
605                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
606                 /*@out@*/ int * freeData)
607         /*@globals rpmGlobalMacroContext, h_errno,
608                 fileSystem, internalState @*/
609         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext,
610                 fileSystem, internalState @*/
611         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
612                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
613 {
614     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
615     const char ** filenames;
616     int_32 * filesizes;
617     uint_32 * usages;
618     int numFiles;
619
620     if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &filesizes, &numFiles)) {
621         filesizes = NULL;
622         numFiles = 0;
623         filenames = NULL;
624     } else {
625         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
626     }
627
628 /*@-boundswrite@*/
629     if (rpmGetFilesystemList(NULL, count))
630         return 1;
631 /*@=boundswrite@*/
632
633     *type = RPM_INT32_TYPE;
634     *freeData = 1;
635
636     if (filenames == NULL) {
637         usages = xcalloc((*count), sizeof(usages));
638         *data = usages;
639
640         return 0;
641     }
642
643 /*@-boundswrite@*/
644     if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))      
645         return 1;
646 /*@=boundswrite@*/
647
648     *data = usages;
649
650     filenames = _free(filenames);
651
652     return 0;
653 }
654
655 /**
656  * Retrieve trigger info.
657  * @param h             header
658  * @retval *type        tag type
659  * @retval *data        tag value
660  * @retval *count       no. of data items
661  * @retval *freeData    data-was-malloc'ed indicator
662  * @return              0 on success
663  */
664 static int triggercondsTag(Header h, /*@out@*/ rpmTagType * type,
665                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
666                 /*@out@*/ int * freeData)
667         /*@modifies *type, *data, *count, *freeData @*/
668         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
669                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
670 {
671     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
672     HFD_t hfd = headerFreeData;
673     rpmTagType tnt, tvt, tst;
674     int_32 * indices, * flags;
675     char ** names, ** versions;
676     int numNames, numScripts;
677     char ** conds, ** s;
678     char * item, * flagsStr;
679     char * chptr;
680     int i, j, xx;
681     char buf[5];
682
683     if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (void **) &names, &numNames)) {
684         *freeData = 0;
685         return 0;
686     }
687
688     xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, NULL);
689     xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
690     xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (void **) &versions, NULL);
691     xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
692     s = hfd(s, tst);
693
694     *freeData = 1;
695     *data = conds = xmalloc(sizeof(*conds) * numScripts);
696     *count = numScripts;
697     *type = RPM_STRING_ARRAY_TYPE;
698 /*@-bounds@*/
699     for (i = 0; i < numScripts; i++) {
700         chptr = xstrdup("");
701
702         for (j = 0; j < numNames; j++) {
703             if (indices[j] != i)
704                 /*@innercontinue@*/ continue;
705
706             item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
707             if (flags[j] & RPMSENSE_SENSEMASK) {
708                 buf[0] = '%', buf[1] = '\0';
709                 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, j);
710                 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
711                 flagsStr = _free(flagsStr);
712             } else {
713                 strcpy(item, names[j]);
714             }
715
716             chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
717             if (*chptr != '\0') strcat(chptr, ", ");
718             strcat(chptr, item);
719             item = _free(item);
720         }
721
722         conds[i] = chptr;
723     }
724 /*@=bounds@*/
725
726     names = hfd(names, tnt);
727     versions = hfd(versions, tvt);
728
729     return 0;
730 }
731
732 /**
733  * Retrieve trigger type info.
734  * @param h             header
735  * @retval *type        tag type
736  * @retval *data        tag value
737  * @retval *count       no. of data items
738  * @retval *freeData    data-was-malloc'ed indicator
739  * @return              0 on success
740  */
741 static int triggertypeTag(Header h, /*@out@*/ rpmTagType * type,
742                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
743                 /*@out@*/ int * freeData)
744         /*@modifies *type, *data, *count, *freeData @*/
745         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
746                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
747 {
748     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
749     HFD_t hfd = headerFreeData;
750     rpmTagType tst;
751     int_32 * indices, * flags;
752     const char ** conds;
753     const char ** s;
754     int i, j, xx;
755     int numScripts, numNames;
756
757     if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, &numNames)) {
758         *freeData = 0;
759         return 1;
760     }
761
762     xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
763     xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
764     s = hfd(s, tst);
765
766     *freeData = 1;
767     *data = conds = xmalloc(sizeof(*conds) * numScripts);
768     *count = numScripts;
769     *type = RPM_STRING_ARRAY_TYPE;
770 /*@-bounds@*/
771     for (i = 0; i < numScripts; i++) {
772         for (j = 0; j < numNames; j++) {
773             if (indices[j] != i)
774                 /*@innercontinue@*/ continue;
775
776             if (flags[j] & RPMSENSE_TRIGGERPREIN)
777                 conds[i] = xstrdup("prein");
778             else if (flags[j] & RPMSENSE_TRIGGERIN)
779                 conds[i] = xstrdup("in");
780             else if (flags[j] & RPMSENSE_TRIGGERUN)
781                 conds[i] = xstrdup("un");
782             else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
783                 conds[i] = xstrdup("postun");
784             else
785                 conds[i] = xstrdup("");
786             /*@innerbreak@*/ break;
787         }
788     }
789 /*@=bounds@*/
790
791     return 0;
792 }
793
794 /**
795  * Retrieve file paths.
796  * @param h             header
797  * @retval *type        tag type
798  * @retval *data        tag value
799  * @retval *count       no. of data items
800  * @retval *freeData    data-was-malloc'ed indicator
801  * @return              0 on success
802  */
803 static int filenamesTag(Header h, /*@out@*/ rpmTagType * type,
804                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
805                 /*@out@*/ int * freeData)
806         /*@modifies *type, *data, *count, *freeData @*/
807         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
808                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
809 {
810     *type = RPM_STRING_ARRAY_TYPE;
811     rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
812     *freeData = 1;
813     return 0; 
814 }
815
816 /**
817  * Retrieve file classes.
818  * @param h             header
819  * @retval *type        tag type
820  * @retval *data        tag value
821  * @retval *count       no. of data items
822  * @retval *freeData    data-was-malloc'ed indicator
823  * @return              0 on success
824  */
825 static int fileclassTag(Header h, /*@out@*/ rpmTagType * type,
826                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
827                 /*@out@*/ int * freeData)
828         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
829         /*@modifies h, *type, *data, *count, *freeData,
830                 rpmGlobalMacroContext, fileSystem @*/
831         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
832                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
833 {
834     *type = RPM_STRING_ARRAY_TYPE;
835     rpmfiBuildFClasses(h, (const char ***) data, count);
836     *freeData = 1;
837     return 0; 
838 }
839
840 /**
841  * Retrieve file contexts from header.
842  * @param h             header
843  * @retval *type        tag type
844  * @retval *data        tag value
845  * @retval *count       no. of data items
846  * @retval *freeData    data-was-malloc'ed indicator
847  * @return              0 on success
848  */
849 static int filecontextsTag(Header h, /*@out@*/ rpmTagType * type,
850                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
851                 /*@out@*/ int * freeData)
852         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
853         /*@modifies h, *type, *data, *count, *freeData,
854                 rpmGlobalMacroContext, fileSystem @*/
855         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
856                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
857 {
858     *type = RPM_STRING_ARRAY_TYPE;
859     rpmfiBuildFContexts(h, (const char ***) data, count);
860     *freeData = 1;
861     return 0; 
862 }
863
864 /**
865  * Retrieve file contexts from file system.
866  * @param h             header
867  * @retval *type        tag type
868  * @retval *data        tag value
869  * @retval *count       no. of data items
870  * @retval *freeData    data-was-malloc'ed indicator
871  * @return              0 on success
872  */
873 static int fscontextsTag(Header h, /*@out@*/ rpmTagType * type,
874                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
875                 /*@out@*/ int * freeData)
876         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
877         /*@modifies h, *type, *data, *count, *freeData,
878                 rpmGlobalMacroContext, fileSystem @*/
879         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
880                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
881 {
882     *type = RPM_STRING_ARRAY_TYPE;
883     rpmfiBuildFSContexts(h, (const char ***) data, count);
884     *freeData = 1;
885     return 0; 
886 }
887
888 /**
889  * Retrieve file contexts from policy RE's.
890  * @param h             header
891  * @retval *type        tag type
892  * @retval *data        tag value
893  * @retval *count       no. of data items
894  * @retval *freeData    data-was-malloc'ed indicator
895  * @return              0 on success
896  */
897 static int recontextsTag(Header h, /*@out@*/ rpmTagType * type,
898                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
899                 /*@out@*/ int * freeData)
900         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
901         /*@modifies h, *type, *data, *count, *freeData,
902                 rpmGlobalMacroContext, fileSystem @*/
903         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
904                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
905 {
906     *type = RPM_STRING_ARRAY_TYPE;
907     rpmfiBuildREContexts(h, (const char ***) data, count);
908     *freeData = 1;
909     return 0; 
910 }
911
912 /**
913  * Retrieve file provides.
914  * @param h             header
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
920  */
921 static int fileprovideTag(Header h, /*@out@*/ rpmTagType * type,
922                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
923                 /*@out@*/ int * freeData)
924         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
925         /*@modifies h, *type, *data, *count, *freeData,
926                 rpmGlobalMacroContext, fileSystem @*/
927         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
928                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
929 {
930     *type = RPM_STRING_ARRAY_TYPE;
931     rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
932     *freeData = 1;
933     return 0; 
934 }
935
936 /**
937  * Retrieve file requires.
938  * @param h             header
939  * @retval *type        tag type
940  * @retval *data        tag value
941  * @retval *count       no. of data items
942  * @retval *freeData    data-was-malloc'ed indicator
943  * @return              0 on success
944  */
945 static int filerequireTag(Header h, /*@out@*/ rpmTagType * type,
946                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
947                 /*@out@*/ int * freeData)
948         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
949         /*@modifies h, *type, *data, *count, *freeData,
950                 rpmGlobalMacroContext, fileSystem @*/
951         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
952                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
953 {
954     *type = RPM_STRING_ARRAY_TYPE;
955     rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
956     *freeData = 1;
957     return 0; 
958 }
959
960 /* I18N look aside diversions */
961
962 /*@-exportlocal -exportheadervar@*/
963 /*@unchecked@*/
964 int _nl_msg_cat_cntr;   /* XXX GNU gettext voodoo */
965 /*@=exportlocal =exportheadervar@*/
966 /*@observer@*/ /*@unchecked@*/
967 static const char * language = "LANGUAGE";
968
969 /*@observer@*/ /*@unchecked@*/
970 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
971
972 /**
973  * Retrieve i18n text.
974  * @param h             header
975  * @param tag           tag
976  * @retval *type        tag type
977  * @retval *data        tag value
978  * @retval *count       no. of data items
979  * @retval *freeData    data-was-malloc'ed indicator
980  * @return              0 on success
981  */
982 static int i18nTag(Header h, int_32 tag, /*@out@*/ rpmTagType * type,
983                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
984                 /*@out@*/ int * freeData)
985         /*@globals rpmGlobalMacroContext, h_errno @*/
986         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
987         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
988                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
989 {
990     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
991     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
992     int rc;
993
994     *type = RPM_STRING_TYPE;
995     *data = NULL;
996     *count = 0;
997     *freeData = 0;
998
999     if (dstring && *dstring) {
1000         char *domain, *de;
1001         const char * langval;
1002         const char * msgkey;
1003         const char * msgid;
1004
1005         {   const char * tn = tagName(tag);
1006             const char * n;
1007             char * mk;
1008             (void) headerNVR(h, &n, NULL, NULL);
1009             mk = alloca(strlen(n) + strlen(tn) + sizeof("()"));
1010             sprintf(mk, "%s(%s)", n, tn);
1011             msgkey = mk;
1012         }
1013
1014         /* change to en_US for msgkey -> msgid resolution */
1015         langval = getenv(language);
1016         (void) setenv(language, "en_US", 1);
1017 /*@i@*/ ++_nl_msg_cat_cntr;
1018
1019         msgid = NULL;
1020         /*@-branchstate@*/
1021         for (domain = dstring; domain != NULL; domain = de) {
1022             de = strchr(domain, ':');
1023             if (de) *de++ = '\0';
1024             msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/;
1025             if (msgid != msgkey) break;
1026         }
1027         /*@=branchstate@*/
1028
1029         /* restore previous environment for msgid -> msgstr resolution */
1030         if (langval)
1031             (void) setenv(language, langval, 1);
1032         else
1033             unsetenv(language);
1034 /*@i@*/ ++_nl_msg_cat_cntr;
1035
1036         if (domain && msgid) {
1037             *data = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/;
1038             *data = xstrdup(*data);     /* XXX xstrdup has side effects. */
1039             *count = 1;
1040             *freeData = 1;
1041         }
1042         dstring = _free(dstring);
1043         if (*data)
1044             return 0;
1045     }
1046
1047     dstring = _free(dstring);
1048
1049     rc = hge(h, tag, type, (void **)data, count);
1050
1051     if (rc && (*data) != NULL) {
1052         *data = xstrdup(*data);
1053         *freeData = 1;
1054         return 0;
1055     }
1056
1057     *freeData = 0;
1058     *data = NULL;
1059     *count = 0;
1060     return 1;
1061 }
1062
1063 /**
1064  * Retrieve summary text.
1065  * @param h             header
1066  * @retval *type        tag type
1067  * @retval *data        tag value
1068  * @retval *count       no. of data items
1069  * @retval *freeData    data-was-malloc'ed indicator
1070  * @return              0 on success
1071  */
1072 static int summaryTag(Header h, /*@out@*/ rpmTagType * type,
1073                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
1074                 /*@out@*/ int * freeData)
1075         /*@globals rpmGlobalMacroContext, h_errno @*/
1076         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
1077         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
1078                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
1079 {
1080     return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
1081 }
1082
1083 /**
1084  * Retrieve description text.
1085  * @param h             header
1086  * @retval *type        tag type
1087  * @retval *data        tag value
1088  * @retval *count       no. of data items
1089  * @retval *freeData    data-was-malloc'ed indicator
1090  * @return              0 on success
1091  */
1092 static int descriptionTag(Header h, /*@out@*/ rpmTagType * type,
1093                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
1094                 /*@out@*/ int * freeData)
1095         /*@globals rpmGlobalMacroContext, h_errno @*/
1096         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
1097         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
1098                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
1099 {
1100     return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
1101 }
1102
1103 /**
1104  * Retrieve group text.
1105  * @param h             header
1106  * @retval *type        tag type
1107  * @retval *data        tag value
1108  * @retval *count       no. of data items
1109  * @retval *freeData    data-was-malloc'ed indicator
1110  * @return              0 on success
1111  */
1112 static int groupTag(Header h, /*@out@*/ rpmTagType * type,
1113                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
1114                 /*@out@*/ int * freeData)
1115         /*@globals rpmGlobalMacroContext, h_errno @*/
1116         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
1117         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
1118                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
1119 {
1120     return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
1121 }
1122
1123 /*@-type@*/ /* FIX: cast? */
1124 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
1125     { HEADER_EXT_TAG, "RPMTAG_GROUP",           { groupTag } },
1126     { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",     { descriptionTag } },
1127     { HEADER_EXT_TAG, "RPMTAG_SUMMARY",         { summaryTag } },
1128     { HEADER_EXT_TAG, "RPMTAG_FILECLASS",       { fileclassTag } },
1129     { HEADER_EXT_TAG, "RPMTAG_FILECONTEXTS",    { filecontextsTag } },
1130     { HEADER_EXT_TAG, "RPMTAG_FILENAMES",       { filenamesTag } },
1131     { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE",     { fileprovideTag } },
1132     { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE",     { filerequireTag } },
1133     { HEADER_EXT_TAG, "RPMTAG_FSCONTEXTS",      { fscontextsTag } },
1134     { HEADER_EXT_TAG, "RPMTAG_FSNAMES",         { fsnamesTag } },
1135     { HEADER_EXT_TAG, "RPMTAG_FSSIZES",         { fssizesTag } },
1136     { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",   { instprefixTag } },
1137     { HEADER_EXT_TAG, "RPMTAG_RECONTEXTS",      { recontextsTag } },
1138     { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",    { triggercondsTag } },
1139     { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",     { triggertypeTag } },
1140     { HEADER_EXT_FORMAT, "armor",               { armorFormat } },
1141     { HEADER_EXT_FORMAT, "base64",              { base64Format } },
1142     { HEADER_EXT_FORMAT, "pgpsig",              { pgpsigFormat } },
1143     { HEADER_EXT_FORMAT, "depflags",            { depflagsFormat } },
1144     { HEADER_EXT_FORMAT, "fflags",              { fflagsFormat } },
1145     { HEADER_EXT_FORMAT, "perms",               { permsFormat } },
1146     { HEADER_EXT_FORMAT, "permissions",         { permsFormat } },
1147     { HEADER_EXT_FORMAT, "triggertype",         { triggertypeFormat } },
1148     { HEADER_EXT_FORMAT, "xml",                 { xmlFormat } },
1149     { HEADER_EXT_MORE, NULL,            { (void *) headerDefaultFormats } }
1150 } ;
1151 /*@=type@*/