Rip out unnecessary selinux babbage.
[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         if (anint != 0)
348             xx = snprintf(t, tlen, "%lu", anint);
349         s = t;
350         xtag = "integer";
351     }
352 /*@=branchstate@*/
353
354     nb = xmlstrlen(s);
355     if (nb == 0) {
356         nb += strlen(xtag) + sizeof("\t</>");
357         te = t = alloca(nb);
358         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
359     } else {
360         nb += 2 * strlen(xtag) + sizeof("\t<></>");
361         te = t = alloca(nb);
362         te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
363         te = xmlstrcpy(te, s);
364         te += strlen(te);
365         te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
366     }
367
368     /* XXX s was malloc'd */
369 /*@-branchstate@*/
370     if (!strcmp(xtag, "base64"))
371         s = _free(s);
372 /*@=branchstate@*/
373
374     nb += padding;
375     val = xmalloc(nb+1);
376 /*@-boundswrite@*/
377     strcat(formatPrefix, "s");
378 /*@=boundswrite@*/
379 /*@-formatconst@*/
380     xx = snprintf(val, nb, formatPrefix, t);
381 /*@=formatconst@*/
382     val[nb] = '\0';
383
384     return val;
385 }
386 /*@=bounds@*/
387
388 /**
389  * Display signature fingerprint and time.
390  * @param type          tag type
391  * @param data          tag value
392  * @param formatPrefix  (unused)
393  * @param padding
394  * @param element       (unused)
395  * @return              formatted string
396  */
397 static /*@only@*/ char * pgpsigFormat(int_32 type, const void * data, 
398                 /*@unused@*/ char * formatPrefix, /*@unused@*/ int padding,
399                 /*@unused@*/ int element)
400         /*@globals fileSystem, internalState @*/
401         /*@modifies fileSystem, internalState @*/
402 {
403     char * val, * t;
404
405     if (type != RPM_BIN_TYPE) {
406         val = xstrdup(_("(not a blob)"));
407     } else {
408         unsigned char * pkt = (byte *) data;
409         unsigned int pktlen = 0;
410 /*@-boundsread@*/
411         unsigned int v = *pkt;
412 /*@=boundsread@*/
413         pgpTag tag = 0;
414         unsigned int plen;
415         unsigned int hlen = 0;
416
417         if (v & 0x80) {
418             if (v & 0x40) {
419                 tag = (v & 0x3f);
420                 plen = pgpLen(pkt+1, &hlen);
421             } else {
422                 tag = (v >> 2) & 0xf;
423                 plen = (1 << (v & 0x3));
424                 hlen = pgpGrab(pkt+1, plen);
425             }
426         
427             pktlen = 1 + plen + hlen;
428         }
429
430         if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
431             val = xstrdup(_("(not an OpenPGP signature)"));
432         } else {
433             pgpDig dig = pgpNewDig();
434             pgpDigParams sigp = &dig->signature;
435             size_t nb = 0;
436             const char *tempstr;
437
438             (void) pgpPrtPkts(pkt, pktlen, dig, 0);
439
440             val = NULL;
441         again:
442             nb += 100;
443             val = t = xrealloc(val, nb + 1);
444
445 /*@-boundswrite@*/
446             switch (sigp->pubkey_algo) {
447             case PGPPUBKEYALGO_DSA:
448                 t = stpcpy(t, "DSA");
449                 break;
450             case PGPPUBKEYALGO_RSA:
451                 t = stpcpy(t, "RSA");
452                 break;
453             default:
454                 (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
455                 t += strlen(t);
456                 break;
457             }
458             if (t + 5 >= val + nb)
459                 goto again;
460             *t++ = '/';
461             switch (sigp->hash_algo) {
462             case PGPHASHALGO_MD5:
463                 t = stpcpy(t, "MD5");
464                 break;
465             case PGPHASHALGO_SHA1:
466                 t = stpcpy(t, "SHA1");
467                 break;
468             default:
469                 (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
470                 t += strlen(t);
471                 break;
472             }
473             if (t + strlen (", ") + 1 >= val + nb)
474                 goto again;
475
476             t = stpcpy(t, ", ");
477
478             /* this is important if sizeof(int_32) ! sizeof(time_t) */
479             {   time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
480                 struct tm * tstruct = localtime(&dateint);
481                 if (tstruct)
482                     (void) strftime(t, (nb - (t - val)), "%c", tstruct);
483             }
484             t += strlen(t);
485             if (t + strlen (", Key ID ") + 1 >= val + nb)
486                 goto again;
487             t = stpcpy(t, ", Key ID ");
488             tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
489             if (t + strlen (tempstr) > val + nb)
490                 goto again;
491             t = stpcpy(t, tempstr);
492 /*@=boundswrite@*/
493
494             dig = pgpFreeDig(dig);
495         }
496     }
497
498     return val;
499 }
500
501 /**
502  * Format dependency flags for display.
503  * @param type          tag type
504  * @param data          tag value
505  * @param formatPrefix
506  * @param padding
507  * @param element       (unused)
508  * @return              formatted string
509  */
510 static /*@only@*/ char * depflagsFormat(int_32 type, const void * data, 
511                 char * formatPrefix, int padding, /*@unused@*/ int element)
512         /*@modifies formatPrefix @*/
513         /*@requires maxRead(data) >= 0 @*/
514 {
515     char * val;
516     char buf[10];
517     int anint;
518
519     if (type != RPM_INT32_TYPE) {
520         val = xstrdup(_("(not a number)"));
521     } else {
522         anint = *((int_32 *) data);
523         buf[0] = '\0';
524
525 /*@-boundswrite@*/
526         if (anint & RPMSENSE_LESS) 
527             strcat(buf, "<");
528         if (anint & RPMSENSE_GREATER)
529             strcat(buf, ">");
530         if (anint & RPMSENSE_EQUAL)
531             strcat(buf, "=");
532 /*@=boundswrite@*/
533
534         val = xmalloc(5 + padding);
535 /*@-boundswrite@*/
536         strcat(formatPrefix, "s");
537 /*@=boundswrite@*/
538         /*@-formatconst@*/
539         sprintf(val, formatPrefix, buf);
540         /*@=formatconst@*/
541     }
542
543     return val;
544 }
545
546 /**
547  * Retrieve mounted file system paths.
548  * @param h             header
549  * @retval *type        tag type
550  * @retval *data        tag value
551  * @retval *count       no. of data items
552  * @retval *freeData    data-was-malloc'ed indicator
553  * @return              0 on success
554  */
555 static int fsnamesTag( /*@unused@*/ Header h, /*@out@*/ int_32 * type,
556                 /*@out@*/ void ** data, /*@out@*/ int_32 * count,
557                 /*@out@*/ int * freeData)
558         /*@globals fileSystem, internalState @*/
559         /*@modifies *type, *data, *count, *freeData,
560                 fileSystem, internalState @*/
561         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
562                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
563 {
564     const char ** list;
565
566 /*@-boundswrite@*/
567     if (rpmGetFilesystemList(&list, count))
568         return 1;
569 /*@=boundswrite@*/
570
571     if (type) *type = RPM_STRING_ARRAY_TYPE;
572     if (data) *((const char ***) data) = list;
573     if (freeData) *freeData = 0;
574
575     return 0; 
576 }
577
578 /**
579  * Retrieve install prefixes.
580  * @param h             header
581  * @retval *type        tag type
582  * @retval *data        tag value
583  * @retval *count       no. of data items
584  * @retval *freeData    data-was-malloc'ed indicator
585  * @return              0 on success
586  */
587 static int instprefixTag(Header h, /*@null@*/ /*@out@*/ rpmTagType * type,
588                 /*@null@*/ /*@out@*/ const void ** data,
589                 /*@null@*/ /*@out@*/ int_32 * count,
590                 /*@null@*/ /*@out@*/ int * freeData)
591         /*@modifies *type, *data, *freeData @*/
592         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
593                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
594 {
595     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
596     HFD_t hfd = headerFreeData;
597     rpmTagType ipt;
598     char ** array;
599
600     if (hge(h, RPMTAG_INSTALLPREFIX, type, (void **)data, count)) {
601         if (freeData) *freeData = 0;
602         return 0;
603     } else if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &array, count)) {
604         if (type) *type = RPM_STRING_TYPE;
605 /*@-boundsread@*/
606         if (data) *data = xstrdup(array[0]);
607 /*@=boundsread@*/
608         if (freeData) *freeData = 1;
609         array = hfd(array, ipt);
610         return 0;
611     }
612
613     return 1;
614 }
615
616 /**
617  * Retrieve mounted file system space.
618  * @param h             header
619  * @retval *type        tag type
620  * @retval *data        tag value
621  * @retval *count       no. of data items
622  * @retval *freeData    data-was-malloc'ed indicator
623  * @return              0 on success
624  */
625 static int fssizesTag(Header h, /*@out@*/ rpmTagType * type,
626                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
627                 /*@out@*/ int * freeData)
628         /*@globals rpmGlobalMacroContext, h_errno,
629                 fileSystem, internalState @*/
630         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext,
631                 fileSystem, internalState @*/
632         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
633                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
634 {
635     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
636     const char ** filenames;
637     int_32 * filesizes;
638     uint_32 * usages;
639     int numFiles;
640
641     if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &filesizes, &numFiles)) {
642         filesizes = NULL;
643         numFiles = 0;
644         filenames = NULL;
645     } else {
646         rpmfiBuildFNames(h, RPMTAG_BASENAMES, &filenames, &numFiles);
647     }
648
649 /*@-boundswrite@*/
650     if (rpmGetFilesystemList(NULL, count))
651         return 1;
652 /*@=boundswrite@*/
653
654     *type = RPM_INT32_TYPE;
655     *freeData = 1;
656
657     if (filenames == NULL) {
658         usages = xcalloc((*count), sizeof(usages));
659         *data = usages;
660
661         return 0;
662     }
663
664 /*@-boundswrite@*/
665     if (rpmGetFilesystemUsage(filenames, filesizes, numFiles, &usages, 0))      
666         return 1;
667 /*@=boundswrite@*/
668
669     *data = usages;
670
671     filenames = _free(filenames);
672
673     return 0;
674 }
675
676 /**
677  * Retrieve trigger info.
678  * @param h             header
679  * @retval *type        tag type
680  * @retval *data        tag value
681  * @retval *count       no. of data items
682  * @retval *freeData    data-was-malloc'ed indicator
683  * @return              0 on success
684  */
685 static int triggercondsTag(Header h, /*@out@*/ rpmTagType * type,
686                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
687                 /*@out@*/ int * freeData)
688         /*@modifies *type, *data, *count, *freeData @*/
689         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
690                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
691 {
692     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
693     HFD_t hfd = headerFreeData;
694     rpmTagType tnt, tvt, tst;
695     int_32 * indices, * flags;
696     char ** names, ** versions;
697     int numNames, numScripts;
698     char ** conds, ** s;
699     char * item, * flagsStr;
700     char * chptr;
701     int i, j, xx;
702     char buf[5];
703
704     if (!hge(h, RPMTAG_TRIGGERNAME, &tnt, (void **) &names, &numNames)) {
705         *freeData = 0;
706         return 0;
707     }
708
709     xx = hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, NULL);
710     xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
711     xx = hge(h, RPMTAG_TRIGGERVERSION, &tvt, (void **) &versions, NULL);
712     xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
713     s = hfd(s, tst);
714
715     *freeData = 1;
716     *data = conds = xmalloc(sizeof(*conds) * numScripts);
717     *count = numScripts;
718     *type = RPM_STRING_ARRAY_TYPE;
719 /*@-bounds@*/
720     for (i = 0; i < numScripts; i++) {
721         chptr = xstrdup("");
722
723         for (j = 0; j < numNames; j++) {
724             if (indices[j] != i)
725                 /*@innercontinue@*/ continue;
726
727             item = xmalloc(strlen(names[j]) + strlen(versions[j]) + 20);
728             if (flags[j] & RPMSENSE_SENSEMASK) {
729                 buf[0] = '%', buf[1] = '\0';
730                 flagsStr = depflagsFormat(RPM_INT32_TYPE, flags, buf, 0, j);
731                 sprintf(item, "%s %s %s", names[j], flagsStr, versions[j]);
732                 flagsStr = _free(flagsStr);
733             } else {
734                 strcpy(item, names[j]);
735             }
736
737             chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
738             if (*chptr != '\0') strcat(chptr, ", ");
739             strcat(chptr, item);
740             item = _free(item);
741         }
742
743         conds[i] = chptr;
744     }
745 /*@=bounds@*/
746
747     names = hfd(names, tnt);
748     versions = hfd(versions, tvt);
749
750     return 0;
751 }
752
753 /**
754  * Retrieve trigger type info.
755  * @param h             header
756  * @retval *type        tag type
757  * @retval *data        tag value
758  * @retval *count       no. of data items
759  * @retval *freeData    data-was-malloc'ed indicator
760  * @return              0 on success
761  */
762 static int triggertypeTag(Header h, /*@out@*/ rpmTagType * type,
763                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
764                 /*@out@*/ int * freeData)
765         /*@modifies *type, *data, *count, *freeData @*/
766         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
767                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
768 {
769     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
770     HFD_t hfd = headerFreeData;
771     rpmTagType tst;
772     int_32 * indices, * flags;
773     const char ** conds;
774     const char ** s;
775     int i, j, xx;
776     int numScripts, numNames;
777
778     if (!hge(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &indices, &numNames)) {
779         *freeData = 0;
780         return 1;
781     }
782
783     xx = hge(h, RPMTAG_TRIGGERFLAGS, NULL, (void **) &flags, NULL);
784     xx = hge(h, RPMTAG_TRIGGERSCRIPTS, &tst, (void **) &s, &numScripts);
785     s = hfd(s, tst);
786
787     *freeData = 1;
788     *data = conds = xmalloc(sizeof(*conds) * numScripts);
789     *count = numScripts;
790     *type = RPM_STRING_ARRAY_TYPE;
791 /*@-bounds@*/
792     for (i = 0; i < numScripts; i++) {
793         for (j = 0; j < numNames; j++) {
794             if (indices[j] != i)
795                 /*@innercontinue@*/ continue;
796
797             if (flags[j] & RPMSENSE_TRIGGERPREIN)
798                 conds[i] = xstrdup("prein");
799             else if (flags[j] & RPMSENSE_TRIGGERIN)
800                 conds[i] = xstrdup("in");
801             else if (flags[j] & RPMSENSE_TRIGGERUN)
802                 conds[i] = xstrdup("un");
803             else if (flags[j] & RPMSENSE_TRIGGERPOSTUN)
804                 conds[i] = xstrdup("postun");
805             else
806                 conds[i] = xstrdup("");
807             /*@innerbreak@*/ break;
808         }
809     }
810 /*@=bounds@*/
811
812     return 0;
813 }
814
815 /**
816  * Retrieve file paths.
817  * @param h             header
818  * @retval *type        tag type
819  * @retval *data        tag value
820  * @retval *count       no. of data items
821  * @retval *freeData    data-was-malloc'ed indicator
822  * @return              0 on success
823  */
824 static int filenamesTag(Header h, /*@out@*/ rpmTagType * type,
825                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
826                 /*@out@*/ int * freeData)
827         /*@modifies *type, *data, *count, *freeData @*/
828         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
829                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
830 {
831     *type = RPM_STRING_ARRAY_TYPE;
832     rpmfiBuildFNames(h, RPMTAG_BASENAMES, (const char ***) data, count);
833     *freeData = 1;
834     return 0; 
835 }
836
837 /**
838  * Retrieve file classes.
839  * @param h             header
840  * @retval *type        tag type
841  * @retval *data        tag value
842  * @retval *count       no. of data items
843  * @retval *freeData    data-was-malloc'ed indicator
844  * @return              0 on success
845  */
846 static int fileclassTag(Header h, /*@out@*/ rpmTagType * type,
847                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
848                 /*@out@*/ int * freeData)
849         /*@globals rpmGlobalMacroContext, h_errno, fileSystem @*/
850         /*@modifies h, *type, *data, *count, *freeData,
851                 rpmGlobalMacroContext, fileSystem @*/
852         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
853                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
854 {
855     *type = RPM_STRING_ARRAY_TYPE;
856     rpmfiBuildFClasses(h, (const char ***) data, count);
857     *freeData = 1;
858     return 0; 
859 }
860
861 /**
862  * Retrieve file provides.
863  * @param h             header
864  * @retval *type        tag type
865  * @retval *data        tag value
866  * @retval *count       no. of data items
867  * @retval *freeData    data-was-malloc'ed indicator
868  * @return              0 on success
869  */
870 static int fileprovideTag(Header h, /*@out@*/ rpmTagType * type,
871                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
872                 /*@out@*/ int * freeData)
873         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
874         /*@modifies h, *type, *data, *count, *freeData,
875                 rpmGlobalMacroContext, fileSystem, internalState @*/
876         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
877                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
878 {
879     *type = RPM_STRING_ARRAY_TYPE;
880     rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, (const char ***) data, count);
881     *freeData = 1;
882     return 0; 
883 }
884
885 /**
886  * Retrieve file requires.
887  * @param h             header
888  * @retval *type        tag type
889  * @retval *data        tag value
890  * @retval *count       no. of data items
891  * @retval *freeData    data-was-malloc'ed indicator
892  * @return              0 on success
893  */
894 static int filerequireTag(Header h, /*@out@*/ rpmTagType * type,
895                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
896                 /*@out@*/ int * freeData)
897         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
898         /*@modifies h, *type, *data, *count, *freeData,
899                 rpmGlobalMacroContext, fileSystem, internalState @*/
900         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
901                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
902 {
903     *type = RPM_STRING_ARRAY_TYPE;
904     rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, (const char ***) data, count);
905     *freeData = 1;
906     return 0; 
907 }
908
909 /* I18N look aside diversions */
910
911 #if defined(ENABLE_NLS)
912 /*@-exportlocal -exportheadervar@*/
913 /*@unchecked@*/
914 extern int _nl_msg_cat_cntr;    /* XXX GNU gettext voodoo */
915 /*@=exportlocal =exportheadervar@*/
916 #endif
917 /*@observer@*/ /*@unchecked@*/
918 static const char * language = "LANGUAGE";
919
920 /*@observer@*/ /*@unchecked@*/
921 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
922
923 /**
924  * Retrieve i18n text.
925  * @param h             header
926  * @param tag           tag
927  * @retval *type        tag type
928  * @retval *data        tag value
929  * @retval *count       no. of data items
930  * @retval *freeData    data-was-malloc'ed indicator
931  * @return              0 on success
932  */
933 static int i18nTag(Header h, int_32 tag, /*@out@*/ rpmTagType * type,
934                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
935                 /*@out@*/ int * freeData)
936         /*@globals rpmGlobalMacroContext, h_errno @*/
937         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
938         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
939                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
940 {
941     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
942     char * dstring = rpmExpand(_macro_i18ndomains, NULL);
943     int rc;
944
945     *type = RPM_STRING_TYPE;
946     *data = NULL;
947     *count = 0;
948     *freeData = 0;
949
950     if (dstring && *dstring) {
951         char *domain, *de;
952         const char * langval;
953         const char * msgkey;
954         const char * msgid;
955
956         {   const char * tn = tagName(tag);
957             const char * n;
958             char * mk;
959             size_t nb = sizeof("()");
960             int xx;
961             xx = headerNVR(h, &n, NULL, NULL);
962             if (tn)     nb += strlen(tn);
963             if (n)      nb += strlen(n);
964             mk = alloca(nb);
965             sprintf(mk, "%s(%s)", n, tn);
966             msgkey = mk;
967         }
968
969         /* change to en_US for msgkey -> msgid resolution */
970         langval = getenv(language);
971         (void) setenv(language, "en_US", 1);
972 #if defined(ENABLE_NLS)
973 /*@i@*/ ++_nl_msg_cat_cntr;
974 #endif
975
976         msgid = NULL;
977         /*@-branchstate@*/
978         for (domain = dstring; domain != NULL; domain = de) {
979             de = strchr(domain, ':');
980             if (de) *de++ = '\0';
981             msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/;
982             if (msgid != msgkey) break;
983         }
984         /*@=branchstate@*/
985
986         /* restore previous environment for msgid -> msgstr resolution */
987         if (langval)
988             (void) setenv(language, langval, 1);
989         else
990             unsetenv(language);
991 #if defined(ENABLE_NLS)
992 /*@i@*/ ++_nl_msg_cat_cntr;
993 #endif
994
995         if (domain && msgid) {
996             *data = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/;
997             *data = xstrdup(*data);     /* XXX xstrdup has side effects. */
998             *count = 1;
999             *freeData = 1;
1000         }
1001         dstring = _free(dstring);
1002         if (*data)
1003             return 0;
1004     }
1005
1006     dstring = _free(dstring);
1007
1008     rc = hge(h, tag, type, (void **)data, count);
1009
1010     if (rc && (*data) != NULL) {
1011         *data = xstrdup(*data);
1012         *freeData = 1;
1013         return 0;
1014     }
1015
1016     *freeData = 0;
1017     *data = NULL;
1018     *count = 0;
1019     return 1;
1020 }
1021
1022 /**
1023  * Retrieve summary text.
1024  * @param h             header
1025  * @retval *type        tag type
1026  * @retval *data        tag value
1027  * @retval *count       no. of data items
1028  * @retval *freeData    data-was-malloc'ed indicator
1029  * @return              0 on success
1030  */
1031 static int summaryTag(Header h, /*@out@*/ rpmTagType * type,
1032                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
1033                 /*@out@*/ int * freeData)
1034         /*@globals rpmGlobalMacroContext, h_errno @*/
1035         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
1036         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
1037                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
1038 {
1039     return i18nTag(h, RPMTAG_SUMMARY, type, data, count, freeData);
1040 }
1041
1042 /**
1043  * Retrieve description text.
1044  * @param h             header
1045  * @retval *type        tag type
1046  * @retval *data        tag value
1047  * @retval *count       no. of data items
1048  * @retval *freeData    data-was-malloc'ed indicator
1049  * @return              0 on success
1050  */
1051 static int descriptionTag(Header h, /*@out@*/ rpmTagType * type,
1052                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
1053                 /*@out@*/ int * freeData)
1054         /*@globals rpmGlobalMacroContext, h_errno @*/
1055         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
1056         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
1057                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
1058 {
1059     return i18nTag(h, RPMTAG_DESCRIPTION, type, data, count, freeData);
1060 }
1061
1062 /**
1063  * Retrieve group text.
1064  * @param h             header
1065  * @retval *type        tag type
1066  * @retval *data        tag value
1067  * @retval *count       no. of data items
1068  * @retval *freeData    data-was-malloc'ed indicator
1069  * @return              0 on success
1070  */
1071 static int groupTag(Header h, /*@out@*/ rpmTagType * type,
1072                 /*@out@*/ const void ** data, /*@out@*/ int_32 * count,
1073                 /*@out@*/ int * freeData)
1074         /*@globals rpmGlobalMacroContext, h_errno @*/
1075         /*@modifies *type, *data, *count, *freeData, rpmGlobalMacroContext @*/
1076         /*@requires maxSet(type) >= 0 /\ maxSet(data) >= 0
1077                 /\ maxSet(count) >= 0 /\ maxSet(freeData) >= 0 @*/
1078 {
1079     return i18nTag(h, RPMTAG_GROUP, type, data, count, freeData);
1080 }
1081
1082 /*@-type@*/ /* FIX: cast? */
1083 const struct headerSprintfExtension_s rpmHeaderFormats[] = {
1084     { HEADER_EXT_TAG, "RPMTAG_GROUP",           { groupTag } },
1085     { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",     { descriptionTag } },
1086     { HEADER_EXT_TAG, "RPMTAG_SUMMARY",         { summaryTag } },
1087     { HEADER_EXT_TAG, "RPMTAG_FILECLASS",       { fileclassTag } },
1088     { HEADER_EXT_TAG, "RPMTAG_FILENAMES",       { filenamesTag } },
1089     { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE",     { fileprovideTag } },
1090     { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE",     { filerequireTag } },
1091     { HEADER_EXT_TAG, "RPMTAG_FSNAMES",         { fsnamesTag } },
1092     { HEADER_EXT_TAG, "RPMTAG_FSSIZES",         { fssizesTag } },
1093     { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",   { instprefixTag } },
1094     { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",    { triggercondsTag } },
1095     { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",     { triggertypeTag } },
1096     { HEADER_EXT_FORMAT, "armor",               { armorFormat } },
1097     { HEADER_EXT_FORMAT, "base64",              { base64Format } },
1098     { HEADER_EXT_FORMAT, "pgpsig",              { pgpsigFormat } },
1099     { HEADER_EXT_FORMAT, "depflags",            { depflagsFormat } },
1100     { HEADER_EXT_FORMAT, "fflags",              { fflagsFormat } },
1101     { HEADER_EXT_FORMAT, "perms",               { permsFormat } },
1102     { HEADER_EXT_FORMAT, "permissions",         { permsFormat } },
1103     { HEADER_EXT_FORMAT, "triggertype",         { triggertypeFormat } },
1104     { HEADER_EXT_FORMAT, "xml",                 { xmlFormat } },
1105     { HEADER_EXT_MORE, NULL,            { (void *) headerDefaultFormats } }
1106 } ;
1107 /*@=type@*/