rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

hdrfmt.c
Go to the documentation of this file.
1
5 #include "system.h"
6
7 /* XXX todo: these should likely be in "system.h" */
8 #if defined(HAVE_ICONV)
9 #include <iconv.h>
10 #if defined(__LCLINT__)
11 /*@-declundef -exportheader -incondefs @*/
12 extern /*@only@*/ iconv_t iconv_open(const char *__tocode, const char *__fromcode)
13 /*@*/;
14
15 extern size_t iconv(iconv_t __cd, /*@null@*/ char ** __inbuf,
16 /*@out@*/ size_t * __inbytesleft,
17 /*@out@*/ char ** __outbuf,
18 /*@out@*/ size_t * __outbytesleft)
19 /*@modifies __cd,
20 *__inbuf, *__inbytesleft, *__outbuf, *__outbytesleft @*/;
21
22 extern int iconv_close(/*@only@*/ iconv_t __cd)
23 /*@modifies __cd @*/;
24 /*@=declundef =exportheader =incondefs @*/
25 #endif
26 #endif
27
28 #if defined(HAVE_LANGINFO_H)
29 #include <langinfo.h>
30 #if defined(__LCLINT__)
31 /*@-declundef -exportheader -incondefs @*/
32 extern char *nl_langinfo (nl_item __item)
33 /*@*/;
34 /*@=declundef =exportheader =incondefs @*/
35 #endif
36 #endif
37
38 #define _MIRE_INTERNAL
39 #include "rpmio_internal.h"
40 #include <rpmbc.h> /* XXX beecrypt base64 */
41 #include <rpmcb.h> /* XXX rpmIsVerbose */
42 #include <rpmmacro.h> /* XXX for %_i18ndomains */
43 #include <rpmuuid.h>
44 #include <argv.h>
45 #include <ugid.h>
46
47 #define _RPMTAG_INTERNAL
48 #include <rpmtag.h>
49 #define _RPMEVR_INTERNAL
50 #include <rpmevr.h> /* XXX RPMSENSE_FOO */
51 #include <rpmns.h>
52 #include <rpmdb.h>
53
54 #include <rpmtypes.h> /* XXX rpmfi */
55 #include "misc.h" /* XXX rpmMkdirPath */
56 #include <rpmfi.h> /* XXX RPMFILE_FOO */
57
58 #include "legacy.h"
59 #include "misc.h"
60
61 #include "debug.h"
62
63 /*@unchecked@*/
64 int _hdrqf_debug;
65
66 /*@access pgpDig @*/
67 /*@access pgpDigParams @*/
68 /*@access headerSprintfExtension @*/
69 /*@access headerTagTableEntry @*/
70 /*@access Header @*/ /* XXX debugging msgs */
71 /*@access EVR_t @*/
72 /*@access rpmdb @*/ /* XXX for casts */
73 /*@access miRE @*/
74
82 static char * intFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
83 /*@null@*/ const char *fmt)
84 /*@*/
85 {
86 rpmuint32_t ix = (he->ix > 0 ? he->ix : 0);
87 rpmuint64_t ival = 0;
88 const char * istr = NULL;
89 char * b;
90 size_t nb = 0;
91 int xx;
92
93 if (fmt == NULL || *fmt == '\0')
94 fmt = "d";
95
96 switch (he->t) {
97 default:
98 return xstrdup(_("(not a number)"));
99 /*@notreached@*/ break;
100 case RPM_UINT8_TYPE:
101 ival = (rpmuint64_t) he->p.ui8p[ix];
102 break;
103 case RPM_UINT16_TYPE:
104 ival = (rpmuint64_t) he->p.ui16p[ix];
105 break;
106 case RPM_UINT32_TYPE:
107 ival = (rpmuint64_t) he->p.ui32p[ix];
108 break;
109 case RPM_UINT64_TYPE:
110 ival = he->p.ui64p[ix];
111 break;
112 case RPM_STRING_TYPE:
113 istr = he->p.str;
114 break;
115 case RPM_STRING_ARRAY_TYPE:
116 istr = he->p.argv[ix];
117 break;
118 case RPM_BIN_TYPE:
119 { static char hex[] = "0123456789abcdef";
120 const char * s = he->p.str;
121 rpmTagCount c = he->c;
122 char * t;
123
124 nb = 2 * c + 1;
125 t = b = alloca(nb+1);
126 while (c-- > 0) {
127 unsigned i;
128 i = (unsigned) *s++;
129 *t++ = hex[ (i >> 4) & 0xf ];
130 *t++ = hex[ (i ) & 0xf ];
131 }
132 *t = '\0';
133 } break;
134 }
135
136 if (istr) { /* string */
137 b = (char *)istr; /* NOCAST */
138 } else
139 if (nb == 0) { /* number */
140 char myfmt[] = "%llX";
141 myfmt[3] = ((fmt != NULL && *fmt != '\0') ? *fmt : 'd');
142 nb = 64;
143 b = alloca(nb);
144 /*@-formatconst@*/
145 xx = snprintf(b, nb, myfmt, ival);
146 /*@=formatconst@*/
147 b[nb-1] = '\0';
148 }
149
150 return xstrdup(b);
151 }
152
159 static char * octFormat(HE_t he, /*@null@*/ const char ** av)
160 /*@*/
161 {
162 return intFormat(he, av, "o");
163 }
164
171 static char * hexFormat(HE_t he, /*@null@*/ const char ** av)
172 /*@*/
173 {
174 return intFormat(he, av, "x");
175 }
176
183 static char * decFormat(HE_t he, /*@null@*/ const char ** av)
184 /*@*/
185 {
186 return intFormat(he, av, "d");
187 }
188
196 static char * realDateFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
197 const char * strftimeFormat)
198 /*@*/
199 {
200 char * val;
201
202 if (he->t != RPM_UINT64_TYPE) {
203 val = xstrdup(_("(not a number)"));
204 } else {
205 struct tm * tstruct;
206 char buf[50];
207
208 /* this is important if sizeof(rpmuint64_t) ! sizeof(time_t) */
209 { time_t dateint = he->p.ui64p[0];
210 tstruct = localtime(&dateint);
211 }
212 buf[0] = '\0';
213 if (tstruct)
214 (void) strftime(buf, sizeof(buf) - 1, strftimeFormat, tstruct);
215 buf[sizeof(buf) - 1] = '\0';
216 val = xstrdup(buf);
217 }
218
219 return val;
220 }
221
228 static char * dateFormat(HE_t he, /*@null@*/ const char ** av)
229 /*@*/
230 {
231 return realDateFormat(he, av, _("%c"));
232 }
233
240 static char * dayFormat(HE_t he, /*@null@*/ const char ** av)
241 /*@*/
242 {
243 return realDateFormat(he, av, _("%a %b %d %Y"));
244 }
245
252 static char * shescapeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
253 /*@*/
254 {
255 char * val;
256 size_t nb;
257 int xx;
258
259 /* XXX one of these integer types is unnecessary. */
260 if (he->t == RPM_UINT32_TYPE) {
261 nb = 20;
262 val = xmalloc(nb);
263 xx = snprintf(val, nb, "%u", (unsigned) he->p.ui32p[0]);
264 val[nb-1] = '\0';
265 } else if (he->t == RPM_UINT64_TYPE) {
266 nb = 40;
267 val = xmalloc(40);
268 /*@-duplicatequals@*/
269 xx = snprintf(val, nb, "%llu", (unsigned long long)he->p.ui64p[0]);
270 /*@=duplicatequals@*/
271 val[nb-1] = '\0';
272 } else if (he->t == RPM_STRING_TYPE) {
273 const char * s = he->p.str;
274 char * t;
275 int c;
276
277 nb = 0;
278 for (s = he->p.str; (c = (int)*s) != 0; s++) {
279 nb++;
280 if (c == (int)'\'')
281 nb += 3;
282 }
283 nb += 3;
284 t = val = xmalloc(nb);
285 *t++ = '\'';
286 for (s = he->p.str; (c = (int)*s) != 0; s++) {
287 if (c == (int)'\'') {
288 *t++ = '\'';
289 *t++ = '\\';
290 *t++ = '\'';
291 }
292 *t++ = (char) c;
293 }
294 *t++ = '\'';
295 *t = '\0';
296 } else
297 val = xstrdup(_("invalid type"));
298
299 return val;
300 }
301
302 static struct headerSprintfExtension_s _headerDefaultFormats[] = {
303 { HEADER_EXT_FORMAT, "octal",
304 { .fmtFunction = octFormat } },
305 { HEADER_EXT_FORMAT, "oct",
306 { .fmtFunction = octFormat } },
307 { HEADER_EXT_FORMAT, "hex",
308 { .fmtFunction = hexFormat } },
309 { HEADER_EXT_FORMAT, "decimal",
310 { .fmtFunction = decFormat } },
311 { HEADER_EXT_FORMAT, "dec",
312 { .fmtFunction = decFormat } },
313 { HEADER_EXT_FORMAT, "date",
314 { .fmtFunction = dateFormat } },
315 { HEADER_EXT_FORMAT, "day",
316 { .fmtFunction = dayFormat } },
317 { HEADER_EXT_FORMAT, "shescape",
318 { .fmtFunction = shescapeFormat } },
319 { HEADER_EXT_LAST, NULL, { NULL } }
320 };
321
322 headerSprintfExtension headerDefaultFormats = &_headerDefaultFormats[0];
323
324 /* XXX FIXME: static for now, refactor from manifest.c later. */
325 static char * rpmPermsString(int mode)
326 /*@*/
327 {
328 char *perms = xstrdup("----------");
329
330 if (S_ISREG(mode))
331 perms[0] = '-';
332 else if (S_ISDIR(mode))
333 perms[0] = 'd';
334 else if (S_ISLNK(mode))
335 perms[0] = 'l';
336 else if (S_ISFIFO(mode))
337 perms[0] = 'p';
338 /*@-unrecog@*/
339 else if (S_ISSOCK(mode))
340 perms[0] = 's';
341 /*@=unrecog@*/
342 else if (S_ISCHR(mode))
343 perms[0] = 'c';
344 else if (S_ISBLK(mode))
345 perms[0] = 'b';
346 else
347 perms[0] = '?';
348
349 if (mode & S_IRUSR) perms[1] = 'r';
350 if (mode & S_IWUSR) perms[2] = 'w';
351 if (mode & S_IXUSR) perms[3] = 'x';
352
353 if (mode & S_IRGRP) perms[4] = 'r';
354 if (mode & S_IWGRP) perms[5] = 'w';
355 if (mode & S_IXGRP) perms[6] = 'x';
356
357 if (mode & S_IROTH) perms[7] = 'r';
358 if (mode & S_IWOTH) perms[8] = 'w';
359 if (mode & S_IXOTH) perms[9] = 'x';
360
361 if (mode & S_ISUID)
362 perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
363
364 if (mode & S_ISGID)
365 perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
366
367 if (mode & S_ISVTX)
368 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
369
370 return perms;
371 }
372
379 static /*@only@*/ char * triggertypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
380 /*@*/
381 {
382 int ix = (he->ix > 0 ? he->ix : 0);
383 char * val;
384
385 assert(ix == 0);
386 if (he->t != RPM_UINT64_TYPE)
387 val = xstrdup(_("(invalid type)"));
388 else {
389 rpmuint64_t anint = he->p.ui64p[ix];
390 if (anint & RPMSENSE_TRIGGERPREIN)
391 val = xstrdup("prein");
392 else if (anint & RPMSENSE_TRIGGERIN)
393 val = xstrdup("in");
394 else if (anint & RPMSENSE_TRIGGERUN)
395 val = xstrdup("un");
396 else if (anint & RPMSENSE_TRIGGERPOSTUN)
397 val = xstrdup("postun");
398 else
399 val = xstrdup("");
400 }
401 return val;
402 }
403
410 static /*@only@*/ char * permsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
411 /*@*/
412 {
413 int ix = (he->ix > 0 ? he->ix : 0);
414 char * val;
415
416 assert(ix == 0);
417 if (he->t != RPM_UINT64_TYPE) {
418 val = xstrdup(_("(invalid type)"));
419 } else {
420 rpmuint64_t anint = he->p.ui64p[0];
421 val = rpmPermsString((int)anint);
422 }
423
424 return val;
425 }
426
433 static /*@only@*/ char * fflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
434 /*@*/
435 {
436 int ix = (he->ix >= 0 ? he->ix : 0);
437 char * val;
438
439 assert(ix == 0);
440 if (he->t != RPM_UINT64_TYPE) {
441 val = xstrdup(_("(invalid type)"));
442 } else {
443 char buf[15];
444 rpmuint64_t anint = he->p.ui64p[ix];
445 buf[0] = '\0';
446 if (anint & RPMFILE_DOC)
447 strcat(buf, "d");
448 if (anint & RPMFILE_CONFIG)
449 strcat(buf, "c");
450 if (anint & RPMFILE_SPECFILE)
451 strcat(buf, "s");
452 if (anint & RPMFILE_MISSINGOK)
453 strcat(buf, "m");
454 if (anint & RPMFILE_NOREPLACE)
455 strcat(buf, "n");
456 if (anint & RPMFILE_GHOST)
457 strcat(buf, "g");
458 if (anint & RPMFILE_LICENSE)
459 strcat(buf, "l");
460 if (anint & RPMFILE_README)
461 strcat(buf, "r");
462 val = xstrdup(buf);
463 }
464
465 return val;
466 }
467
475 static /*@only@*/ char * armorFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
476 /*@*/
477 {
478 int ix = (he->ix > 0 ? he->ix : 0);
479 const char * enc;
480 const unsigned char * s;
481 size_t ns;
482 rpmuint8_t atype;
483 char * val;
484
485 assert(ix == 0);
486 switch (he->t) {
487 case RPM_BIN_TYPE:
488 s = (unsigned char *) he->p.ui8p;
489 ns = he->c;
490 atype = (rpmuint8_t)PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
491 break;
492 case RPM_STRING_TYPE:
493 case RPM_STRING_ARRAY_TYPE:
494 enc = he->p.str;
495 s = NULL;
496 ns = 0;
497 /*@-moduncon@*/
498 if (b64decode(enc, (void **)&s, &ns))
499 return xstrdup(_("(not base64)"));
500 /*@=moduncon@*/
501 atype = (rpmuint8_t)PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
502 break;
503 case RPM_UINT8_TYPE:
504 case RPM_UINT16_TYPE:
505 case RPM_UINT32_TYPE:
506 case RPM_UINT64_TYPE:
507 case RPM_I18NSTRING_TYPE:
508 default:
509 return xstrdup(_("(invalid type)"));
510 /*@notreached@*/ break;
511 }
512
513 val = pgpArmorWrap(atype, s, ns);
514 if (atype == (rpmuint8_t)PGPARMOR_PUBKEY)
515 s = _free(s);
516 return val;
517 }
518
526 static /*@only@*/ char * base64Format(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
527 /*@*/
528 {
529 int ix = (he->ix > 0 ? he->ix : 0);
530 char * val;
531 const char * enc;
532 char * t;
533 int lc;
534 size_t ns;
535 size_t nt;
536
537 assert(ix == 0);
538 switch(he->t) {
539 default:
540 val = xstrdup(_("(invalid type :base64)"));
541 goto exit;
542 /*@notreached@*/ break;
543 case RPM_UINT64_TYPE:
544 ns = sizeof(he->p.ui64p[0]);
545 break;
546 case RPM_STRING_TYPE:
547 ns = strlen(he->p.str);
548 break;
549 case RPM_BIN_TYPE:
550 ns = he->c;
551 break;
552 }
553
554 nt = ((ns + 2) / 3) * 4;
555
556 /*@-globs@*/
557 /* Add additional bytes necessary for eol string(s). */
558 if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
559 lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
560 if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
561 ++lc;
562 nt += lc * strlen(b64encode_eolstr);
563 }
564 /*@=globs@*/
565
566 val = t = xcalloc(1, nt + 1);
567 *t = '\0';
568
569 /* XXX b64encode accesses uninitialized memory. */
570 { unsigned char * _data = xcalloc(1, ns+1);
571 assert(he->p.ptr != NULL);
572 memcpy(_data, he->p.ptr, ns);
573 /*@-moduncon@*/
574 if ((enc = b64encode(_data, ns)) != NULL) {
575 t = stpcpy(t, enc);
576 enc = _free(enc);
577 }
578 /*@=moduncon@*/
579 _data = _free(_data);
580 }
581
582 exit:
583 /*@-globstate@*/ /* b64encode_eolstr annotation */
584 return val;
585 /*@=globstate@*/
586 }
587
593 static size_t xmlstrlen(const char * s)
594 /*@*/
595 {
596 size_t len = 0;
597 int c;
598
599 while ((c = (int) *s++) != (int) '\0') {
600 switch (c) {
601 case '<':
602 case '>': len += sizeof("&lt;") - 1; /*@switchbreak@*/ break;
603 case '&': len += sizeof("&amp;") - 1; /*@switchbreak@*/ break;
604 default: len += 1; /*@switchbreak@*/ break;
605 }
606 }
607 return len;
608 }
609
616 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
617 /*@modifies t @*/
618 {
619 char * te = t;
620 int c;
621
622 while ((c = (int) *s++) != (int) '\0') {
623 switch (c) {
624 case '<': te = stpcpy(te, "&lt;"); /*@switchbreak@*/ break;
625 case '>': te = stpcpy(te, "&gt;"); /*@switchbreak@*/ break;
626 case '&': te = stpcpy(te, "&amp;"); /*@switchbreak@*/ break;
627 default: *te++ = (char) c; /*@switchbreak@*/ break;
628 }
629 }
630 *te = '\0';
631 return t;
632 }
633
634 static /*@only@*/ /*@null@*/ char *
635 strdup_locale_convert (/*@null@*/ const char * buffer,
636 /*@null@*/ const char * tocode)
637 /*@*/
638 {
639 char *dest_str;
640 #if defined(HAVE_ICONV)
641 char *fromcode = NULL;
642 iconv_t fd;
643
644 if (buffer == NULL)
645 return NULL;
646
647 if (tocode == NULL)
648 tocode = "UTF-8";
649
650 #ifdef HAVE_LANGINFO_H
651 fromcode = nl_langinfo (CODESET);
652 #endif
653
654 if (fromcode != NULL && strcmp(tocode, fromcode) != 0
655 && (fd = iconv_open(tocode, fromcode)) != (iconv_t)-1)
656 {
657 const char *pin = buffer;
658 char *pout = NULL;
659 size_t ib, ob, dest_size;
660 int done;
661 int is_error;
662 size_t err;
663 const char *shift_pin = NULL;
664 int xx;
665
666 err = iconv(fd, NULL, &ib, &pout, &ob);
667 dest_size = ob = ib = strlen(buffer);
668 dest_str = pout = malloc((dest_size + 1) * sizeof(*dest_str));
669 if (dest_str)
670 *dest_str = '\0';
671 done = is_error = 0;
672 if (pout != NULL)
673 while (done == 0 && is_error == 0) {
674 err = iconv(fd, (char **)&pin, &ib, &pout, &ob);
675
676 if (err == (size_t)-1) {
677 switch (errno) {
678 case EINVAL:
679 done = 1;
680 /*@switchbreak@*/ break;
681 case E2BIG:
682 { size_t used = (size_t)(pout - dest_str);
683 dest_size *= 2;
684 dest_str = realloc(dest_str, (dest_size + 1) * sizeof(*dest_str));
685 if (dest_str == NULL) {
686 is_error = 1;
687 continue;
688 }
689 pout = dest_str + used;
690 ob = dest_size - used;
691 } /*@switchbreak@*/ break;
692 case EILSEQ:
693 is_error = 1;
694 /*@switchbreak@*/ break;
695 default:
696 is_error = 1;
697 /*@switchbreak@*/ break;
698 }
699 } else {
700 if (shift_pin == NULL) {
701 shift_pin = pin;
702 pin = NULL;
703 ib = 0;
704 } else {
705 done = 1;
706 }
707 }
708 }
709 xx = iconv_close(fd);
710 if (pout)
711 *pout = '\0';
712 if (dest_str != NULL)
713 dest_str = xstrdup(dest_str);
714 } else
715 #endif
716 {
717 dest_str = xstrdup((buffer ? buffer : ""));
718 }
719
720 return dest_str;
721 }
722
729 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av)
730 /*@*/
731 {
732 int ix = (he->ix > 0 ? he->ix : 0);
733 char * val;
734
735 assert(ix == 0);
736 if (he->t != RPM_STRING_TYPE) {
737 val = xstrdup(_("(not a string)"));
738 } else {
739 const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
740 size_t nb;
741 char * t;
742
743 if (s == NULL) {
744 /* XXX better error msg? */
745 val = xstrdup(_("(not a string)"));
746 goto exit;
747 }
748 nb = xmlstrlen(s);
749 val = t = xcalloc(1, nb + 1);
750 t = xmlstrcpy(t, s); t += strlen(t);
751 *t = '\0';
752 s = _free(s);
753 }
754
755 exit:
756 return val;
757 }
758
765 static /*@only@*/ char * iconvFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
766 /*@*/
767 {
768 int ix = (he->ix > 0 ? he->ix : 0);
769 char * val = NULL;
770
771 assert(ix == 0);
772 if (he->t == RPM_STRING_TYPE)
773 val = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
774 if (val == NULL)
775 val = xstrdup(_("(not a string)"));
776
777 return val;
778 }
779
786 static /*@only@*/ char * xmlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
787 /*@*/
788 {
789 int ix = (he->ix > 0 ? he->ix : 0);
790 const char * xtag = NULL;
791 size_t nb;
792 char * val;
793 const char * s = NULL;
794 char * t, * te;
795 rpmuint64_t anint = 0;
796 int freeit = 0;
797 int xx;
798
799 assert(ix == 0);
800 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
801 switch (he->t) {
802 case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
803 s = he->p.argv[ix];
804 xtag = "string";
805 /* XXX Force utf8 strings. */
806 s = xstrdup(s);
807 s = xstrtolocale(s);
808 freeit = 1;
809 break;
810 case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
811 case RPM_STRING_TYPE:
812 s = he->p.str;
813 xtag = "string";
814 /* XXX Force utf8 strings. */
815 s = xstrdup(s);
816 s = xstrtolocale(s);
817 freeit = 1;
818 break;
819 case RPM_BIN_TYPE:
820 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */
821 { int cpl = b64encode_chars_per_line;
822 b64encode_chars_per_line = 0;
823 /*@-formatconst@*/
824 s = base64Format(he, NULL);
825 /*@=formatconst@*/
826 b64encode_chars_per_line = cpl;
827 xtag = "base64";
828 freeit = 1;
829 } break;
830 /*@=globs =mods@*/
831 case RPM_UINT8_TYPE:
832 anint = (rpmuint64_t)he->p.ui8p[ix];
833 break;
834 case RPM_UINT16_TYPE:
835 anint = (rpmuint64_t)he->p.ui16p[ix];
836 break;
837 case RPM_UINT32_TYPE:
838 anint = (rpmuint64_t)he->p.ui32p[ix];
839 break;
840 case RPM_UINT64_TYPE:
841 anint = he->p.ui64p[ix];
842 break;
843 default:
844 return xstrdup(_("(invalid xml type)"));
845 /*@notreached@*/ break;
846 }
847
848 if (s == NULL) {
849 int tlen = 64;
850 t = memset(alloca(tlen+1), 0, tlen+1);
851 /*@-duplicatequals@*/
852 if (anint != 0)
853 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
854 /*@=duplicatequals@*/
855 s = t;
856 xtag = "integer";
857 }
858
859 nb = xmlstrlen(s);
860 if (nb == 0) {
861 nb += strlen(xtag) + sizeof("\t</>");
862 te = t = alloca(nb);
863 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
864 } else {
865 nb += 2 * strlen(xtag) + sizeof("\t<></>");
866 te = t = alloca(nb);
867 te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
868 te = xmlstrcpy(te, s);
869 te += strlen(te);
870 te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
871 }
872
873 if (freeit)
874 s = _free(s);
875
876 val = xstrdup(t);
877
878 return val;
879 }
880
887 static size_t yamlstrlen(const char * s, int lvl)
888 /*@*/
889 {
890 size_t len = 0;
891 int indent = (lvl > 0);
892 int c;
893
894 while ((c = (int) *s++) != (int) '\0')
895 {
896 if (indent) {
897 len += 2 * lvl;
898 indent = 0;
899 }
900 if (c == (int) '\n')
901 indent = (lvl > 0);
902 len++;
903 }
904 return len;
905 }
906
914 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s, int lvl)
915 /*@modifies t @*/
916 {
917 char * te = t;
918 int indent = (lvl > 0);
919 int c;
920
921 while ((c = (int) *s++) != (int) '\0') {
922 if (indent) {
923 int i;
924 for (i = 0; i < lvl; i++) {
925 *te++ = ' ';
926 *te++ = ' ';
927 }
928 indent = 0;
929 }
930 if (c == (int) '\n')
931 indent = (lvl > 0);
932 *te++ = (char) c;
933 }
934 *te = '\0';
935 return t;
936 }
937
944 static /*@only@*/ char * yamlFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
945 /*@*/
946 {
947 int element = he->ix;
948 int ix = (he->ix > 0 ? he->ix : 0);
949 const char * xtag = NULL;
950 int freetag = 0;
951 size_t nb;
952 char * val;
953 const char * s = NULL;
954 char * t, * te;
955 rpmuint64_t anint = 0;
956 int freeit = 0;
957 int lvl = 0;
958 int xx;
959 int ls;
960 int c;
961
962 assert(ix == 0);
963 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
964 xx = 0;
965 ls = 0;
966 switch (he->t) {
967 case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
968 case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
969 case RPM_STRING_TYPE:
970 s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
971 if (strchr("[", s[0])) /* leading [ */
972 xx = 1;
973 if (xx == 0)
974 while ((c = (int) *s++) != (int) '\0') {
975 switch (c) {
976 default:
977 continue;
978 case '\n': /* multiline */
979 xx = 1;
980 if (s[0] == ' ' || s[0] == '\t') /* leading space */
981 ls = 1;
982 continue;
983 case '-': /* leading "- \"" */
984 case ':': /* embedded ": " or ":" at EOL */
985 if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
986 continue;
987 xx = 1;
988 /*@switchbreak@*/ break;
989 }
990 /*@loopbreak@*/ break;
991 }
992 if (xx) {
993 if (ls) { /* leading spaces means we need to specify the indent */
994 xtag = xmalloc(strlen("- |##-\n") + 1);
995 freetag = 1;
996 if (element >= 0) {
997 lvl = 3;
998 sprintf((char *)xtag, "- |%d-\n", lvl);
999 } else {
1000 lvl = 2;
1001 if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */
1002 sprintf((char *)xtag, "|%d-\n", lvl);
1003 }
1004 } else {
1005 if (element >= 0) {
1006 xtag = "- |-\n";
1007 lvl = 3;
1008 } else {
1009 xtag = "|-\n";
1010 lvl = 2;
1011 if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */
1012 }
1013 }
1014 } else {
1015 xtag = (element >= 0 ? "- " : NULL);
1016 }
1017
1018 /* XXX Force utf8 strings. */
1019 s = xstrdup(he->p.str);
1020 s = xstrtolocale(s);
1021 freeit = 1;
1022 break;
1023 case RPM_BIN_TYPE:
1024 /*@-globs -mods@*/ /* Don't bother annotating beecrypt global mods */
1025 { int cpl = b64encode_chars_per_line;
1026 b64encode_chars_per_line = 0;
1027 /*@-formatconst@*/
1028 s = base64Format(he, NULL);
1029 element = -element; /* XXX skip " " indent. */
1030 /*@=formatconst@*/
1031 b64encode_chars_per_line = cpl;
1032 xtag = "!!binary ";
1033 freeit = 1;
1034 } break;
1035 /*@=globs =mods@*/
1036 case RPM_UINT8_TYPE:
1037 anint = (rpmuint64_t)he->p.ui8p[ix];
1038 break;
1039 case RPM_UINT16_TYPE:
1040 anint = (rpmuint64_t)he->p.ui16p[ix];
1041 break;
1042 case RPM_UINT32_TYPE:
1043 anint = (rpmuint64_t)he->p.ui32p[ix];
1044 break;
1045 case RPM_UINT64_TYPE:
1046 anint = he->p.ui64p[ix];
1047 break;
1048 default:
1049 return xstrdup(_("(invalid yaml type)"));
1050 /*@notreached@*/ break;
1051 }
1052
1053 if (s == NULL) {
1054 int tlen = 64;
1055 t = memset(alloca(tlen+1), 0, tlen+1);
1056 /*@-duplicatequals@*/
1057 xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
1058 /*@=duplicatequals@*/
1059 s = t;
1060 xtag = (element >= 0 ? "- " : NULL);
1061 }
1062
1063 nb = yamlstrlen(s, lvl);
1064 if (nb == 0) {
1065 if (element >= 0)
1066 nb += sizeof(" ") - 1;
1067 nb += sizeof("- ~") - 1;
1068 nb++;
1069 te = t = alloca(nb);
1070 if (element >= 0)
1071 te = stpcpy(te, " ");
1072 te = stpcpy(te, "- ~");
1073 } else {
1074 if (element >= 0)
1075 nb += sizeof(" ") - 1;
1076 if (xtag)
1077 nb += strlen(xtag);
1078 nb++;
1079 te = t = alloca(nb);
1080 if (element >= 0)
1081 te = stpcpy(te, " ");
1082 if (xtag)
1083 te = stpcpy(te, xtag);
1084 /*@-modobserver -observertrans -statictrans @*/ /* XXX LCL: can't see freetag flow */
1085 if (freetag)
1086 xtag = _free(xtag);
1087 /*@=modobserver =observertrans =statictrans @*/
1088 te = yamlstrcpy(te, s, lvl);
1089 te += strlen(te);
1090 }
1091
1092 /* XXX s was malloc'd */
1093 if (freeit)
1094 s = _free(s);
1095
1096 val = xstrdup(t);
1097
1098 return val;
1099 }
1100
1107 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1108 /*@globals fileSystem, internalState @*/
1109 /*@modifies fileSystem, internalState @*/
1110 {
1111 int ix = (he->ix > 0 ? he->ix : 0);
1112 char * val, * t;
1113
1114 assert(ix == 0);
1115 if (!(he->t == RPM_BIN_TYPE)) {
1116 val = xstrdup(_("(not a blob)"));
1117 } else {
1118 rpmuint8_t * pkt = he->p.ui8p;
1119 unsigned int pktlen = 0;
1120 unsigned int v = (unsigned int) *pkt;
1121 pgpTag tag = 0;
1122 unsigned int plen;
1123 unsigned int hlen = 0;
1124
1125 if (v & 0x80) {
1126 if (v & 0x40) {
1127 tag = (v & 0x3f);
1128 plen = pgpLen(pkt+1, &hlen);
1129 } else {
1130 tag = (v >> 2) & 0xf;
1131 plen = (1 << (v & 0x3));
1132 hlen = pgpGrab(pkt+1, plen);
1133 }
1134
1135 pktlen = 1 + plen + hlen;
1136 }
1137
1138 if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
1139 val = xstrdup(_("(not an OpenPGP signature)"));
1140 } else {
1141 pgpDig dig = pgpDigNew(0);
1142 pgpDigParams sigp = pgpGetSignature(dig);
1143 size_t nb = 0;
1144 const char *tempstr;
1145
1146 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
1147
1148 val = NULL;
1149 again:
1150 nb += 100;
1151 val = t = xrealloc(val, nb + 1);
1152
1153 switch (sigp->pubkey_algo) {
1154 case PGPPUBKEYALGO_DSA:
1155 t = stpcpy(t, "DSA");
1156 break;
1157 case PGPPUBKEYALGO_RSA:
1158 t = stpcpy(t, "RSA");
1159 break;
1160 default:
1161 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->pubkey_algo);
1162 t += strlen(t);
1163 break;
1164 }
1165 if (t + 5 >= val + nb)
1166 goto again;
1167 *t++ = '/';
1168 switch (sigp->hash_algo) {
1169 case PGPHASHALGO_MD5:
1170 t = stpcpy(t, "MD5");
1171 break;
1172 case PGPHASHALGO_SHA1:
1173 t = stpcpy(t, "SHA1");
1174 break;
1175 default:
1176 (void) snprintf(t, nb - (t - val), "%u", (unsigned)sigp->hash_algo);
1177 t += strlen(t);
1178 break;
1179 }
1180 if (t + strlen (", ") + 1 >= val + nb)
1181 goto again;
1182
1183 t = stpcpy(t, ", ");
1184
1185 /* this is important if sizeof(rpmuint32_t) ! sizeof(time_t) */
1186 { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
1187 struct tm * tstruct = localtime(&dateint);
1188 if (tstruct)
1189 (void) strftime(t, (nb - (t - val)), "%c", tstruct);
1190 }
1191 t += strlen(t);
1192 if (t + strlen (", Key ID ") + 1 >= val + nb)
1193 goto again;
1194 t = stpcpy(t, ", Key ID ");
1195 tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
1196 if (t + strlen (tempstr) > val + nb)
1197 goto again;
1198 t = stpcpy(t, tempstr);
1199
1200 dig = pgpDigFree(dig, "pgpsigFormat");
1201 }
1202 }
1203
1204 return val;
1205 }
1206
1213 static /*@only@*/
1214 char * depflagsFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1215 /*@*/
1216 {
1217 int ix = (he->ix > 0 ? he->ix : 0);
1218 char * val;
1219
1220 assert(ix == 0);
1221 if (he->t != RPM_UINT64_TYPE) {
1222 val = xstrdup(_("(invalid type)"));
1223 } else {
1224 rpmuint64_t anint = he->p.ui64p[ix];
1225 char *t, *buf;
1226
1227 t = buf = alloca(32);
1228 *t = '\0';
1229
1230 #ifdef NOTYET /* XXX appending markers breaks :depflags format. */
1231 if (anint & RPMSENSE_SCRIPT_PRE)
1232 t = stpcpy(t, "(pre)");
1233 else if (anint & RPMSENSE_SCRIPT_POST)
1234 t = stpcpy(t, "(post)");
1235 else if (anint & RPMSENSE_SCRIPT_PREUN)
1236 t = stpcpy(t, "(preun)");
1237 else if (anint & RPMSENSE_SCRIPT_POSTUN)
1238 t = stpcpy(t, "(postun)");
1239 #endif
1240 if (anint & RPMSENSE_SENSEMASK)
1241 *t++ = ' ';
1242 if (anint & RPMSENSE_LESS)
1243 *t++ = '<';
1244 if (anint & RPMSENSE_GREATER)
1245 *t++ = '>';
1246 if (anint & RPMSENSE_EQUAL)
1247 *t++ = '=';
1248 if (anint & RPMSENSE_SENSEMASK)
1249 *t++ = ' ';
1250 *t = '\0';
1251
1252 val = xstrdup(buf);
1253 }
1254
1255 return val;
1256 }
1257
1265 static /*@only@*/
1266 char * deptypeFormat(HE_t he, /*@unused@*/ /*@null@*/ const char ** av)
1267 /*@*/
1268 {
1269 int ix = (he->ix > 0 ? he->ix : 0);
1270 char * val;
1271
1272 assert(ix == 0);
1273 if (he->t != RPM_UINT64_TYPE) {
1274 val = xstrdup(_("(invalid type)"));
1275 } else {
1276 rpmuint64_t anint = he->p.ui64p[ix];
1277 char *t, *buf;
1278
1279 t = buf = alloca(32);
1280 *t = '\0';
1281
1282 if (anint & RPMSENSE_SCRIPT_PRE)
1283 t = stpcpy(t, "pre");
1284 else if (anint & RPMSENSE_SCRIPT_POST)
1285 t = stpcpy(t, "post");
1286 else if (anint & RPMSENSE_SCRIPT_PREUN)
1287 t = stpcpy(t, "preun");
1288 else if (anint & RPMSENSE_SCRIPT_POSTUN)
1289 t = stpcpy(t, "postun");
1290 else if (anint & RPMSENSE_SCRIPT_VERIFY)
1291 t = stpcpy(t, "verify");
1292 else if (anint & RPMSENSE_RPMLIB)
1293 t = stpcpy(t, "rpmlib");
1294 else if (anint & RPMSENSE_INTERP)
1295 t = stpcpy(t, "interp");
1296 else if (anint & (RPMSENSE_FIND_PROVIDES | RPMSENSE_FIND_REQUIRES))
1297 t = stpcpy(t, "auto");
1298 else
1299 t = stpcpy(t, "manual");
1300 *t = '\0';
1301
1302 val = xstrdup(buf);
1303 }
1304
1305 return val;
1306 }
1307
1314 static int instprefixTag(Header h, HE_t he)
1315 /*@globals internalState @*/
1316 /*@modifies he, internalState @*/
1317 {
1318 he->tag = RPMTAG_INSTALLPREFIX;
1319 if (headerGet(h, he, 0))
1320 return 0;
1321
1322 he->tag = RPMTAG_INSTPREFIXES;
1323 if (headerGet(h, he, 0)) {
1324 rpmTagData array = { .argv = he->p.argv };
1325 he->t = RPM_STRING_TYPE;
1326 he->c = 1;
1327 he->p.str = xstrdup(array.argv[0]);
1328 he->freeData = 1;
1329 array.ptr = _free(array.ptr);
1330 return 0;
1331 }
1332 return 1;
1333 }
1334
1342 static int tv2uuidv1(/*@unused@*/ Header h, HE_t he, struct timeval *tv)
1343 /*@modifies he @*/
1344 {
1345 rpmuint64_t uuid_time = ((rpmuint64_t)tv->tv_sec * 10000000) +
1346 (tv->tv_usec * 10) + 0x01B21DD213814000ULL;
1347
1348 he->t = RPM_BIN_TYPE;
1349 he->c = 128/8;
1350 he->p.ptr = xcalloc(1, he->c);
1351 he->freeData = 1;
1352 if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) {
1353 he->p.ptr = _free(he->p.ptr);
1354 he->freeData = 0;
1355 return 1;
1356 }
1357
1358 he->p.ui8p[6] &= 0xf0; /* preserve version, clear time_hi nibble */
1359 he->p.ui8p[8] &= 0x3f; /* preserve reserved, clear clock */
1360 he->p.ui8p[9] &= 0x00;
1361
1362 he->p.ui8p[3] = (rpmuint8_t)(uuid_time >> 0);
1363 he->p.ui8p[2] = (rpmuint8_t)(uuid_time >> 8);
1364 he->p.ui8p[1] = (rpmuint8_t)(uuid_time >> 16);
1365 he->p.ui8p[0] = (rpmuint8_t)(uuid_time >> 24);
1366 he->p.ui8p[5] = (rpmuint8_t)(uuid_time >> 32);
1367 he->p.ui8p[4] = (rpmuint8_t)(uuid_time >> 40);
1368 he->p.ui8p[6] |= (rpmuint8_t)(uuid_time >> 56) & 0x0f;
1369
1370 #ifdef NOTYET
1371 /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */
1372 he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f);
1373 he->p.ui8p[9] |= he->p.ui8p[3]
1374 #endif
1375
1376 return 0;
1377 }
1378
1385 static int tag2uuidv1(Header h, HE_t he)
1386 /*@globals internalState @*/
1387 /*@modifies he, internalState @*/
1388 {
1389 struct timeval tv;
1390
1391 if (!headerGet(h, he, 0))
1392 return 1;
1393 tv.tv_sec = (long) he->p.ui32p[0];
1394 tv.tv_usec = (long) (he->c > 1 ? he->p.ui32p[1] : 0);
1395 he->p.ptr = _free(he->p.ptr);
1396 return tv2uuidv1(h, he, &tv);
1397 }
1398
1405 static int installtime_uuidTag(Header h, HE_t he)
1406 /*@globals internalState @*/
1407 /*@modifies he, internalState @*/
1408 {
1409 he->tag = RPMTAG_INSTALLTIME;
1410 return tag2uuidv1(h, he);
1411 }
1412
1419 static int buildtime_uuidTag(Header h, HE_t he)
1420 /*@globals internalState @*/
1421 /*@modifies he, internalState @*/
1422 {
1423 he->tag = RPMTAG_BUILDTIME;
1424 return tag2uuidv1(h, he);
1425 }
1426
1433 static int origintime_uuidTag(Header h, HE_t he)
1434 /*@globals internalState @*/
1435 /*@modifies he, internalState @*/
1436 {
1437 he->tag = RPMTAG_ORIGINTIME;
1438 return tag2uuidv1(h, he);
1439 }
1440
1447 static int installtid_uuidTag(Header h, HE_t he)
1448 /*@globals internalState @*/
1449 /*@modifies he, internalState @*/
1450 {
1451 he->tag = RPMTAG_INSTALLTID;
1452 return tag2uuidv1(h, he);
1453 }
1454
1461 static int removetid_uuidTag(Header h, HE_t he)
1462 /*@globals internalState @*/
1463 /*@modifies he, internalState @*/
1464 {
1465 he->tag = RPMTAG_REMOVETID;
1466 return tag2uuidv1(h, he);
1467 }
1468
1475 static int origintid_uuidTag(Header h, HE_t he)
1476 /*@globals internalState @*/
1477 /*@modifies he, internalState @*/
1478 {
1479 he->tag = RPMTAG_ORIGINTID;
1480 return tag2uuidv1(h, he);
1481 }
1482
1483 /*@unchecked@*/ /*@observer@*/
1484 static const char uuid_ns[] = "ns:URL";
1485 /*@unchecked@*/ /*@observer@*/
1486 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}";
1487 /*@unchecked@*/ /*@observer@*/
1488 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}";
1489 /*@unchecked@*/
1490 static rpmuint32_t uuid_version = 5;
1491
1500 static int str2uuid(HE_t he, /*@unused@*/ /*@null@*/ const char ** av,
1501 rpmuint32_t version, char * val)
1502 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1503 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1504 {
1505 const char * ns = NULL;
1506 const char * tagn = tagName(he->tag);
1507 const char * s = NULL;
1508 int rc;
1509
1510 /* XXX Substitute Pkgid & Hdrid strings for aliases. */
1511 if (!strcmp("Sigmd5", tagn))
1512 tagn = "Pkgid";
1513 else if (!strcmp("Sha1header", tagn))
1514 tagn = "Hdrid";
1515
1516 switch (version) {
1517 default:
1518 version = uuid_version;
1519 /*@fallthrough@*/
1520 case 3:
1521 case 5:
1522 assert(he->t == RPM_STRING_TYPE);
1523 ns = uuid_ns;
1524 s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/",
1525 he->p.str, NULL);
1526 /*@fallthrough@*/
1527 case 4:
1528 break;
1529 }
1530 he->p.ptr = _free(he->p.ptr);
1531 he->t = RPM_BIN_TYPE;
1532 he->c = 128/8;
1533 he->p.ptr = xcalloc(1, he->c);
1534 he->freeData = 1;
1535 rc = rpmuuidMake((int)version, ns, s, val, (unsigned char *)he->p.ui8p);
1536 if (rc) {
1537 he->p.ptr = _free(he->p.ptr);
1538 he->freeData = 0;
1539 }
1540 s = _free(s);
1541 return rc;
1542 }
1543
1550 static int tag2uuidv5(Header h, HE_t he)
1551 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1552 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1553 {
1554 if (!headerGet(h, he, 0))
1555 return 1;
1556 switch (he->t) {
1557 default:
1558 assert(0);
1559 /*@notreached@*/ break;
1560 case RPM_BIN_TYPE: { /* Convert RPMTAG_PKGID from binary => hex. */
1561 static const char hex[] = "0123456789abcdef";
1562 char * t;
1563 char * te;
1564 rpmuint32_t i;
1565
1566 t = te = xmalloc (2*he->c + 1);
1567 for (i = 0; i < he->c; i++) {
1568 *te++ = hex[ (int)((he->p.ui8p[i] >> 4) & 0x0f) ];
1569 *te++ = hex[ (int)((he->p.ui8p[i] ) & 0x0f) ];
1570 }
1571 *te = '\0';
1572 he->p.ptr = _free(he->p.ptr);
1573 he->t = RPM_STRING_TYPE;
1574 he->p.ptr = t;
1575 he->c = 1;
1576 he->freeData = 1;
1577 } break;
1578 case RPM_STRING_TYPE:
1579 break;
1580 }
1581 return str2uuid(he, NULL, 0, NULL);
1582 }
1583
1590 static int pkguuidTag(Header h, HE_t he)
1591 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1592 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1593 {
1594 he->tag = RPMTAG_PKGID;
1595 return tag2uuidv5(h, he);
1596 }
1597
1604 static int sourcepkguuidTag(Header h, HE_t he)
1605 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1606 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1607 {
1608 he->tag = RPMTAG_SOURCEPKGID;
1609 return tag2uuidv5(h, he);
1610 }
1611
1618 static int hdruuidTag(Header h, HE_t he)
1619 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1620 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1621 {
1622 he->tag = RPMTAG_HDRID;
1623 return tag2uuidv5(h, he);
1624 }
1625
1632 static int triggercondsTag(Header h, HE_t he)
1633 /*@globals internalState @*/
1634 /*@modifies he, internalState @*/
1635 {
1636 HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
1637 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
1638 HE_t Ihe = memset(alloca(sizeof(*Ihe)), 0, sizeof(*Ihe));
1639 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
1640 HE_t Vhe = memset(alloca(sizeof(*Vhe)), 0, sizeof(*Vhe));
1641 HE_t She = memset(alloca(sizeof(*She)), 0, sizeof(*She));
1642 rpmuint64_t anint;
1643 unsigned i, j;
1644 int rc = 1; /* assume failure */
1645 int xx;
1646
1647 he->freeData = 0;
1648
1649 Nhe->tag = RPMTAG_TRIGGERNAME;
1650 xx = headerGet(h, Nhe, 0);
1651 if (!xx) { /* no triggers, succeed anyways */
1652 rc = 0;
1653 goto exit;
1654 }
1655
1656 Ihe->tag = RPMTAG_TRIGGERINDEX;
1657 xx = headerGet(h, Ihe, 0);
1658 if (!xx) goto exit;
1659
1660 Fhe->tag = RPMTAG_TRIGGERFLAGS;
1661 xx = headerGet(h, Fhe, 0);
1662 if (!xx) goto exit;
1663
1664 Vhe->tag = RPMTAG_TRIGGERVERSION;
1665 xx = headerGet(h, Vhe, 0);
1666 if (!xx) goto exit;
1667
1668 She->tag = RPMTAG_TRIGGERSCRIPTS;
1669 xx = headerGet(h, She, 0);
1670 if (!xx) goto exit;
1671
1672 _he->tag = he->tag;
1673 _he->t = RPM_UINT64_TYPE;
1674 _he->p.ui64p = &anint;
1675 _he->c = 1;
1676 _he->freeData = 0;
1677
1678 he->t = RPM_STRING_ARRAY_TYPE;
1679 he->c = She->c;
1680
1681 he->freeData = 1;
1682 he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
1683 for (i = 0; i < (unsigned) he->c; i++) {
1684 char * item, * flagsStr;
1685 char * chptr;
1686
1687 chptr = xstrdup("");
1688
1689 for (j = 0; j < Nhe->c; j++) {
1690 if (Ihe->p.ui32p[j] != i)
1691 /*@innercontinue@*/ continue;
1692
1693 item = xmalloc(strlen(Nhe->p.argv[j]) + strlen(Vhe->p.argv[j]) + 20);
1694 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
1695 if (Fhe->p.ui32p[j] & RPMSENSE_SENSEMASK) {
1696 anint = Fhe->p.ui32p[j];
1697 flagsStr = depflagsFormat(_he, NULL);
1698 sprintf(item, "%s%s%s", Nhe->p.argv[j], flagsStr, Vhe->p.argv[j]);
1699 flagsStr = _free(flagsStr);
1700 } else
1701 strcpy(item, Nhe->p.argv[j]);
1702 /*@=compmempass@*/
1703
1704 chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
1705 if (*chptr != '\0') strcat(chptr, ", ");
1706 strcat(chptr, item);
1707 item = _free(item);
1708 }
1709
1710 he->p.argv[i] = chptr;
1711 }
1712 rc = 0;
1713
1714 exit:
1715 Ihe->p.ptr = _free(Ihe->p.ptr);
1716 Fhe->p.ptr = _free(Fhe->p.ptr);
1717 Nhe->p.ptr = _free(Nhe->p.ptr);
1718 Vhe->p.ptr = _free(Vhe->p.ptr);
1719 She->p.ptr = _free(She->p.ptr);
1720
1721 return rc;
1722 }
1723
1730 static int triggertypeTag(Header h, HE_t he)
1731 /*@globals internalState @*/
1732 /*@modifies he, internalState @*/
1733 {
1734 HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
1735 rpmTagData indices = { .ptr = NULL };
1736 rpmTagData flags = { .ptr = NULL };
1737 rpmTagData s = { .ptr = NULL };
1738 rpmTagCount numNames;
1739 rpmTagCount numScripts;
1740 unsigned i, j;
1741 int rc = 1; /* assume failure */
1742 int xx;
1743
1744 he->freeData = 0;
1745
1746 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
1747 _he->tag = RPMTAG_TRIGGERINDEX;
1748 xx = headerGet(h, _he, 0);
1749 if (!xx) goto exit;
1750 indices.ui32p = _he->p.ui32p;
1751 numNames = _he->c;
1752
1753 _he->tag = RPMTAG_TRIGGERFLAGS;
1754 xx = headerGet(h, _he, 0);
1755 if (!xx) goto exit;
1756 flags.ui32p = _he->p.ui32p;
1757
1758 _he->tag = RPMTAG_TRIGGERSCRIPTS;
1759 xx = headerGet(h, _he, 0);
1760 if (!xx) goto exit;
1761 s.argv = _he->p.argv;
1762 numScripts = _he->c;
1763 /*@=compmempass@*/
1764
1765 he->t = RPM_STRING_ARRAY_TYPE;
1766 he->c = numScripts;
1767
1768 he->freeData = 1;
1769 he->p.argv = xmalloc(sizeof(*he->p.argv) * he->c);
1770 for (i = 0; i < (unsigned) he->c; i++) {
1771 for (j = 0; j < (unsigned) numNames; j++) {
1772 if (indices.ui32p[j] != i)
1773 /*@innercontinue@*/ continue;
1774
1775 /* XXX FIXME: there's memory leaks here. */
1776 if (flags.ui32p[j] & RPMSENSE_TRIGGERPREIN)
1777 he->p.argv[i] = xstrdup("prein");
1778 else if (flags.ui32p[j] & RPMSENSE_TRIGGERIN)
1779 he->p.argv[i] = xstrdup("in");
1780 else if (flags.ui32p[j] & RPMSENSE_TRIGGERUN)
1781 he->p.argv[i] = xstrdup("un");
1782 else if (flags.ui32p[j] & RPMSENSE_TRIGGERPOSTUN)
1783 he->p.argv[i] = xstrdup("postun");
1784 else
1785 he->p.argv[i] = xstrdup("");
1786 /*@innerbreak@*/ break;
1787 }
1788 }
1789 rc = 0;
1790
1791 exit:
1792 indices.ptr = _free(indices.ptr);
1793 flags.ptr = _free(flags.ptr);
1794 s.ptr = _free(s.ptr);
1795 return 0;
1796 }
1797
1798 /* I18N look aside diversions */
1799
1800 #if defined(ENABLE_NLS)
1801 /*@-exportlocal -exportheadervar@*/
1802 /*@unchecked@*/
1803 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
1804 /*@=exportlocal =exportheadervar@*/
1805 #endif
1806 /*@observer@*/ /*@unchecked@*/
1807 static const char * language = "LANGUAGE";
1808
1809 /*@observer@*/ /*@unchecked@*/
1810 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
1811
1818 static int i18nTag(Header h, HE_t he)
1819 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1820 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1821 {
1822 char * dstring = rpmExpand(_macro_i18ndomains, NULL);
1823 int rc = 1; /* assume failure */
1824
1825 he->t = RPM_STRING_TYPE;
1826 he->p.str = NULL;
1827 he->c = 0;
1828 he->freeData = 0;
1829
1830 if (dstring && *dstring) {
1831 char *domain, *de;
1832 const char * langval;
1833 const char * msgkey;
1834 const char * msgid;
1835
1836 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
1837 const char * tn;
1838 char * mk;
1839 size_t nb = sizeof("()");
1840 int xx;
1841
1842 nhe->tag = RPMTAG_NAME;
1843 xx = headerGet(h, nhe, 0);
1844 /*
1845 * XXX Ick, tagName() is called by headerGet(), and the tagName()
1846 * buffer is valid only until next tagName() call.
1847 * For now, do the tagName() lookup after headerGet().
1848 */
1849 tn = tagName(he->tag);
1850 if (tn) nb += strlen(tn);
1851 if (nhe->p.str) nb += strlen(nhe->p.str);
1852 mk = alloca(nb);
1853 (void) snprintf(mk, nb, "%s(%s)",
1854 (nhe->p.str ? nhe->p.str : ""), (tn ? tn : ""));
1855 mk[nb-1] = '\0';
1856 nhe->p.ptr = _free(nhe->p.ptr);
1857 msgkey = mk;
1858 }
1859
1860 /* change to en_US for msgkey -> msgid resolution */
1861 langval = getenv(language);
1862 (void) setenv(language, "en_US", 1);
1863 #if defined(ENABLE_NLS)
1864 /*@i@*/ ++_nl_msg_cat_cntr;
1865 #endif
1866
1867 msgid = NULL;
1868 for (domain = dstring; domain != NULL; domain = de) {
1869 de = strchr(domain, ':');
1870 if (de) *de++ = '\0';
1871 /*@-unrecog@*/
1872 msgid = dgettext(domain, msgkey);
1873 /*@=unrecog@*/
1874 if (msgid != msgkey) break;
1875 }
1876
1877 /* restore previous environment for msgid -> msgstr resolution */
1878 if (langval)
1879 (void) setenv(language, langval, 1);
1880 else
1881 unsetenv(language);
1882 #if defined(ENABLE_NLS)
1883 /*@i@*/ ++_nl_msg_cat_cntr;
1884 #endif
1885
1886 if (domain && msgid) {
1887 /*@-unrecog@*/
1888 const char * s = dgettext(domain, msgid);
1889 /*@=unrecog@*/
1890 if (s) {
1891 rc = 0;
1892 he->p.str = xstrdup(s);
1893 he->c = 1;
1894 he->freeData = 1;
1895 }
1896 }
1897 }
1898
1899 /*@-dependenttrans@*/
1900 dstring = _free(dstring);
1901 /*@=dependenttrans@*/
1902 if (!rc)
1903 return rc;
1904
1905 rc = headerGet(h, he, HEADERGET_NOEXTENSION);
1906 if (rc) {
1907 rc = 0;
1908 he->p.str = xstrtolocale(he->p.str);
1909 he->freeData = 1;
1910 return rc;
1911 }
1912
1913 he->t = RPM_STRING_TYPE;
1914 he->p.str = NULL;
1915 he->c = 0;
1916 he->freeData = 0;
1917
1918 return 1;
1919 }
1920
1924 static int localeTag(Header h, HE_t he)
1925 /*@globals internalState @*/
1926 /*@modifies he, internalState @*/
1927 {
1928 int rc;
1929
1930 rc = headerGet(h, he, HEADERGET_NOEXTENSION);
1931 if (!rc || he->p.str == NULL || he->c == 0) {
1932 he->t = RPM_STRING_TYPE;
1933 he->freeData = 0;
1934 return 1;
1935 }
1936
1937 switch (he->t) {
1938 default:
1939 he->freeData = 0;
1940 break;
1941 case RPM_STRING_TYPE:
1942 he->p.str = xstrtolocale(he->p.str);
1943 he->freeData = 1;
1944 break;
1945 case RPM_STRING_ARRAY_TYPE:
1946 { const char ** argv;
1947 char * te;
1948 size_t l = 0;
1949 unsigned i;
1950 for (i = 0; i < (unsigned) he->c; i++) {
1951 he->p.argv[i] = xstrdup(he->p.argv[i]);
1952 he->p.argv[i] = xstrtolocale(he->p.argv[i]);
1953 assert(he->p.argv[i] != NULL);
1954 l += strlen(he->p.argv[i]) + 1;
1955 }
1956 argv = xmalloc(he->c * sizeof(*argv) + l);
1957 te = (char *)&argv[he->c];
1958 for (i = 0; i < (unsigned) he->c; i++) {
1959 argv[i] = te;
1960 te = stpcpy(te, he->p.argv[i]);
1961 te++;
1962 he->p.argv[i] = _free(he->p.argv[i]);
1963 }
1964 he->p.ptr = _free(he->p.ptr);
1965 he->p.argv = argv;
1966 he->freeData = 1;
1967 } break;
1968 }
1969
1970 return 0;
1971 }
1972
1979 static int summaryTag(Header h, HE_t he)
1980 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1981 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1982 {
1983 he->tag = RPMTAG_SUMMARY;
1984 return i18nTag(h, he);
1985 }
1986
1993 static int descriptionTag(Header h, HE_t he)
1994 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
1995 /*@modifies he, rpmGlobalMacroContext, internalState @*/
1996 {
1997 he->tag = RPMTAG_DESCRIPTION;
1998 return i18nTag(h, he);
1999 }
2000
2001 static int changelognameTag(Header h, HE_t he)
2002 /*@globals internalState @*/
2003 /*@modifies he, internalState @*/
2004 {
2005 he->tag = RPMTAG_CHANGELOGNAME;
2006 return localeTag(h, he);
2007 }
2008
2009 static int changelogtextTag(Header h, HE_t he)
2010 /*@globals internalState @*/
2011 /*@modifies he, internalState @*/
2012 {
2013 he->tag = RPMTAG_CHANGELOGTEXT;
2014 return localeTag(h, he);
2015 }
2016
2023 static int groupTag(Header h, HE_t he)
2024 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2025 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2026 {
2027 he->tag = RPMTAG_GROUP;
2028 return i18nTag(h, he);
2029 }
2030
2037 static int dbinstanceTag(Header h, HE_t he)
2038 /*@modifies he @*/
2039 {
2040 he->tag = RPMTAG_DBINSTANCE;
2041 he->t = RPM_UINT32_TYPE;
2042 he->p.ui32p = xmalloc(sizeof(*he->p.ui32p));
2043 he->p.ui32p[0] = headerGetInstance(h);
2044 he->freeData = 1;
2045 he->c = 1;
2046 return 0;
2047 }
2048
2055 static int headerstartoffTag(Header h, HE_t he)
2056 /*@modifies he @*/
2057 {
2058 he->tag = RPMTAG_HEADERSTARTOFF;
2059 he->t = RPM_UINT64_TYPE;
2060 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2061 he->p.ui64p[0] = headerGetStartOff(h);
2062 he->freeData = 1;
2063 he->c = 1;
2064 return 0;
2065 }
2066
2073 static int headerendoffTag(Header h, HE_t he)
2074 /*@modifies he @*/
2075 {
2076 he->tag = RPMTAG_HEADERENDOFF;
2077 he->t = RPM_UINT64_TYPE;
2078 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2079 he->p.ui64p[0] = headerGetEndOff(h);
2080 he->freeData = 1;
2081 he->c = 1;
2082 return 0;
2083 }
2084
2091 static int pkgoriginTag(Header h, HE_t he)
2092 /*@globals internalState @*/
2093 /*@modifies he, internalState @*/
2094 {
2095 const char * origin;
2096 int rc = 1;
2097
2098 he->tag = RPMTAG_PACKAGEORIGIN;
2099 if (!headerGet(h, he, HEADERGET_NOEXTENSION)
2100 && (origin = headerGetOrigin(h)) != NULL)
2101 {
2102 he->t = RPM_STRING_TYPE;
2103 he->p.str = xstrdup(origin);
2104 he->c = 1;
2105 he->freeData = 1;
2106 rc = 0;
2107 }
2108 return rc;
2109 }
2110
2117 static int pkgbaseurlTag(Header h, HE_t he)
2118 /*@globals internalState @*/
2119 /*@modifies he, internalState @*/
2120 {
2121 const char * baseurl;
2122 int rc = 1;
2123
2124 he->tag = RPMTAG_PACKAGEBASEURL;
2125 if (!headerGet(h, he, HEADERGET_NOEXTENSION)
2126 && (baseurl = headerGetBaseURL(h)) != NULL)
2127 {
2128 he->t = RPM_STRING_TYPE;
2129 he->p.str = xstrdup(baseurl);
2130 he->c = 1;
2131 he->freeData = 1;
2132 rc = 0;
2133 }
2134 return rc;
2135 }
2136
2143 static int pkgdigestTag(Header h, HE_t he)
2144 /*@modifies he @*/
2145 {
2146 const char * digest;
2147 int rc = 1;
2148
2149 he->tag = RPMTAG_PACKAGEDIGEST;
2150 if ((digest = headerGetDigest(h)) != NULL)
2151 {
2152 he->t = RPM_STRING_TYPE;
2153 he->p.str = xstrdup(digest);
2154 he->c = 1;
2155 he->freeData = 1;
2156 rc = 0;
2157 }
2158 return rc;
2159 }
2160
2167 static int pkgmtimeTag(Header h, HE_t he)
2168 /*@modifies he @*/
2169 {
2170 struct stat * st = headerGetStatbuf(h);
2171 he->tag = RPMTAG_PACKAGETIME;
2172 he->t = RPM_UINT64_TYPE;
2173 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2174 /*@-type@*/
2175 he->p.ui64p[0] = (rpmuint64_t)st->st_mtime;
2176 /*@=type@*/
2177 he->freeData = 1;
2178 he->c = 1;
2179 return 0;
2180 }
2181
2188 static int pkgsizeTag(Header h, HE_t he)
2189 /*@modifies he @*/
2190 {
2191 struct stat * st = headerGetStatbuf(h);
2192 he->tag = RPMTAG_PACKAGESIZE;
2193 he->t = RPM_UINT64_TYPE;
2194 he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
2195 he->p.ui64p[0] = (rpmuint64_t)st->st_size;
2196 he->freeData = 1;
2197 he->c = 1;
2198 return 0;
2199 }
2200
2206 /*@only@*/
2207 static char * hGetNVRA(Header h)
2208 /*@globals internalState @*/
2209 /*@modifies h, internalState @*/
2210 {
2211 const char * N = NULL;
2212 const char * V = NULL;
2213 const char * R = NULL;
2214 const char * A = NULL;
2215 size_t nb = 0;
2216 char * NVRA, * t;
2217
2218 (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
2219 if (N) nb += strlen(N);
2220 if (V) nb += strlen(V) + 1;
2221 if (R) nb += strlen(R) + 1;
2222 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
2223 /* do not expose the architecture as this is too less
2224 information, as in OpenPKG the "platform" is described by the
2225 architecture+operating-system combination. But as the whole
2226 "platform" information is actually overkill, just revert to the
2227 RPM 4 behaviour and do not expose any such information at all. */
2228 #else
2229 if (A) nb += strlen(A) + 1;
2230 #endif
2231 nb++;
2232 NVRA = t = xmalloc(nb);
2233 *t = '\0';
2234 if (N) t = stpcpy(t, N);
2235 if (V) t = stpcpy( stpcpy(t, "-"), V);
2236 if (R) t = stpcpy( stpcpy(t, "-"), R);
2237 #if defined(RPM_VENDOR_OPENPKG) /* no-architecture-expose */
2238 /* do not expose the architecture as this is too less
2239 information, as in OpenPKG the "platform" is described by the
2240 architecture+operating-system combination. But as the whole
2241 "platform" information is actually overkill, just revert to the
2242 RPM 4 behaviour and do not expose any such information at all. */
2243 #else
2244 if (A) t = stpcpy( stpcpy(t, "."), A);
2245 #endif
2246 N = _free(N);
2247 V = _free(V);
2248 R = _free(R);
2249 A = _free(A);
2250 return NVRA;
2251 }
2252
2259 static int nvraTag(Header h, HE_t he)
2260 /*@globals internalState @*/
2261 /*@modifies h, he, internalState @*/
2262 {
2263 he->t = RPM_STRING_TYPE;
2264 he->p.str = hGetNVRA(h);
2265 he->c = 1;
2266 he->freeData = 1;
2267 return 0;
2268 }
2269
2287 static void rpmfiBuildFNames(Header h, rpmTag tagN,
2288 /*@null@*/ /*@out@*/ const char *** fnp,
2289 /*@null@*/ /*@out@*/ rpmTagCount * fcp)
2290 /*@globals internalState @*/
2291 /*@modifies *fnp, *fcp, internalState @*/
2292 {
2293 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2294 rpmTag dirNameTag = 0;
2295 rpmTag dirIndexesTag = 0;
2296 rpmTagData baseNames = { .ptr = NULL };
2297 rpmTagData dirNames = { .ptr = NULL };
2298 rpmTagData dirIndexes = { .ptr = NULL };
2299 rpmTagData fileNames;
2300 rpmTagCount count;
2301 size_t size;
2302 int isSource =
2303 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
2304 headerIsEntry(h, RPMTAG_ARCH) != 0);
2305 char * t;
2306 unsigned i;
2307 int xx;
2308
2309 if (tagN == RPMTAG_BASENAMES) {
2310 dirNameTag = RPMTAG_DIRNAMES;
2311 dirIndexesTag = RPMTAG_DIRINDEXES;
2312 } else if (tagN == RPMTAG_ORIGBASENAMES) {
2313 dirNameTag = RPMTAG_ORIGDIRNAMES;
2314 dirIndexesTag = RPMTAG_ORIGDIRINDEXES;
2315 } else {
2316 if (fnp) *fnp = NULL;
2317 if (fcp) *fcp = 0;
2318 return; /* programmer error */
2319 }
2320
2321 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
2322 he->tag = tagN;
2323 xx = headerGet(h, he, 0);
2324 /* XXX 3.0.x SRPM's can be used, relative fn's at RPMTAG_OLDFILENAMES. */
2325 if (xx == 0 && isSource) {
2326 he->tag = RPMTAG_OLDFILENAMES;
2327 xx = headerGet(h, he, 0);
2328 if (xx) {
2329 dirNames.argv = xcalloc(3, sizeof(*dirNames.argv));
2330 dirNames.argv[0] = (const char *)&dirNames.argv[2];
2331 dirIndexes.ui32p = xcalloc(he->c, sizeof(*dirIndexes.ui32p));
2332 }
2333 }
2334 baseNames.argv = he->p.argv;
2335 count = he->c;
2336
2337 if (!xx) {
2338 if (fnp) *fnp = NULL;
2339 if (fcp) *fcp = 0;
2340 return; /* no file list */
2341 }
2342
2343 he->tag = dirNameTag;
2344 if ((xx = headerGet(h, he, 0)) != 0)
2345 dirNames.argv = he->p.argv;
2346
2347 he->tag = dirIndexesTag;
2348 if ((xx = headerGet(h, he, 0)) != 0)
2349 dirIndexes.ui32p = he->p.ui32p;
2350 /*@=compmempass@*/
2351
2352 size = sizeof(*fileNames.argv) * count;
2353 for (i = 0; i < (unsigned)count; i++) {
2354 const char * dn = NULL;
2355 (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
2356 size += strlen(baseNames.argv[i]) + strlen(dn) + 1;
2357 }
2358
2359 fileNames.argv = xmalloc(size);
2360 t = (char *)&fileNames.argv[count];
2361 for (i = 0; i < (unsigned)count; i++) {
2362 const char * dn = NULL;
2363 (void) urlPath(dirNames.argv[dirIndexes.ui32p[i]], &dn);
2364 fileNames.argv[i] = t;
2365 t = stpcpy( stpcpy(t, dn), baseNames.argv[i]);
2366 *t++ = '\0';
2367 }
2368 baseNames.ptr = _free(baseNames.ptr);
2369 dirNames.ptr = _free(dirNames.ptr);
2370 dirIndexes.ptr = _free(dirIndexes.ptr);
2371
2372 /*@-onlytrans@*/
2373 if (fnp)
2374 *fnp = fileNames.argv;
2375 else
2376 fileNames.ptr = _free(fileNames.ptr);
2377 /*@=onlytrans@*/
2378 if (fcp) *fcp = count;
2379 }
2380
2388 static int _fnTag(Header h, HE_t he, rpmTag tag)
2389 /*@globals internalState @*/
2390 /*@modifies he, internalState @*/
2391 {
2392 he->t = RPM_STRING_ARRAY_TYPE;
2393 rpmfiBuildFNames(h, tag, &he->p.argv, &he->c);
2394 he->freeData = 1;
2395 return 0;
2396 }
2397
2398 static int filenamesTag(Header h, HE_t he)
2399 /*@globals internalState @*/
2400 /*@modifies he, internalState @*/
2401 {
2402 he->tag = tagValue("Filenames");
2403 return _fnTag(h, he, RPMTAG_BASENAMES);
2404 }
2405
2406 static int filepathsTag(Header h, HE_t he)
2407 /*@globals internalState @*/
2408 /*@modifies he, internalState @*/
2409 {
2410 he->tag = RPMTAG_FILEPATHS;
2411 return _fnTag(h, he, RPMTAG_BASENAMES);
2412 }
2413
2414 static int origpathsTag(Header h, HE_t he)
2415 /*@globals internalState @*/
2416 /*@modifies he, internalState @*/
2417 {
2418 he->tag = RPMTAG_ORIGPATHS;
2419 return _fnTag(h, he, RPMTAG_ORIGBASENAMES);
2420 }
2421
2431 static int debevrfmtTag(/*@unused@*/ Header h, HE_t he,
2432 HE_t Nhe, HE_t EVRhe, HE_t Fhe)
2433 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2434 /*@modifies he, Nhe, rpmGlobalMacroContext, internalState @*/
2435 {
2436 char * t, * te;
2437 size_t nb = 0;
2438 int rc = 1;
2439
2440 he->t = RPM_STRING_ARRAY_TYPE;
2441 he->c = 0;
2442 he->freeData = 1;
2443 for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
2444 nb += sizeof(*he->p.argv);
2445 nb += strlen(Nhe->p.argv[Nhe->ix]) + 1;
2446 if (*EVRhe->p.argv[Nhe->ix] != '\0')
2447 nb += strlen(EVRhe->p.argv[Nhe->ix]) + (sizeof(" (== )")-1);
2448 he->c++;
2449 }
2450 nb += sizeof(*he->p.argv);
2451
2452 he->p.argv = xmalloc(nb);
2453 te = (char *) &he->p.argv[he->c+1];
2454
2455 he->c = 0;
2456 for (Nhe->ix = 0; Nhe->ix < (int)Nhe->c; Nhe->ix++) {
2457 he->p.argv[he->c++] = te;
2458 if (*EVRhe->p.argv[Nhe->ix] != '\0') {
2459 char opstr[4], * op = opstr;
2460 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_LESS)
2461 *op++ = '<';
2462 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_GREATER)
2463 *op++ = '>';
2464 if (Fhe->p.ui32p[Nhe->ix] & RPMSENSE_EQUAL)
2465 *op++ = '=';
2466 *op = '\0';
2467 t = rpmExpand(Nhe->p.argv[Nhe->ix],
2468 " (", opstr, " ", EVRhe->p.argv[Nhe->ix], ")", NULL);
2469 } else
2470 t = rpmExpand(Nhe->p.argv[Nhe->ix], NULL);
2471 te = stpcpy(te, t);
2472 te++;
2473 t = _free(t);
2474 }
2475 he->p.argv[he->c] = NULL;
2476 rc = 0;
2477
2478 return rc;
2479 }
2480
2490 static int debevrTag(Header h, HE_t he, rpmTag tagN, rpmTag tagEVR, rpmTag tagF)
2491 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2492 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2493 {
2494 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
2495 HE_t EVRhe = memset(alloca(sizeof(*EVRhe)), 0, sizeof(*EVRhe));
2496 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
2497 int rc = 1;
2498 int xx;
2499
2500 Nhe->tag = tagN;
2501 if (!(xx = headerGet(h, Nhe, 0)))
2502 goto exit;
2503 EVRhe->tag = tagEVR;
2504 if (!(xx = headerGet(h, EVRhe, 0)))
2505 goto exit;
2506 assert(EVRhe->c == Nhe->c);
2507 Fhe->tag = tagF;
2508 if (!(xx = headerGet(h, Fhe, 0)))
2509 goto exit;
2510 assert(Fhe->c == Nhe->c);
2511
2512 rc = debevrfmtTag(h, he, Nhe, EVRhe, Fhe);
2513
2514 exit:
2515 Nhe->p.ptr = _free(Nhe->p.ptr);
2516 EVRhe->p.ptr = _free(EVRhe->p.ptr);
2517 Fhe->p.ptr = _free(Fhe->p.ptr);
2518 return rc;
2519 }
2520
2527 static int debconflictsTag(Header h, HE_t he)
2528 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2529 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2530 {
2531 he->tag = tagValue("Debconflicts");
2532 return debevrTag(h, he,
2533 RPMTAG_CONFLICTNAME, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
2534 }
2535
2536 static int debdependsTag(Header h, HE_t he)
2537 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2538 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2539 {
2540 he->tag = tagValue("Debdepends");
2541 return debevrTag(h, he,
2542 RPMTAG_REQUIRENAME, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
2543 }
2544
2545 static int debobsoletesTag(Header h, HE_t he)
2546 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2547 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2548 {
2549 he->tag = tagValue("Debobsoletes");
2550 return debevrTag(h, he,
2551 RPMTAG_OBSOLETENAME, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
2552 }
2553
2554 static int debprovidesTag(Header h, HE_t he)
2555 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2556 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2557 {
2558 he->tag = tagValue("Debprovides");
2559 return debevrTag(h, he,
2560 RPMTAG_PROVIDENAME, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
2561 }
2562
2569 static int debmd5sumsTag(Header h, HE_t he)
2570 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
2571 /*@modifies he, rpmGlobalMacroContext, internalState @*/
2572 {
2573 HE_t Nhe = memset(alloca(sizeof(*Nhe)), 0, sizeof(*Nhe));
2574 HE_t Dhe = memset(alloca(sizeof(*Dhe)), 0, sizeof(*Dhe));
2575 char * t, * te;
2576 size_t nb = 0;
2577 int rc = 1;
2578 int xx;
2579
2580 Nhe->tag = RPMTAG_FILEPATHS;
2581 if (!(xx = headerGet(h, Nhe, 0)))
2582 goto exit;
2583 Dhe->tag = RPMTAG_FILEDIGESTS;
2584 if (!(xx = headerGet(h, Dhe, 0)))
2585 goto exit;
2586 assert(Dhe->c == Nhe->c);
2587
2588 he->tag = tagValue("Debmd5sums");
2589 he->t = RPM_STRING_ARRAY_TYPE;
2590 he->c = 0;
2591 he->freeData = 1;
2592 for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
2593 if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
2594 continue;
2595 nb += sizeof(*he->p.argv);
2596 nb += strlen(Dhe->p.argv[Dhe->ix]) + sizeof(" ") + strlen(Nhe->p.argv[Dhe->ix]) - 1;
2597 he->c++;
2598 }
2599 nb += sizeof(*he->p.argv);
2600
2601 he->p.argv = xmalloc(nb);
2602 te = (char *) &he->p.argv[he->c+1];
2603
2604 he->c = 0;
2605 for (Dhe->ix = 0; Dhe->ix < (int)Dhe->c; Dhe->ix++) {
2606 if (!(Dhe->p.argv[Dhe->ix] && *Dhe->p.argv[Dhe->ix]))
2607 continue;
2608 he->p.argv[he->c++] = te;
2609 t = rpmExpand(Dhe->p.argv[Dhe->ix], " ", Nhe->p.argv[Dhe->ix]+1, NULL);
2610 te = stpcpy(te, t);
2611 te++;
2612 t = _free(t);
2613 }
2614 he->p.argv[he->c] = NULL;
2615 rc = 0;
2616
2617 exit:
2618 Nhe->p.ptr = _free(Nhe->p.ptr);
2619 Dhe->p.ptr = _free(Dhe->p.ptr);
2620 return rc;
2621 }
2622
2623 static int filestatTag(Header h, HE_t he)
2624 /*@globals internalState @*/
2625 /*@modifies he, internalState @*/
2626 {
2627 rpmTagData paths = { .ptr = NULL };
2628 /* _dev */
2629 rpmTagData _ino = { .ptr = NULL };
2630 rpmTagData _mode = { .ptr = NULL };
2631 /* _nlink */
2632 /* _uid */
2633 /* _gid */
2634 rpmTagData _rdev = { .ptr = NULL };
2635 rpmTagData _size = { .ptr = NULL };
2636 /* _blksize */
2637 /* _blocks */
2638 /* _atime */
2639 rpmTagData _mtime = { .ptr = NULL };
2640 /* st_ctime */
2641 int rc;
2642
2643 he->tag = RPMTAG_FILEPATHS;
2644 if ((rc = _fnTag(h, he, RPMTAG_BASENAMES)) != 0 || he->c == 0)
2645 goto exit;
2646
2647 exit:
2648 paths.ptr = _free(paths.ptr);
2649 _ino.ptr = _free(_ino.ptr);
2650 _mode.ptr = _free(_mode.ptr);
2651 _rdev.ptr = _free(_rdev.ptr);
2652 _size.ptr = _free(_size.ptr);
2653 _mtime.ptr = _free(_mtime.ptr);
2654 return rc;
2655 }
2656
2657 static int wnlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
2658 HE_t PNhe, /*@null@*/ HE_t PEVRhe, /*@null@*/ HE_t PFhe)
2659 /*@globals rpmGlobalMacroContext, h_errno,
2660 fileSystem, internalState @*/
2661 /*@modifies *avp, *hitp, rpmGlobalMacroContext,
2662 fileSystem, internalState @*/
2663 {
2664 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
2665 HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
2666 HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
2667 HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
2668 rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
2669 const char * key = PNhe->p.argv[PNhe->ix];
2670 size_t keylen = 0;
2671 rpmmi mi;
2672 rpmTag tagN = RPMTAG_REQUIRENAME;
2673 rpmTag tagEVR = RPMTAG_REQUIREVERSION;
2674 rpmTag tagF = RPMTAG_REQUIREFLAGS;
2675 rpmuint32_t PFlags;
2676 rpmuint32_t RFlags;
2677 EVR_t Pevr;
2678 Header oh;
2679 int rc = 0;
2680 int xx;
2681
2682 if (tagNVRA == 0)
2683 tagNVRA = RPMTAG_NVRA;
2684
2685 PFlags = (PFhe != NULL ? (PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK) : 0);
2686 Pevr = rpmEVRnew(PFlags, 1);
2687
2688 if (PEVRhe != NULL)
2689 xx = rpmEVRparse(xstrdup(PEVRhe->p.argv[PNhe->ix]), Pevr);
2690
2691 RNhe->tag = tagN;
2692 REVRhe->tag = tagEVR;
2693 RFhe->tag = tagF;
2694
2695 mi = rpmmiInit(_rpmdb, tagN, key, keylen);
2696 if (hitp && *hitp)
2697 xx = rpmmiPrune(mi, (int *)argiData(*hitp), argiCount(*hitp), 0);
2698 while ((oh = rpmmiNext(mi)) != NULL) {
2699 if (!headerGet(oh, RNhe, 0))
2700 goto bottom;
2701 if (PEVRhe != NULL) {
2702 if (!headerGet(oh, REVRhe, 0))
2703 goto bottom;
2704 assert(REVRhe->c == RNhe->c);
2705 if (!headerGet(oh, RFhe, 0))
2706 goto bottom;
2707 assert(RFhe->c == RNhe->c);
2708 }
2709
2710 for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
2711 if (strcmp(PNhe->p.argv[PNhe->ix], RNhe->p.argv[RNhe->ix]))
2712 /*@innercontinue@*/ continue;
2713 if (PEVRhe == NULL)
2714 goto bingo;
2715 RFlags = RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK;
2716 { EVR_t Revr = rpmEVRnew(RFlags, 1);
2717 if (!(PFlags && RFlags))
2718 xx = 1;
2719 else {
2720 xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
2721 xx = rpmEVRoverlap(Pevr, Revr);
2722 }
2723 Revr = rpmEVRfree(Revr);
2724 }
2725 if (xx)
2726 goto bingo;
2727 }
2728 goto bottom;
2729
2730 bingo:
2731 NVRAhe->tag = tagNVRA;
2732 xx = headerGet(oh, NVRAhe, 0);
2733 if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
2734 xx = argvAdd(avp, NVRAhe->p.str);
2735 xx = argvSort(*avp, NULL);
2736 if (hitp != NULL)
2737 xx = argiAdd(hitp, -1, rpmmiInstance(mi));
2738 rc++;
2739 }
2740
2741 bottom:
2742 RNhe->p.ptr = _free(RNhe->p.ptr);
2743 REVRhe->p.ptr = _free(REVRhe->p.ptr);
2744 RFhe->p.ptr = _free(RFhe->p.ptr);
2745 NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
2746 }
2747 mi = rpmmiFree(mi);
2748
2749 Pevr = rpmEVRfree(Pevr);
2750
2751 return rc;
2752 }
2753
2754 static int whatneedsTag(Header h, HE_t he)
2755 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2756 /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
2757 {
2758 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
2759 HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
2760 HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
2761 HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
2762 HE_t FNhe = memset(alloca(sizeof(*FNhe)), 0, sizeof(*FNhe));
2763 rpmTag tagNVRA = RPMTAG_NVRA;
2764 ARGV_t pkgs = NULL;
2765 ARGI_t hits = NULL;
2766 int rc = 1;
2767
2768 PNhe->tag = RPMTAG_PROVIDENAME;
2769 if (!headerGet(h, PNhe, 0))
2770 goto exit;
2771 PEVRhe->tag = RPMTAG_PROVIDEVERSION;
2772 if (!headerGet(h, PEVRhe, 0))
2773 goto exit;
2774 assert(PEVRhe->c == PNhe->c);
2775 PFhe->tag = RPMTAG_PROVIDEFLAGS;
2776 if (!headerGet(h, PFhe, 0))
2777 goto exit;
2778 assert(PFhe->c == PNhe->c);
2779
2780 FNhe->tag = RPMTAG_FILEPATHS;
2781 if (!headerGet(h, FNhe, 0))
2782 goto exit;
2783
2784 NVRAhe->tag = tagNVRA;;
2785 if (!headerGet(h, NVRAhe, 0))
2786 goto exit;
2787
2788 (void) argvAdd(&pkgs, NVRAhe->p.str);
2789
2790 for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++)
2791 (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, PNhe, PEVRhe, PFhe);
2792 for (FNhe->ix = 0; FNhe->ix < (int)FNhe->c; FNhe->ix++)
2793 (void) wnlookupTag(h, tagNVRA, &pkgs, &hits, FNhe, NULL, NULL);
2794
2795 /* Convert package NVRA array to Header string array. */
2796 { size_t nb = 0;
2797 char * te;
2798 rpmuint32_t i;
2799
2800 he->t = RPM_STRING_ARRAY_TYPE;
2801 he->c = argvCount(pkgs);
2802 nb = 0;
2803 for (i = 0; i < he->c; i++) {
2804 nb += sizeof(*he->p.argv);
2805 nb += strlen(pkgs[i]) + 1;
2806 }
2807 nb += sizeof(*he->p.argv);
2808
2809 he->p.argv = xmalloc(nb);
2810 te = (char *) &he->p.argv[he->c+1];
2811
2812 for (i = 0; i < he->c; i++) {
2813 he->p.argv[i] = te;
2814 te = stpcpy(te, pkgs[i]);
2815 te++;
2816 }
2817 he->p.argv[he->c] = NULL;
2818 }
2819
2820 hits = argiFree(hits);
2821 pkgs = argvFree(pkgs);
2822 rc = 0;
2823
2824 exit:
2825 NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
2826 PNhe->p.ptr = _free(PNhe->p.ptr);
2827 PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
2828 PFhe->p.ptr = _free(PFhe->p.ptr);
2829 FNhe->p.ptr = _free(FNhe->p.ptr);
2830 return rc;
2831 }
2832
2833 static int nwlookupTag(Header h, rpmTag tagNVRA, ARGV_t *avp, ARGI_t *hitp,
2834 HE_t RNhe, /*@null@*/ HE_t REVRhe, /*@null@*/ HE_t RFhe)
2835 /*@globals rpmGlobalMacroContext, h_errno,
2836 fileSystem, internalState @*/
2837 /*@modifies *avp, *hitp, REVRhe, rpmGlobalMacroContext,
2838 fileSystem, internalState @*/
2839 {
2840 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
2841 HE_t PNhe = memset(alloca(sizeof(*PNhe)), 0, sizeof(*PNhe));
2842 HE_t PEVRhe = memset(alloca(sizeof(*PEVRhe)), 0, sizeof(*PEVRhe));
2843 HE_t PFhe = memset(alloca(sizeof(*PFhe)), 0, sizeof(*PFhe));
2844 rpmdb _rpmdb = (rpmdb) headerGetRpmdb(h);
2845 const char * key = RNhe->p.argv[RNhe->ix];
2846 size_t keylen = 0;
2847 rpmmi mi;
2848 rpmTag tagN = tagN = (*RNhe->p.argv[RNhe->ix] == '/')
2849 ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME;
2850 rpmTag tagEVR = RPMTAG_PROVIDEVERSION;
2851 rpmTag tagF = RPMTAG_PROVIDEFLAGS;
2852 rpmuint32_t PFlags;
2853 rpmuint32_t RFlags;
2854 EVR_t Revr;
2855 Header oh;
2856 int rc = 0;
2857 int xx;
2858
2859 if (tagNVRA == 0)
2860 tagNVRA = RPMTAG_NVRA;
2861
2862 RFlags = (RFhe != NULL ? (RFhe->p.ui32p[RNhe->ix] & RPMSENSE_SENSEMASK) : 0);
2863 Revr = rpmEVRnew(RFlags, 1);
2864
2865 if (REVRhe != NULL)
2866 xx = rpmEVRparse(REVRhe->p.argv[RNhe->ix], Revr);
2867
2868 PNhe->tag = tagN;
2869 PEVRhe->tag = tagEVR;
2870 PFhe->tag = tagF;
2871
2872 mi = rpmmiInit(_rpmdb, tagN, key, keylen);
2873 if (hitp && *hitp)
2874 xx = rpmmiPrune(mi, (int *)argiData(*hitp), argiCount(*hitp), 0);
2875 while ((oh = rpmmiNext(mi)) != NULL) {
2876 if (!headerGet(oh, PNhe, 0))
2877 goto bottom;
2878 if (REVRhe != NULL) {
2879 if (!headerGet(oh, PEVRhe, 0))
2880 goto bottom;
2881 assert(PEVRhe->c == PNhe->c);
2882 if (!headerGet(oh, PFhe, 0))
2883 goto bottom;
2884 assert(PFhe->c == PNhe->c);
2885 }
2886
2887 for (PNhe->ix = 0; PNhe->ix < (int)PNhe->c; PNhe->ix++) {
2888 if (strcmp(RNhe->p.argv[RNhe->ix], PNhe->p.argv[PNhe->ix]))
2889 /*@innercontinue@*/ continue;
2890 if (REVRhe == NULL)
2891 goto bingo;
2892 PFlags = PFhe->p.ui32p[PNhe->ix] & RPMSENSE_SENSEMASK;
2893 { EVR_t Pevr = rpmEVRnew(PFlags, 1);
2894 if (!(PFlags && RFlags))
2895 xx = 1;
2896 else {
2897 xx = rpmEVRparse(PEVRhe->p.argv[PNhe->ix], Pevr);
2898 xx = rpmEVRoverlap(Revr, Pevr);
2899 }
2900 Pevr = rpmEVRfree(Pevr);
2901 }
2902 if (xx)
2903 goto bingo;
2904 }
2905 goto bottom;
2906
2907 bingo:
2908 NVRAhe->tag = tagNVRA;
2909 xx = headerGet(oh, NVRAhe, 0);
2910 if (!(*avp != NULL && argvSearch(*avp, NVRAhe->p.str, NULL) != NULL)) {
2911 xx = argvAdd(avp, NVRAhe->p.str);
2912 xx = argvSort(*avp, NULL);
2913 if (hitp != NULL)
2914 xx = argiAdd(hitp, -1, rpmmiInstance(mi));
2915 rc++;
2916 }
2917
2918 bottom:
2919 PNhe->p.ptr = _free(PNhe->p.ptr);
2920 PEVRhe->p.ptr = _free(PEVRhe->p.ptr);
2921 PFhe->p.ptr = _free(PFhe->p.ptr);
2922 NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
2923 }
2924 mi = rpmmiFree(mi);
2925
2926 Revr = rpmEVRfree(Revr);
2927
2928 return rc;
2929 }
2930
2931 static int needswhatTag(Header h, HE_t he)
2932 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2933 /*@modifies he, rpmGlobalMacroContext, fileSystem, internalState @*/
2934 {
2935 HE_t NVRAhe = memset(alloca(sizeof(*NVRAhe)), 0, sizeof(*NVRAhe));
2936 HE_t RNhe = memset(alloca(sizeof(*RNhe)), 0, sizeof(*RNhe));
2937 HE_t REVRhe = memset(alloca(sizeof(*REVRhe)), 0, sizeof(*REVRhe));
2938 HE_t RFhe = memset(alloca(sizeof(*RFhe)), 0, sizeof(*RFhe));
2939 rpmTag tagNVRA = RPMTAG_NVRA;
2940 ARGV_t pkgs = NULL;
2941 ARGI_t hits = NULL;
2942 int rc = 1;
2943
2944 RNhe->tag = RPMTAG_REQUIRENAME;
2945 if (!headerGet(h, RNhe, 0))
2946 goto exit;
2947 REVRhe->tag = RPMTAG_REQUIREVERSION;
2948 if (!headerGet(h, REVRhe, 0))
2949 goto exit;
2950 assert(REVRhe->c == RNhe->c);
2951 RFhe->tag = RPMTAG_REQUIREFLAGS;
2952 if (!headerGet(h, RFhe, 0))
2953 goto exit;
2954 assert(RFhe->c == RNhe->c);
2955
2956 NVRAhe->tag = tagNVRA;;
2957 if (!headerGet(h, NVRAhe, 0))
2958 goto exit;
2959
2960 (void) argvAdd(&pkgs, NVRAhe->p.str);
2961
2962 for (RNhe->ix = 0; RNhe->ix < (int)RNhe->c; RNhe->ix++) {
2963 if (*RNhe->p.argv[RNhe->ix] == '/' || *REVRhe->p.argv[RNhe->ix] == '\0')
2964 (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, NULL, NULL);
2965 else
2966 (void) nwlookupTag(h, tagNVRA, &pkgs, &hits, RNhe, REVRhe, RFhe);
2967 }
2968
2969 /* Convert package NVRA array to Header string array. */
2970 { size_t nb = 0;
2971 char * te;
2972 rpmuint32_t i;
2973
2974 he->t = RPM_STRING_ARRAY_TYPE;
2975 he->c = argvCount(pkgs);
2976 nb = 0;
2977 for (i = 0; i < he->c; i++) {
2978 nb += sizeof(*he->p.argv);
2979 nb += strlen(pkgs[i]) + 1;
2980 }
2981 nb += sizeof(*he->p.argv);
2982
2983 he->p.argv = xmalloc(nb);
2984 te = (char *) &he->p.argv[he->c+1];
2985
2986 for (i = 0; i < he->c; i++) {
2987 he->p.argv[i] = te;
2988 te = stpcpy(te, pkgs[i]);
2989 te++;
2990 }
2991 he->p.argv[he->c] = NULL;
2992 }
2993
2994 hits = argiFree(hits);
2995 pkgs = argvFree(pkgs);
2996 rc = 0;
2997
2998 exit:
2999 NVRAhe->p.ptr = _free(NVRAhe->p.ptr);
3000 RNhe->p.ptr = _free(RNhe->p.ptr);
3001 REVRhe->p.ptr = _free(REVRhe->p.ptr);
3002 RFhe->p.ptr = _free(RFhe->p.ptr);
3003 return rc;
3004 }
3005
3006 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F,
3007 rpmuint32_t i)
3008 /*@*/
3009 {
3010 int a = -2, b = -2;
3011
3012 if (N.argv[i] == NULL || *N.argv[i] == '\0')
3013 return 1;
3014 if (tag == RPMTAG_REQUIRENAME && i > 0
3015 && !(a=strcmp(N.argv[i], N.argv[i-1]))
3016 && !(b=strcmp(EVR.argv[i], EVR.argv[i-1]))
3017 && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e)))
3018 return 1;
3019 return 0;
3020 }
3021
3022 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3023 /*@globals internalState @*/
3024 /*@modifies he, internalState @*/
3025 {
3026 rpmTag tag = he->tag;
3027 rpmTagData N = { .ptr = NULL };
3028 rpmTagData EVR = { .ptr = NULL };
3029 rpmTagData F = { .ptr = NULL };
3030 size_t nb;
3031 rpmuint32_t ac;
3032 rpmuint32_t c;
3033 rpmuint32_t i;
3034 char *t;
3035 int rc = 1; /* assume failure */
3036 int xx;
3037
3038 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3039 xx = headerGet(h, he, 0);
3040 if (xx == 0) goto exit;
3041 N.argv = he->p.argv;
3042 c = he->c;
3043
3044 he->tag = EVRtag;
3045 xx = headerGet(h, he, 0);
3046 if (xx == 0) goto exit;
3047 EVR.argv = he->p.argv;
3048
3049 he->tag = Ftag;
3050 xx = headerGet(h, he, 0);
3051 if (xx == 0) goto exit;
3052 F.ui32p = he->p.ui32p;
3053
3054 nb = sizeof(*he->p.argv);
3055 ac = 0;
3056 for (i = 0; i < c; i++) {
3057 /*@-nullstate@*/ /* EVR.argv might be NULL */
3058 if (PRCOSkip(tag, N, EVR, F, i))
3059 continue;
3060 /*@=nullstate@*/
3061 ac++;
3062 nb += sizeof(*he->p.argv);
3063 nb += sizeof("<rpm:entry name=\"\"/>");
3064 if (*N.argv[i] == '/')
3065 nb += xmlstrlen(N.argv[i]);
3066 else
3067 nb += strlen(N.argv[i]);
3068 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3069 nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1;
3070 nb += strlen(EVR.argv[i]);
3071 if (strchr(EVR.argv[i], ':') != NULL)
3072 nb -= 2;
3073 if (strchr(EVR.argv[i], '-') != NULL)
3074 nb += sizeof(" rel=\"\"") - 2;
3075 }
3076 #ifdef NOTNOW
3077 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3078 nb += sizeof(" pre=\"1\"") - 1;
3079 #endif
3080 }
3081
3082 he->t = RPM_STRING_ARRAY_TYPE;
3083 he->c = ac;
3084 he->freeData = 1;
3085 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3086 t = (char *) &he->p.argv[he->c + 1];
3087 ac = 0;
3088 for (i = 0; i < c; i++) {
3089 /*@-nullstate@*/ /* EVR.argv might be NULL */
3090 if (PRCOSkip(tag, N, EVR, F, i))
3091 continue;
3092 /*@=nullstate@*/
3093 he->p.argv[ac++] = t;
3094 t = stpcpy(t, "<rpm:entry");
3095 t = stpcpy(t, " name=\"");
3096 if (*N.argv[i] == '/') {
3097 t = xmlstrcpy(t, N.argv[i]); t += strlen(t);
3098 } else
3099 t = stpcpy(t, N.argv[i]);
3100 t = stpcpy(t, "\"");
3101 /*@-readonlytrans@*/
3102 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3103 static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
3104 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3105 const char *E, *V, *R;
3106 char *f, *fe;
3107 t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\"");
3108 f = (char *) EVR.argv[i];
3109 for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++)
3110 {};
3111 if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
3112 V = f;
3113 for (fe = f; *fe != '\0' && *fe != '-'; fe++)
3114 {};
3115 if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
3116 t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\"");
3117 t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\"");
3118 if (R != NULL)
3119 t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\"");
3120 }
3121 /*@=readonlytrans@*/
3122 #ifdef NOTNOW
3123 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3124 t = stpcpy(t, " pre=\"1\"");
3125 #endif
3126 t = stpcpy(t, "/>");
3127 *t++ = '\0';
3128 }
3129 he->p.argv[he->c] = NULL;
3130 /*@=compmempass@*/
3131 rc = 0;
3132
3133 exit:
3134 /*@-kepttrans@*/ /* N.argv may be kept. */
3135 N.argv = _free(N.argv);
3136 /*@=kepttrans@*/
3137 /*@-usereleased@*/ /* EVR.argv may be dead. */
3138 EVR.argv = _free(EVR.argv);
3139 /*@=usereleased@*/
3140 F.ui32p = _free(F.ui32p);
3141 return rc;
3142 }
3143
3144 static int PxmlTag(Header h, HE_t he)
3145 /*@globals internalState @*/
3146 /*@modifies he, internalState @*/
3147 {
3148 he->tag = RPMTAG_PROVIDENAME;
3149 return PRCOxmlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
3150 }
3151
3152 static int RxmlTag(Header h, HE_t he)
3153 /*@globals internalState @*/
3154 /*@modifies he, internalState @*/
3155 {
3156 he->tag = RPMTAG_REQUIRENAME;
3157 return PRCOxmlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
3158 }
3159
3160 static int CxmlTag(Header h, HE_t he)
3161 /*@globals internalState @*/
3162 /*@modifies he, internalState @*/
3163 {
3164 he->tag = RPMTAG_CONFLICTNAME;
3165 return PRCOxmlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
3166 }
3167
3168 static int OxmlTag(Header h, HE_t he)
3169 /*@globals internalState @*/
3170 /*@modifies he, internalState @*/
3171 {
3172 he->tag = RPMTAG_OBSOLETENAME;
3173 return PRCOxmlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
3174 }
3175
3181 static size_t sqlstrlen(const char * s)
3182 /*@*/
3183 {
3184 size_t len = 0;
3185 int c;
3186
3187 while ((c = (int) *s++) != (int) '\0') {
3188 switch (c) {
3189 case '\'': len += 1; /*@fallthrough@*/
3190 default: len += 1; /*@switchbreak@*/ break;
3191 }
3192 }
3193 return len;
3194 }
3195
3202 static char * sqlstrcpy(/*@returned@*/ char * t, const char * s)
3203 /*@modifies t @*/
3204 {
3205 char * te = t;
3206 int c;
3207
3208 while ((c = (int) *s++) != (int) '\0') {
3209 switch (c) {
3210 case '\'': *te++ = (char) c; /*@fallthrough@*/
3211 default: *te++ = (char) c; /*@switchbreak@*/ break;
3212 }
3213 }
3214 *te = '\0';
3215 return t;
3216 }
3217
3224 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av)
3225 /*@*/
3226 {
3227 int ix = (he->ix > 0 ? he->ix : 0);
3228 char * val;
3229
3230 assert(ix == 0);
3231 if (he->t != RPM_STRING_TYPE) {
3232 val = xstrdup(_("(not a string)"));
3233 } else {
3234 const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
3235 size_t nb;
3236 char * t;
3237
3238 if (s == NULL) {
3239 /* XXX better error msg? */
3240 val = xstrdup(_("(not a string)"));
3241 goto exit;
3242 }
3243
3244 nb = sqlstrlen(s);
3245 val = t = xcalloc(1, nb + 1);
3246 t = sqlstrcpy(t, s); t += strlen(t);
3247 *t = '\0';
3248 s = _free(s);
3249 }
3250
3251 exit:
3252 return val;
3253 }
3254
3255 /*@-compmempass -kepttrans -nullstate -usereleased @*/
3256 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3257 /*@globals internalState @*/
3258 /*@modifies he, internalState @*/
3259 {
3260 rpmTag tag = he->tag;
3261 rpmTagData N = { .ptr = NULL };
3262 rpmTagData EVR = { .ptr = NULL };
3263 rpmTagData F = { .ptr = NULL };
3264 char instance[64];
3265 size_t nb;
3266 rpmuint32_t ac;
3267 rpmuint32_t c;
3268 rpmuint32_t i;
3269 char *t;
3270 int rc = 1; /* assume failure */
3271 int xx;
3272
3273 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3274 xx = headerGet(h, he, 0);
3275 if (xx == 0) goto exit;
3276 N.argv = he->p.argv;
3277 c = he->c;
3278
3279 he->tag = EVRtag;
3280 xx = headerGet(h, he, 0);
3281 if (xx == 0) goto exit;
3282 EVR.argv = he->p.argv;
3283
3284 he->tag = Ftag;
3285 xx = headerGet(h, he, 0);
3286 if (xx == 0) goto exit;
3287 F.ui32p = he->p.ui32p;
3288
3289 xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
3290 nb = sizeof(*he->p.argv);
3291 ac = 0;
3292 for (i = 0; i < c; i++) {
3293 /*@-nullstate@*/ /* EVR.argv might be NULL */
3294 if (PRCOSkip(tag, N, EVR, F, i))
3295 continue;
3296 /*@=nullstate@*/
3297 ac++;
3298 nb += sizeof(*he->p.argv);
3299 nb += strlen(instance) + sizeof(", '', '', '', '', ''");
3300 if (tag == RPMTAG_REQUIRENAME)
3301 nb += sizeof(", ''") - 1;
3302 nb += strlen(N.argv[i]);
3303 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3304 nb += strlen(EVR.argv[i]);
3305 nb += sizeof("EQ0") - 1;
3306 }
3307 #ifdef NOTNOW
3308 if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
3309 nb += sizeof("1") - 1;
3310 #endif
3311 }
3312
3313 he->t = RPM_STRING_ARRAY_TYPE;
3314 he->c = ac;
3315 he->freeData = 1;
3316 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3317 t = (char *) &he->p.argv[he->c + 1];
3318 ac = 0;
3319 for (i = 0; i < c; i++) {
3320 /*@-nullstate@*/ /* EVR.argv might be NULL */
3321 if (PRCOSkip(tag, N, EVR, F, i))
3322 continue;
3323 /*@=nullstate@*/
3324 he->p.argv[ac++] = t;
3325 t = stpcpy(t, instance);
3326 t = stpcpy( stpcpy( stpcpy(t, ", '"), N.argv[i]), "'");
3327 /*@-readonlytrans@*/
3328 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3329 static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
3330 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3331 const char *E, *V, *R;
3332 char *f, *fe;
3333 t = stpcpy( stpcpy( stpcpy(t, ", '"), Fstr[Fx]), "'");
3334 f = (char *) EVR.argv[i];
3335 for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++)
3336 {};
3337 if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
3338 V = f;
3339 for (fe = f; *fe != '\0' && *fe != '-'; fe++)
3340 {};
3341 if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
3342 t = stpcpy( stpcpy( stpcpy(t, ", '"), (E && *E ? E : "0")), "'");
3343 t = stpcpy( stpcpy( stpcpy(t, ", '"), V), "'");
3344 t = stpcpy( stpcpy( stpcpy(t, ", '"), (R ? R : "")), "'");
3345 } else
3346 t = stpcpy(t, ", '', '', '', ''");
3347 /*@=readonlytrans@*/
3348 #ifdef NOTNOW
3349 if (tag == RPMTAG_REQUIRENAME)
3350 t = stpcpy(stpcpy(stpcpy(t, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'");
3351 #endif
3352 *t++ = '\0';
3353 }
3354 he->p.argv[he->c] = NULL;
3355 /*@=compmempass@*/
3356 rc = 0;
3357
3358 exit:
3359 /*@-kepttrans@*/ /* N.argv may be kept. */
3360 N.argv = _free(N.argv);
3361 /*@=kepttrans@*/
3362 /*@-usereleased@*/ /* EVR.argv may be dead. */
3363 EVR.argv = _free(EVR.argv);
3364 /*@=usereleased@*/
3365 F.ui32p = _free(F.ui32p);
3366 return rc;
3367 }
3368
3369 static int PsqlTag(Header h, HE_t he)
3370 /*@globals internalState @*/
3371 /*@modifies he, internalState @*/
3372 {
3373 he->tag = RPMTAG_PROVIDENAME;
3374 return PRCOsqlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
3375 }
3376
3377 static int RsqlTag(Header h, HE_t he)
3378 /*@globals internalState @*/
3379 /*@modifies he, internalState @*/
3380 {
3381 he->tag = RPMTAG_REQUIRENAME;
3382 return PRCOsqlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
3383 }
3384
3385 static int CsqlTag(Header h, HE_t he)
3386 /*@globals internalState @*/
3387 /*@modifies he, internalState @*/
3388 {
3389 he->tag = RPMTAG_CONFLICTNAME;
3390 return PRCOsqlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
3391 }
3392
3393 static int OsqlTag(Header h, HE_t he)
3394 /*@globals internalState @*/
3395 /*@modifies he, internalState @*/
3396 {
3397 he->tag = RPMTAG_OBSOLETENAME;
3398 return PRCOsqlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
3399 }
3400
3401 static int PRCOyamlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
3402 /*@globals internalState @*/
3403 /*@modifies he, internalState @*/
3404 {
3405 rpmTag tag = he->tag;
3406 rpmTagData N = { .ptr = NULL };
3407 rpmTagData EVR = { .ptr = NULL };
3408 rpmTagData F = { .ptr = NULL };
3409 size_t nb;
3410 rpmuint32_t ac;
3411 rpmuint32_t c;
3412 rpmuint32_t i;
3413 char *t;
3414 int rc = 1; /* assume failure */
3415 int indent = 0;
3416 int xx;
3417
3418 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3419 xx = headerGet(h, he, 0);
3420 if (xx == 0) goto exit;
3421 N.argv = he->p.argv;
3422 c = he->c;
3423
3424 he->tag = EVRtag;
3425 xx = headerGet(h, he, 0);
3426 if (xx == 0) goto exit;
3427 EVR.argv = he->p.argv;
3428
3429 he->tag = Ftag;
3430 xx = headerGet(h, he, 0);
3431 if (xx == 0) goto exit;
3432 F.ui32p = he->p.ui32p;
3433
3434 nb = sizeof(*he->p.argv);
3435 ac = 0;
3436 for (i = 0; i < c; i++) {
3437 /*@-nullstate@*/ /* EVR.argv might be NULL */
3438 if (PRCOSkip(tag, N, EVR, F, i))
3439 continue;
3440 /*@=nullstate@*/
3441 ac++;
3442 nb += sizeof(*he->p.argv);
3443 nb += sizeof("- ");
3444 if (*N.argv[i] == '/')
3445 nb += yamlstrlen(N.argv[i], indent);
3446 else
3447 nb += strlen(N.argv[i]);
3448 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3449 nb += sizeof(" >= ") - 1;
3450 nb += strlen(EVR.argv[i]);
3451 }
3452 }
3453
3454 he->t = RPM_STRING_ARRAY_TYPE;
3455 he->c = ac;
3456 he->freeData = 1;
3457 he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
3458 t = (char *) &he->p.argv[he->c + 1];
3459 ac = 0;
3460 for (i = 0; i < c; i++) {
3461 /*@-nullstate@*/ /* EVR.argv might be NULL */
3462 if (PRCOSkip(tag, N, EVR, F, i))
3463 continue;
3464 /*@=nullstate@*/
3465 he->p.argv[ac++] = t;
3466 t = stpcpy(t, "- ");
3467 if (*N.argv[i] == '/') {
3468 t = yamlstrcpy(t, N.argv[i], indent); t += strlen(t);
3469 } else
3470 t = stpcpy(t, N.argv[i]);
3471 /*@-readonlytrans@*/
3472 if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
3473 static char *Fstr[] = { "?0","<",">","?3","=","<=",">=","?7" };
3474 rpmuint32_t Fx = ((F.ui32p[i] >> 1) & 0x7);
3475 t = stpcpy( stpcpy( stpcpy(t, " "), Fstr[Fx]), " ");
3476 t = stpcpy(t, EVR.argv[i]);
3477 }
3478 /*@=readonlytrans@*/
3479 *t++ = '\0';
3480 }
3481 he->p.argv[he->c] = NULL;
3482 /*@=compmempass@*/
3483 rc = 0;
3484
3485 exit:
3486 /*@-kepttrans@*/ /* N.argv may be kept. */
3487 N.argv = _free(N.argv);
3488 /*@=kepttrans@*/
3489 /*@-usereleased@*/ /* EVR.argv may be dead. */
3490 EVR.argv = _free(EVR.argv);
3491 /*@=usereleased@*/
3492 F.ui32p = _free(F.ui32p);
3493 return rc;
3494 }
3495
3496 static int PyamlTag(Header h, HE_t he)
3497 /*@globals internalState @*/
3498 /*@modifies he, internalState @*/
3499 {
3500 he->tag = RPMTAG_PROVIDENAME;
3501 return PRCOyamlTag(h, he, RPMTAG_PROVIDEVERSION, RPMTAG_PROVIDEFLAGS);
3502 }
3503
3504 static int RyamlTag(Header h, HE_t he)
3505 /*@globals internalState @*/
3506 /*@modifies he, internalState @*/
3507 {
3508 he->tag = RPMTAG_REQUIRENAME;
3509 return PRCOyamlTag(h, he, RPMTAG_REQUIREVERSION, RPMTAG_REQUIREFLAGS);
3510 }
3511
3512 static int CyamlTag(Header h, HE_t he)
3513 /*@globals internalState @*/
3514 /*@modifies he, internalState @*/
3515 {
3516 he->tag = RPMTAG_CONFLICTNAME;
3517 return PRCOyamlTag(h, he, RPMTAG_CONFLICTVERSION, RPMTAG_CONFLICTFLAGS);
3518 }
3519
3520 static int OyamlTag(Header h, HE_t he)
3521 /*@globals internalState @*/
3522 /*@modifies he, internalState @*/
3523 {
3524 he->tag = RPMTAG_OBSOLETENAME;
3525 return PRCOyamlTag(h, he, RPMTAG_OBSOLETEVERSION, RPMTAG_OBSOLETEFLAGS);
3526 }
3527
3528 static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, rpmuint32_t i)
3529 /*@*/
3530 {
3531 const char * dn = DN.argv[DI.ui32p[i]];
3532 size_t dnlen = strlen(dn);
3533
3534 assert(dn != NULL);
3535 if (strstr(dn, "bin/") != NULL)
3536 return 1;
3537 if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen))
3538 return 1;
3539 if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail"))
3540 return 1;
3541 return 2;
3542 }
3543
3544 static int FDGxmlTag(Header h, HE_t he, int lvl)
3545 /*@globals internalState @*/
3546 /*@modifies he, internalState @*/
3547 {
3548 rpmTagData BN = { .ptr = NULL };
3549 rpmTagData DN = { .ptr = NULL };
3550 rpmTagData DI = { .ptr = NULL };
3551 rpmTagData FMODES = { .ptr = NULL };
3552 rpmTagData FFLAGS = { .ptr = NULL };
3553 size_t nb;
3554 rpmuint32_t ac;
3555 rpmuint32_t c;
3556 rpmuint32_t i;
3557 char *t;
3558 int rc = 1; /* assume failure */
3559 int xx;
3560
3561 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3562 he->tag = RPMTAG_BASENAMES;
3563 xx = headerGet(h, he, 0);
3564 if (xx == 0) goto exit;
3565 BN.argv = he->p.argv;
3566 c = he->c;
3567
3568 he->tag = RPMTAG_DIRNAMES;
3569 xx = headerGet(h, he, 0);
3570 if (xx == 0) goto exit;
3571 DN.argv = he->p.argv;
3572
3573 he->tag = RPMTAG_DIRINDEXES;
3574 xx = headerGet(h, he, 0);
3575 if (xx == 0) goto exit;
3576 DI.ui32p = he->p.ui32p;
3577
3578 he->tag = RPMTAG_FILEMODES;
3579 xx = headerGet(h, he, 0);
3580 if (xx == 0) goto exit;
3581 FMODES.ui16p = he->p.ui16p;
3582
3583 he->tag = RPMTAG_FILEFLAGS;
3584 xx = headerGet(h, he, 0);
3585 if (xx == 0) goto exit;
3586 FFLAGS.ui32p = he->p.ui32p;
3587
3588 nb = sizeof(*he->p.argv);
3589 ac = 0;
3590 for (i = 0; i < c; i++) {
3591 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3592 continue;
3593 ac++;
3594 nb += sizeof(*he->p.argv);
3595 nb += sizeof("<file></file>");
3596 nb += xmlstrlen(DN.argv[DI.ui32p[i]]);
3597 nb += xmlstrlen(BN.argv[i]);
3598 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3599 nb += sizeof(" type=\"ghost\"") - 1;
3600 else if (S_ISDIR(FMODES.ui16p[i])) {
3601 nb += sizeof(" type=\"dir\"") - 1;
3602 #ifdef NOTYET
3603 nb += sizeof("/") - 1;
3604 #endif
3605 }
3606 }
3607
3608 he->t = RPM_STRING_ARRAY_TYPE;
3609 he->c = ac;
3610 he->freeData = 1;
3611 he->p.argv = xmalloc(nb);
3612 t = (char *) &he->p.argv[he->c + 1];
3613 ac = 0;
3614 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
3615 for (i = 0; i < c; i++) {
3616 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3617 continue;
3618 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3619 continue;
3620 if (S_ISDIR(FMODES.ui16p[i]))
3621 continue;
3622 he->p.argv[ac++] = t;
3623 t = stpcpy(t, "<file>");
3624 t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
3625 t = xmlstrcpy(t, BN.argv[i]); t += strlen(t);
3626 t = stpcpy(t, "</file>");
3627 *t++ = '\0';
3628 }
3629 for (i = 0; i < c; i++) {
3630 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3631 continue;
3632 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3633 continue;
3634 if (!S_ISDIR(FMODES.ui16p[i]))
3635 continue;
3636 he->p.argv[ac++] = t;
3637 t = stpcpy(t, "<file type=\"dir\">");
3638 t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
3639 t = xmlstrcpy(t, BN.argv[i]); t += strlen(t);
3640 #ifdef NOTYET
3641 /* Append the pesky trailing / to directories. */
3642 if (t[-1] != '/')
3643 t = stpcpy(t, "/");
3644 #endif
3645 t = stpcpy(t, "</file>");
3646 *t++ = '\0';
3647 }
3648 for (i = 0; i < c; i++) {
3649 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3650 continue;
3651 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
3652 continue;
3653 he->p.argv[ac++] = t;
3654 t = stpcpy(t, "<file type=\"ghost\">");
3655 t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
3656 t = xmlstrcpy(t, BN.argv[i]); t += strlen(t);
3657 t = stpcpy(t, "</file>");
3658 *t++ = '\0';
3659 }
3660
3661 he->p.argv[he->c] = NULL;
3662 /*@=compmempass@*/
3663 rc = 0;
3664
3665 exit:
3666 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
3667 BN.argv = _free(BN.argv);
3668 /*@-usereleased@*/ /* DN.argv may be dead. */
3669 DN.argv = _free(DN.argv);
3670 /*@=usereleased@*/
3671 DI.ui32p = _free(DI.ui32p);
3672 /*@=kepttrans@*/
3673 FMODES.ui16p = _free(FMODES.ui16p);
3674 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
3675 FFLAGS.ui32p = _free(FFLAGS.ui32p);
3676 /*@=usereleased@*/
3677 return rc;
3678 }
3679
3680 static int F1xmlTag(Header h, HE_t he)
3681 /*@globals internalState @*/
3682 /*@modifies he, internalState @*/
3683 {
3684 he->tag = RPMTAG_BASENAMES;
3685 return FDGxmlTag(h, he, 1);
3686 }
3687
3688 static int F2xmlTag(Header h, HE_t he)
3689 /*@globals internalState @*/
3690 /*@modifies he, internalState @*/
3691 {
3692 he->tag = RPMTAG_BASENAMES;
3693 return FDGxmlTag(h, he, 2);
3694 }
3695
3696 static int FDGsqlTag(Header h, HE_t he, int lvl)
3697 /*@globals internalState @*/
3698 /*@modifies he, internalState @*/
3699 {
3700 rpmTagData BN = { .ptr = NULL };
3701 rpmTagData DN = { .ptr = NULL };
3702 rpmTagData DI = { .ptr = NULL };
3703 rpmTagData FMODES = { .ptr = NULL };
3704 rpmTagData FFLAGS = { .ptr = NULL };
3705 char instance[64];
3706 size_t nb;
3707 rpmuint32_t ac;
3708 rpmuint32_t c;
3709 rpmuint32_t i;
3710 char *t;
3711 int rc = 1; /* assume failure */
3712 int xx;
3713
3714 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3715 he->tag = RPMTAG_BASENAMES;
3716 xx = headerGet(h, he, 0);
3717 if (xx == 0) goto exit;
3718 BN.argv = he->p.argv;
3719 c = he->c;
3720
3721 he->tag = RPMTAG_DIRNAMES;
3722 xx = headerGet(h, he, 0);
3723 if (xx == 0) goto exit;
3724 DN.argv = he->p.argv;
3725
3726 he->tag = RPMTAG_DIRINDEXES;
3727 xx = headerGet(h, he, 0);
3728 if (xx == 0) goto exit;
3729 DI.ui32p = he->p.ui32p;
3730
3731 he->tag = RPMTAG_FILEMODES;
3732 xx = headerGet(h, he, 0);
3733 if (xx == 0) goto exit;
3734 FMODES.ui16p = he->p.ui16p;
3735
3736 he->tag = RPMTAG_FILEFLAGS;
3737 xx = headerGet(h, he, 0);
3738 if (xx == 0) goto exit;
3739 FFLAGS.ui32p = he->p.ui32p;
3740
3741 xx = snprintf(instance, sizeof(instance), "'%u'", (unsigned)headerGetInstance(h));
3742 nb = sizeof(*he->p.argv);
3743 ac = 0;
3744 for (i = 0; i < c; i++) {
3745 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3746 continue;
3747 ac++;
3748 nb += sizeof(*he->p.argv);
3749 nb += strlen(instance) + sizeof(", '', ''");
3750 nb += strlen(DN.argv[DI.ui32p[i]]);
3751 nb += strlen(BN.argv[i]);
3752 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3753 nb += sizeof("ghost") - 1;
3754 else if (S_ISDIR(FMODES.ui16p[i])) {
3755 nb += sizeof("dir") - 1;
3756 #ifdef NOTYET
3757 nb += sizeof("/") - 1;
3758 #endif
3759 } else
3760 nb += sizeof("file") - 1;
3761 }
3762
3763 he->t = RPM_STRING_ARRAY_TYPE;
3764 he->c = ac;
3765 he->freeData = 1;
3766 he->p.argv = xmalloc(nb);
3767 t = (char *) &he->p.argv[he->c + 1];
3768 ac = 0;
3769 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
3770 for (i = 0; i < c; i++) {
3771 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3772 continue;
3773 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3774 continue;
3775 if (S_ISDIR(FMODES.ui16p[i]))
3776 continue;
3777 he->p.argv[ac++] = t;
3778 t = stpcpy( stpcpy(t, instance), ", '");
3779 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
3780 t = strcpy(t, BN.argv[i]); t += strlen(t);
3781 t = stpcpy(t, "', 'file'");
3782 *t++ = '\0';
3783 }
3784 for (i = 0; i < c; i++) {
3785 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3786 continue;
3787 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3788 continue;
3789 if (!S_ISDIR(FMODES.ui16p[i]))
3790 continue;
3791 he->p.argv[ac++] = t;
3792 t = stpcpy( stpcpy(t, instance), ", '");
3793 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
3794 t = strcpy(t, BN.argv[i]); t += strlen(t);
3795 #ifdef NOTYET
3796 /* Append the pesky trailing / to directories. */
3797 if (t[-1] != '/')
3798 t = stpcpy(t, "/");
3799 #endif
3800 t = stpcpy(t, "', 'dir'");
3801 *t++ = '\0';
3802 }
3803 for (i = 0; i < c; i++) {
3804 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3805 continue;
3806 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
3807 continue;
3808 he->p.argv[ac++] = t;
3809 t = stpcpy( stpcpy(t, instance), ", '");
3810 t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
3811 t = strcpy(t, BN.argv[i]); t += strlen(t);
3812 t = stpcpy(t, "', 'ghost'");
3813 *t++ = '\0';
3814 }
3815
3816 he->p.argv[he->c] = NULL;
3817 /*@=compmempass@*/
3818 rc = 0;
3819
3820 exit:
3821 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
3822 BN.argv = _free(BN.argv);
3823 /*@-usereleased@*/ /* DN.argv may be dead. */
3824 DN.argv = _free(DN.argv);
3825 /*@=usereleased@*/
3826 DI.ui32p = _free(DI.ui32p);
3827 /*@=kepttrans@*/
3828 FMODES.ui16p = _free(FMODES.ui16p);
3829 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
3830 FFLAGS.ui32p = _free(FFLAGS.ui32p);
3831 /*@=usereleased@*/
3832 return rc;
3833 }
3834
3835 static int F1sqlTag(Header h, HE_t he)
3836 /*@globals internalState @*/
3837 /*@modifies he, internalState @*/
3838 {
3839 he->tag = RPMTAG_BASENAMES;
3840 return FDGsqlTag(h, he, 1);
3841 }
3842
3843 static int F2sqlTag(Header h, HE_t he)
3844 /*@globals internalState @*/
3845 /*@modifies he, internalState @*/
3846 {
3847 he->tag = RPMTAG_BASENAMES;
3848 return FDGsqlTag(h, he, 2);
3849 }
3850
3851 static int FDGyamlTag(Header h, HE_t he, int lvl)
3852 /*@globals internalState @*/
3853 /*@modifies he, internalState @*/
3854 {
3855 rpmTagData BN = { .ptr = NULL };
3856 rpmTagData DN = { .ptr = NULL };
3857 rpmTagData DI = { .ptr = NULL };
3858 rpmTagData FMODES = { .ptr = NULL };
3859 rpmTagData FFLAGS = { .ptr = NULL };
3860 size_t nb;
3861 rpmuint32_t ac;
3862 rpmuint32_t c;
3863 rpmuint32_t i;
3864 char *t;
3865 int rc = 1; /* assume failure */
3866 int indent = 0;
3867 int xx;
3868
3869 /*@-compmempass@*/ /* use separate HE_t, not rpmTagData, containers. */
3870 he->tag = RPMTAG_BASENAMES;
3871 xx = headerGet(h, he, 0);
3872 if (xx == 0) goto exit;
3873 BN.argv = he->p.argv;
3874 c = he->c;
3875
3876 he->tag = RPMTAG_DIRNAMES;
3877 xx = headerGet(h, he, 0);
3878 if (xx == 0) goto exit;
3879 DN.argv = he->p.argv;
3880
3881 he->tag = RPMTAG_DIRINDEXES;
3882 xx = headerGet(h, he, 0);
3883 if (xx == 0) goto exit;
3884 DI.ui32p = he->p.ui32p;
3885
3886 he->tag = RPMTAG_FILEMODES;
3887 xx = headerGet(h, he, 0);
3888 if (xx == 0) goto exit;
3889 FMODES.ui16p = he->p.ui16p;
3890
3891 he->tag = RPMTAG_FILEFLAGS;
3892 xx = headerGet(h, he, 0);
3893 if (xx == 0) goto exit;
3894 FFLAGS.ui32p = he->p.ui32p;
3895
3896 nb = sizeof(*he->p.argv);
3897 ac = 0;
3898 for (i = 0; i < c; i++) {
3899 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3900 continue;
3901 ac++;
3902 nb += sizeof(*he->p.argv);
3903 nb += sizeof("- ");
3904 nb += yamlstrlen(DN.argv[DI.ui32p[i]], indent);
3905 nb += yamlstrlen(BN.argv[i], indent);
3906 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3907 nb += sizeof("") - 1;
3908 else if (S_ISDIR(FMODES.ui16p[i]))
3909 nb += sizeof("/") - 1;
3910 }
3911
3912 he->t = RPM_STRING_ARRAY_TYPE;
3913 he->c = ac;
3914 he->freeData = 1;
3915 he->p.argv = xmalloc(nb);
3916 t = (char *) &he->p.argv[he->c + 1];
3917 ac = 0;
3918 /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
3919 for (i = 0; i < c; i++) {
3920 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3921 continue;
3922 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3923 continue;
3924 if (S_ISDIR(FMODES.ui16p[i]))
3925 continue;
3926 he->p.argv[ac++] = t;
3927 t = stpcpy(t, "- ");
3928 t = yamlstrcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
3929 t = yamlstrcpy(t, BN.argv[i], indent); t += strlen(t);
3930 t = stpcpy(t, "");
3931 *t++ = '\0';
3932 }
3933 for (i = 0; i < c; i++) {
3934 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3935 continue;
3936 if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
3937 continue;
3938 if (!S_ISDIR(FMODES.ui16p[i]))
3939 continue;
3940 he->p.argv[ac++] = t;
3941 t = stpcpy(t, "- ");
3942 t = yamlstrcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
3943 t = yamlstrcpy(t, BN.argv[i], indent); t += strlen(t);
3944 /* Append the pesky trailing / to directories. */
3945 if (t[-1] != '/')
3946 t = stpcpy(t, "/");
3947 *t++ = '\0';
3948 }
3949 for (i = 0; i < c; i++) {
3950 if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
3951 continue;
3952 if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
3953 continue;
3954 he->p.argv[ac++] = t;
3955 t = stpcpy(t, "- ");
3956 t = yamlstrcpy(t, DN.argv[DI.ui32p[i]], indent); t += strlen(t);
3957 t = yamlstrcpy(t, BN.argv[i], indent); t += strlen(t);
3958 *t++ = '\0';
3959 }
3960
3961 he->p.argv[he->c] = NULL;
3962 /*@=compmempass@*/
3963 rc = 0;
3964
3965 exit:
3966 /*@-kepttrans@*/ /* {BN,DN,DI}.argv may be kept. */
3967 BN.argv = _free(BN.argv);
3968 /*@-usereleased@*/ /* DN.argv may be dead. */
3969 DN.argv = _free(DN.argv);
3970 /*@=usereleased@*/
3971 DI.ui32p = _free(DI.ui32p);
3972 /*@=kepttrans@*/
3973 FMODES.ui16p = _free(FMODES.ui16p);
3974 /*@-usereleased@*/ /* FFLAGS.argv may be dead. */
3975 FFLAGS.ui32p = _free(FFLAGS.ui32p);
3976 /*@=usereleased@*/
3977 return rc;
3978 }
3979
3980 static int F1yamlTag(Header h, HE_t he)
3981 /*@globals internalState @*/
3982 /*@modifies he, internalState @*/
3983 {
3984 he->tag = RPMTAG_BASENAMES;
3985 return FDGyamlTag(h, he, 1);
3986 }
3987
3988 static int F2yamlTag(Header h, HE_t he)
3989 /*@globals internalState @*/
3990 /*@modifies he, internalState @*/
3991 {
3992 he->tag = RPMTAG_BASENAMES;
3993 return FDGyamlTag(h, he, 2);
3994 }
3995
4002 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av)
4003 /*@*/
4004 {
4005 char * val;
4006
4007 if (he->t != RPM_STRING_TYPE) {
4008 val = xstrdup(_("(not a string)"));
4009 } else {
4010 const char * bn;
4011 const char * s;
4012 size_t nb;
4013 char * t;
4014
4015 assert(he->p.str != NULL);
4016 /* Get rightmost '/' in string (i.e. basename(3) behavior). */
4017 if ((bn = strrchr(he->p.str, '/')) != NULL)
4018 bn++;
4019 else
4020 bn = he->p.str;
4021
4022 /* Convert to utf8, escape for XML CDATA. */
4023 s = strdup_locale_convert(bn, (av ? av[0] : NULL));
4024 if (s == NULL) {
4025 /* XXX better error msg? */
4026 val = xstrdup(_("(not a string)"));
4027 goto exit;
4028 }
4029
4030 nb = xmlstrlen(s);
4031 val = t = xcalloc(1, nb + 1);
4032 t = xmlstrcpy(t, s); t += strlen(t);
4033 *t = '\0';
4034 s = _free(s);
4035 }
4036
4037 exit:
4038 return val;
4039 }
4040
4041 typedef struct key_s {
4042 /*@observer@*/
4043 const char *name; /* key name */
4044 rpmuint32_t value;
4045 } KEY;
4046
4047 /*@unchecked@*/ /*@observer@*/
4048 static KEY keyDigests[] = {
4049 { "adler32", PGPHASHALGO_ADLER32 },
4050 { "crc32", PGPHASHALGO_CRC32 },
4051 { "crc64", PGPHASHALGO_CRC64 },
4052 { "haval160", PGPHASHALGO_HAVAL_5_160 },
4053 { "jlu32", PGPHASHALGO_JLU32 },
4054 { "md2", PGPHASHALGO_MD2 },
4055 { "md4", PGPHASHALGO_MD4 },
4056 { "md5", PGPHASHALGO_MD5 },
4057 { "rmd128", PGPHASHALGO_RIPEMD128 },
4058 { "rmd160", PGPHASHALGO_RIPEMD160 },
4059 { "rmd256", PGPHASHALGO_RIPEMD256 },
4060 { "rmd320", PGPHASHALGO_RIPEMD320 },
4061 { "salsa10", PGPHASHALGO_SALSA10 },
4062 { "salsa20", PGPHASHALGO_SALSA20 },
4063 { "sha1", PGPHASHALGO_SHA1 },
4064 { "sha224", PGPHASHALGO_SHA224 },
4065 { "sha256", PGPHASHALGO_SHA256 },
4066 { "sha384", PGPHASHALGO_SHA384 },
4067 { "sha512", PGPHASHALGO_SHA512 },
4068 { "tiger192", PGPHASHALGO_TIGER192 },
4069 };
4070 /*@unchecked@*/
4071 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]);
4072
4076 enum keyStat_e {
4077 STAT_KEYS_NONE = 0,
4078 STAT_KEYS_DEV = (1U << 0),
4079 STAT_KEYS_INO = (1U << 1),
4080 STAT_KEYS_MODE = (1U << 2),
4081 STAT_KEYS_NLINK = (1U << 3),
4082 STAT_KEYS_UID = (1U << 4),
4083 STAT_KEYS_GID = (1U << 5),
4084 STAT_KEYS_RDEV = (1U << 6),
4085 STAT_KEYS_SIZE = (1U << 7),
4086 STAT_KEYS_BLKSIZE = (1U << 8),
4087 STAT_KEYS_BLOCKS = (1U << 9),
4088 STAT_KEYS_ATIME = (1U << 10),
4089 STAT_KEYS_CTIME = (1U << 11),
4090 STAT_KEYS_MTIME = (1U << 12),
4091 #ifdef NOTYET
4092 STAT_KEYS_FLAGS = (1U << 13),
4093 #endif
4094 STAT_KEYS_SLINK = (1U << 14),
4095 STAT_KEYS_DIGEST = (1U << 15),
4096 #ifdef NOTYET
4097 STAT_KEYS_FCONTEXT = (1U << 16),
4098 #endif
4099 STAT_KEYS_UNAME = (1U << 17),
4100 STAT_KEYS_GNAME = (1U << 18),
4101 };
4102
4103 /*@unchecked@*/ /*@observer@*/
4104 static KEY keyStat[] = {
4105 { "adler32", STAT_KEYS_DIGEST },
4106 { "atime", STAT_KEYS_ATIME },
4107 { "ctime", STAT_KEYS_CTIME },
4108 { "blksize", STAT_KEYS_BLKSIZE },
4109 { "blocks", STAT_KEYS_BLOCKS },
4110 { "crc32", STAT_KEYS_DIGEST },
4111 { "crc64", STAT_KEYS_DIGEST },
4112 { "dev", STAT_KEYS_DEV },
4113 #ifdef NOTYET
4114 { "digest", STAT_KEYS_DIGEST },
4115 { "fcontext", STAT_KEYS_FCONTEXT },
4116 { "flags", STAT_KEYS_FLAGS },
4117 #endif
4118 { "gid", STAT_KEYS_GID },
4119 { "gname", STAT_KEYS_GNAME },
4120 { "haval160", STAT_KEYS_DIGEST },
4121 { "ino", STAT_KEYS_INO },
4122 { "jlu32", STAT_KEYS_DIGEST },
4123 { "link", STAT_KEYS_SLINK },
4124 { "md2", STAT_KEYS_DIGEST },
4125 { "md4", STAT_KEYS_DIGEST },
4126 { "md5", STAT_KEYS_DIGEST },
4127 { "mode", STAT_KEYS_MODE },
4128 { "mtime", STAT_KEYS_MTIME },
4129 { "nlink", STAT_KEYS_NLINK },
4130 { "rdev", STAT_KEYS_RDEV },
4131 { "rmd128", STAT_KEYS_DIGEST },
4132 { "rmd160", STAT_KEYS_DIGEST },
4133 { "rmd256", STAT_KEYS_DIGEST },
4134 { "rmd320", STAT_KEYS_DIGEST },
4135 { "salsa10", STAT_KEYS_DIGEST },
4136 { "salsa20", STAT_KEYS_DIGEST },
4137 { "sha1", STAT_KEYS_DIGEST },
4138 { "sha224", STAT_KEYS_DIGEST },
4139 { "sha256", STAT_KEYS_DIGEST },
4140 { "sha384", STAT_KEYS_DIGEST },
4141 { "sha512", STAT_KEYS_DIGEST },
4142 { "size", STAT_KEYS_SIZE },
4143 { "tiger192", STAT_KEYS_DIGEST },
4144 { "uid", STAT_KEYS_UID },
4145 { "uname", STAT_KEYS_UNAME },
4146 };
4147 /*@unchecked@*/
4148 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]);
4149
4153 enum keyUuids_e {
4154 UUID_KEYS_NONE = (0U << 0),
4155 UUID_KEYS_V1 = (1U << 0),
4156 UUID_KEYS_V3 = (3U << 0),
4157 UUID_KEYS_V4 = (4U << 0),
4158 UUID_KEYS_V5 = (5U << 0),
4159 #ifdef NOTYET
4160 UUID_KEYS_STRING = (0U << 4),
4161 UUID_KEYS_SIV = (1U << 4),
4162 UUID_KEYS_BINARY = (2U << 4),
4163 UUID_KEYS_TEXT = (3U << 4),
4164 #endif
4165 };
4166
4167 /*@unchecked@*/ /*@observer@*/
4168 static KEY keyUuids[] = {
4169 #ifdef NOTYET
4170 { "binary", UUID_KEYS_BINARY },
4171 { "siv", UUID_KEYS_SIV },
4172 { "string", UUID_KEYS_STRING },
4173 { "text", UUID_KEYS_TEXT },
4174 #endif
4175 { "v1", UUID_KEYS_V1 },
4176 { "v3", UUID_KEYS_V3 },
4177 { "v4", UUID_KEYS_V4 },
4178 { "v5", UUID_KEYS_V5 },
4179 };
4180 /*@unchecked@*/
4181 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]);
4182
4185 static int
4186 keyCmp(const void * a, const void * b)
4187 /*@*/
4188 {
4189 return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
4190 }
4191
4194 static rpmuint32_t
4195 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name)
4196 /*@*/
4197 {
4198 rpmuint32_t keyval = 0;
4199
4200 if (name && * name) {
4201 KEY needle = { .name = name, .value = 0 };
4202 KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp);
4203 if (k)
4204 keyval = k->value;
4205 }
4206 return keyval;
4207 }
4208
4215 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av)
4216 /*@*/
4217 {
4218 int ix = (he->ix > 0 ? he->ix : 0);
4219 char * val = NULL;
4220 size_t ns;
4221
4222 assert(ix == 0);
4223 switch(he->t) {
4224 default:
4225 val = xstrdup(_("(invalid type :digest)"));
4226 goto exit;
4227 /*@notreached@*/ break;
4228 case RPM_UINT64_TYPE:
4229 ns = sizeof(he->p.ui64p[0]);
4230 break;
4231 case RPM_STRING_TYPE:
4232 ns = strlen(he->p.str);
4233 break;
4234 case RPM_BIN_TYPE:
4235 ns = he->c;
4236 break;
4237 }
4238
4239 assert(he->p.ptr != NULL);
4240 { rpmuint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL));
4241 rpmuint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1);
4242 DIGEST_CTX ctx = rpmDigestInit(algo, 0);
4243 int xx = rpmDigestUpdate(ctx, he->p.ptr, ns);
4244 xx = rpmDigestFinal(ctx, &val, NULL, 1);
4245 }
4246
4247 exit:
4248 return val;
4249 }
4250
4257 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av)
4258 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
4259 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
4260 {
4261 /*@-nullassign@*/
4262 /*@unchecked@*/ /*@observer@*/
4263 static const char *avdefault[] = { "mode", NULL };
4264 /*@=nullassign@*/
4265 const char * fn = NULL;
4266 struct stat sb, *st = &sb;
4267 int ix = (he->ix > 0 ? he->ix : 0);
4268 char * val = NULL;
4269 int xx;
4270 int i;
4271
4272 memset(st, 0, sizeof(*st));
4273 assert(ix == 0);
4274 switch(he->t) {
4275 case RPM_BIN_TYPE:
4276 /* XXX limit to RPMTAG_PACKAGESTAT ... */
4277 if (he->tag == RPMTAG_PACKAGESTAT)
4278 if ((size_t)he->c == sizeof(*st)) {
4279 st = (struct stat *)he->p.ptr;
4280 break;
4281 }
4282 /*@fallthrough @*/
4283 default:
4284 val = xstrdup(_("(invalid type :stat)"));
4285 goto exit;
4286 /*@notreached@*/ break;
4287 case RPM_STRING_TYPE:
4288 fn = he->p.str;
4289 if (Lstat(fn, st) == 0)
4290 break;
4291 /*@-ownedtrans@*/
4292 val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL);
4293 /*@=ownedtrans@*/
4294 goto exit;
4295 /*@notreached@*/ break;
4296 }
4297
4298 if (!(av && av[0] && *av[0]))
4299 av = avdefault;
4300 for (i = 0; av[i] != NULL; i++) {
4301 char b[BUFSIZ];
4302 size_t nb = sizeof(b);
4303 char * nval;
4304 rpmuint32_t keyval = keyValue(keyStat, nkeyStat, av[i]);
4305
4306 nval = NULL;
4307 b[0] = '\0';
4308 switch (keyval) {
4309 default:
4310 /*@switchbreak@*/ break;
4311 case STAT_KEYS_NONE:
4312 /*@switchbreak@*/ break;
4313 case STAT_KEYS_DEV:
4314 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev);
4315 /*@switchbreak@*/ break;
4316 case STAT_KEYS_INO:
4317 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino);
4318 /*@switchbreak@*/ break;
4319 case STAT_KEYS_MODE:
4320 xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode);
4321 /*@switchbreak@*/ break;
4322 case STAT_KEYS_NLINK:
4323 xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink);
4324 /*@switchbreak@*/ break;
4325 case STAT_KEYS_UID:
4326 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid);
4327 /*@switchbreak@*/ break;
4328 case STAT_KEYS_GID:
4329 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid);
4330 /*@switchbreak@*/ break;
4331 case STAT_KEYS_RDEV:
4332 xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev);
4333 /*@switchbreak@*/ break;
4334 case STAT_KEYS_SIZE:
4335 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size);
4336 /*@switchbreak@*/ break;
4337 case STAT_KEYS_BLKSIZE:
4338 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize);
4339 /*@switchbreak@*/ break;
4340 case STAT_KEYS_BLOCKS:
4341 xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks);
4342 /*@switchbreak@*/ break;
4343 case STAT_KEYS_ATIME:
4344 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_atime));
4345 /*@switchbreak@*/ break;
4346 case STAT_KEYS_CTIME:
4347 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_ctime));
4348 /*@switchbreak@*/ break;
4349 case STAT_KEYS_MTIME:
4350 /*@i@*/ (void) stpcpy(b, ctime((time_t *)&st->st_mtime));
4351 /*@switchbreak@*/ break;
4352 #ifdef NOTYET
4353 case STAT_KEYS_FLAGS:
4354 /*@switchbreak@*/ break;
4355 #endif
4356 case STAT_KEYS_SLINK:
4357 if (fn != NULL && S_ISLNK(st->st_mode)) {
4358 ssize_t size = Readlink(fn, b, nb);
4359 if (size == -1) {
4360 nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL);
4361 (void) stpcpy(b, nval);
4362 nval = _free(nval);
4363 } else
4364 b[size] = '\0';
4365 }
4366 /*@switchbreak@*/ break;
4367 case STAT_KEYS_DIGEST:
4368 if (fn != NULL && S_ISREG(st->st_mode)) {
4369 rpmuint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]);
4370 rpmuint32_t algo = (digval ? digval : PGPHASHALGO_SHA1);
4371 FD_t fd = Fopen(fn, "r%{?_rpmgio}");
4372 if (fd == NULL || Ferror(fd)) {
4373 nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL);
4374 } else {
4375 static int asAscii = 1;
4376 char buffer[16 * 1024];
4377 fdInitDigest(fd, algo, 0);
4378 while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
4379 {};
4380 if (Ferror(fd))
4381 nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL);
4382 else
4383 fdFiniDigest(fd, algo, &nval, NULL, asAscii);
4384 }
4385 if (nval) {
4386 (void) stpcpy(b, nval);
4387 nval = _free(nval);
4388 }
4389 if (fd != NULL)
4390 xx = Fclose(fd);
4391 }
4392 /*@switchbreak@*/ break;
4393 case STAT_KEYS_UNAME:
4394 { const char * uname = uidToUname(st->st_uid);
4395 if (uname != NULL)
4396 (void) stpcpy(b, uname);
4397 else
4398 xx = snprintf(b, nb, "%u", (unsigned)st->st_uid);
4399 } /*@switchbreak@*/ break;
4400 case STAT_KEYS_GNAME:
4401 { const char * gname = gidToGname(st->st_gid);
4402 if (gname != NULL)
4403 (void) stpcpy(b, gname);
4404 else
4405 xx = snprintf(b, nb, "%u", (unsigned)st->st_gid);
4406 } /*@switchbreak@*/ break;
4407 }
4408 if (b[0] == '\0')
4409 continue;
4410 b[nb-1] = '\0';
4411
4412 if (val == NULL)
4413 val = xstrdup(b);
4414 else {
4415 nval = rpmExpand(val, " | ", b, NULL);
4416 val = _free(val);
4417 val = nval;
4418 }
4419 }
4420
4421 exit:
4422 return val;
4423 }
4424
4431 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av)
4432 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
4433 /*@modifies rpmGlobalMacroContext, internalState @*/
4434 {
4435 /*@-nullassign@*/
4436 /*@unchecked@*/ /*@observer@*/
4437 static const char *avdefault[] = { "v5", NULL };
4438 /*@=nullassign@*/
4439 rpmuint32_t version = 0;
4440 int ix = (he->ix > 0 ? he->ix : 0);
4441 char * val = NULL;
4442 int i;
4443
4444 assert(ix == 0);
4445 switch(he->t) {
4446 default:
4447 val = xstrdup(_("(invalid type :uuid)"));
4448 goto exit;
4449 /*@notreached@*/ break;
4450 case RPM_STRING_TYPE:
4451 break;
4452 }
4453
4454 if (!(av && av[0] && *av[0]))
4455 av = avdefault;
4456
4457 for (i = 0; av[i] != NULL; i++) {
4458 rpmuint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]);
4459
4460 switch (keyval) {
4461 default:
4462 /*@switchbreak@*/ break;
4463 case UUID_KEYS_V1:
4464 case UUID_KEYS_V3:
4465 case UUID_KEYS_V4:
4466 case UUID_KEYS_V5:
4467 version = keyval;
4468 /*@switchbreak@*/ break;
4469 }
4470 }
4471
4472 /* XXX use private tag container to avoid memory issues for now. */
4473 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
4474 int xx;
4475 nhe->tag = he->tag;
4476 nhe->t = he->t;
4477 nhe->p.str = xstrdup(he->p.str);
4478 nhe->c = he->c;
4479 val = xmalloc((128/4 + 4) + 1);
4480 *val = '\0';
4481 xx = str2uuid(nhe, NULL, version, val);
4482 nhe->p.ptr = _free(nhe->p.ptr);
4483 }
4484
4485 exit:
4486 return val;
4487 }
4488
4495 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av)
4496 /*@*/
4497 {
4498 int ac = argvCount(av) + 1;
4499 int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack)));
4500 char * end;
4501 char * val = NULL;
4502 int ix = 0;
4503 int i;
4504
4505 switch(he->t) {
4506 default:
4507 val = xstrdup(_("(invalid type :rpn)"));
4508 goto exit;
4509 /*@notreached@*/ break;
4510 case RPM_UINT64_TYPE:
4511 stack[ix] = he->p.ui64p[0];
4512 break;
4513 case RPM_STRING_TYPE:
4514 end = NULL;
4515 /*@-unrecog@*/ /* Add annotated prototype. */
4516 stack[ix] = strtoll(he->p.str, &end, 0);
4517 /*@=unrecog@*/
4518 if (end && *end != '\0') {
4519 val = xstrdup(_("(invalid string :rpn)"));
4520 goto exit;
4521 }
4522 break;
4523 }
4524
4525 if (av != NULL)
4526 for (i = 0; av[i] != NULL; i++) {
4527 const char * arg = av[i];
4528 size_t len = strlen(arg);
4529 int c = (int) *arg;
4530
4531 if (len == 0) {
4532 /* do nothing */
4533 } else if (len > 1) {
4534 if (!(xisdigit(c) || (c == (int)'-' && xisdigit((int) arg[1])))) {
4535 val = xstrdup(_("(expected number :rpn)"));
4536 goto exit;
4537 }
4538 if (++ix == ac) {
4539 val = xstrdup(_("(stack overflow :rpn)"));
4540 goto exit;
4541 }
4542 end = NULL;
4543 stack[ix] = strtoll(arg, &end, 0);
4544 if (end && *end != '\0') {
4545 val = xstrdup(_("(invalid number :rpn)"));
4546 goto exit;
4547 }
4548 } else {
4549 if (ix-- < 1) {
4550 val = xstrdup(_("(stack underflow :rpn)"));
4551 goto exit;
4552 }
4553 switch (c) {
4554 case '&': stack[ix] &= stack[ix+1]; /*@switchbreak@*/ break;
4555 case '|': stack[ix] |= stack[ix+1]; /*@switchbreak@*/ break;
4556 case '^': stack[ix] ^= stack[ix+1]; /*@switchbreak@*/ break;
4557 case '+': stack[ix] += stack[ix+1]; /*@switchbreak@*/ break;
4558 case '-': stack[ix] -= stack[ix+1]; /*@switchbreak@*/ break;
4559 case '*': stack[ix] *= stack[ix+1]; /*@switchbreak@*/ break;
4560 case '%':
4561 case '/':
4562 if (stack[ix+1] == 0) {
4563 val = xstrdup(_("(divide by zero :rpn)"));
4564 goto exit;
4565 }
4566 if (c == (int)'%')
4567 stack[ix] %= stack[ix+1];
4568 else
4569 stack[ix] /= stack[ix+1];
4570 /*@switchbreak@*/ break;
4571 }
4572 }
4573 }
4574
4575 { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
4576 nhe->tag = he->tag;
4577 nhe->t = RPM_UINT64_TYPE;
4578 nhe->p.ui64p = (rpmuint64_t *)&stack[ix];
4579 nhe->c = 1;
4580 val = intFormat(nhe, NULL, NULL);
4581 }
4582
4583 exit:
4584 return val;
4585 }
4586
4593 static /*@only@*/ char * strsubFormat(HE_t he, /*@null@*/ const char ** av)
4594 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
4595 /*@modifies rpmGlobalMacroContext, internalState @*/
4596 {
4597 char * val = NULL;
4598 int ac = argvCount(av);
4599 miRE mires = NULL;
4600 int nmires = 0;
4601 int xx;
4602 int i;
4603
4604 switch(he->t) {
4605 default:
4606 val = xstrdup(_("(invalid type :strsub)"));
4607 goto exit;
4608 /*@notreached@*/ break;
4609 case RPM_STRING_TYPE:
4610 if (ac < 2 || (ac % 2) != 0) {
4611 val = xstrdup(_("(invalid args :strsub)"));
4612 goto exit;
4613 }
4614 break;
4615 }
4616 if (av == NULL)
4617 goto noop;
4618
4619 /* Create the mire pattern array. */
4620 for (i = 0; av[i] != NULL; i += 2)
4621 xx = mireAppend(RPMMIRE_REGEX, 0, av[i], NULL, &mires, &nmires);
4622
4623 /* Find-and-replace first pattern that matches. */
4624 if (mires != NULL) {
4625 int noffsets = 3;
4626 int offsets[3];
4627 const char * s, * se;
4628 char * t, * te;
4629 char * nval;
4630 size_t slen;
4631 size_t nb;
4632
4633 for (i = 0; i < nmires; i++) {
4634 miRE mire = mires + i;
4635
4636 s = he->p.str;
4637 slen = strlen(s);
4638 if ((xx = mireRegexec(mire, s, slen)) < 0)
4639 continue;
4640 xx = mireSetEOptions(mire, offsets, noffsets);
4641
4642 /* Replace the string(s). This is just s/find/replace/g */
4643 val = xstrdup("");
4644 while (*s != '\0') {
4645 nb = strlen(s);
4646 if ((se = strchr(s, '\n')) == NULL)
4647 se = s + nb;
4648 else
4649 se++;
4650
4651 offsets[0] = offsets[1] = -1;
4652 xx = mireRegexec(mire, s, nb);
4653
4654 nb = 1;
4655 /* On match, copy lead-in and match string. */
4656 if (xx == 0)
4657 nb += offsets[0] + strlen(av[2*i+1]);
4658 /* Copy up to EOL on nomatch or insertion. */
4659 if (xx != 0 || offsets[1] == offsets[0])
4660 nb += (se - (s + offsets[1]));
4661
4662 te = t = xmalloc(nb);
4663
4664 /* On match, copy lead-in and match string. */
4665 if (xx == 0) {
4666 te = stpcpy( stpncpy(te, s, offsets[0]), av[2*i+1]);
4667 s += offsets[1];
4668 }
4669 /* Copy up to EOL on nomatch or insertion. */
4670 if (xx != 0 || offsets[1] == offsets[0]) {
4671 s += offsets[1];
4672 te = stpncpy(te, s, (se - s));
4673 s = se;
4674 }
4675 *te = '\0';
4676
4677 nval = rpmExpand(val, t, NULL);
4678 val = _free(val);
4679 val = nval;
4680 t = _free(t);
4681 }
4682 }
4683 mires = mireFreeAll(mires, nmires);
4684 }
4685
4686 noop:
4687 if (val == NULL)
4688 val = xstrdup(he->p.str);
4689 exit:
4690 return val;
4691 }
4692
4693 static struct headerSprintfExtension_s _headerCompoundFormats[] = {
4694 { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID",
4695 { .tagFunction = buildtime_uuidTag } },
4696 { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
4697 { .tagFunction = changelognameTag } },
4698 { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
4699 { .tagFunction = changelogtextTag } },
4700 { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
4701 { .tagFunction = descriptionTag } },
4702 { HEADER_EXT_TAG, "RPMTAG_GROUP",
4703 { .tagFunction = groupTag } },
4704 { HEADER_EXT_TAG, "RPMTAG_HDRUUID",
4705 { .tagFunction = hdruuidTag } },
4706 { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
4707 { .tagFunction = instprefixTag } },
4708 { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID",
4709 { .tagFunction = installtid_uuidTag } },
4710 { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID",
4711 { .tagFunction = installtime_uuidTag } },
4712 { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID",
4713 { .tagFunction = origintid_uuidTag } },
4714 { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID",
4715 { .tagFunction = origintime_uuidTag } },
4716 { HEADER_EXT_TAG, "RPMTAG_PKGUUID",
4717 { .tagFunction = pkguuidTag } },
4718 { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID",
4719 { .tagFunction = removetid_uuidTag } },
4720 { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID",
4721 { .tagFunction = sourcepkguuidTag } },
4722 { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
4723 { .tagFunction = summaryTag } },
4724 { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
4725 { .tagFunction = triggercondsTag } },
4726 { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
4727 { .tagFunction = triggertypeTag } },
4728 { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
4729 { .tagFunction = dbinstanceTag } },
4730 { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF",
4731 { .tagFunction = headerstartoffTag } },
4732 { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF",
4733 { .tagFunction = headerendoffTag } },
4734 { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL",
4735 { .tagFunction = pkgbaseurlTag } },
4736 { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST",
4737 { .tagFunction = pkgdigestTag } },
4738 { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN",
4739 { .tagFunction = pkgoriginTag } },
4740 { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE",
4741 { .tagFunction = pkgsizeTag } },
4742 { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME",
4743 { .tagFunction = pkgmtimeTag } },
4744 { HEADER_EXT_TAG, "RPMTAG_NVRA",
4745 { .tagFunction = nvraTag } },
4746 { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
4747 { .tagFunction = filenamesTag } },
4748 { HEADER_EXT_TAG, "RPMTAG_FILEPATHS",
4749 { .tagFunction = filepathsTag } },
4750 { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
4751 { .tagFunction = origpathsTag } },
4752 { HEADER_EXT_TAG, "RPMTAG_FILESTAT",
4753 { .tagFunction = filestatTag } },
4754 { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY",
4755 { .tagFunction = PxmlTag } },
4756 { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY",
4757 { .tagFunction = RxmlTag } },
4758 { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY",
4759 { .tagFunction = CxmlTag } },
4760 { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY",
4761 { .tagFunction = OxmlTag } },
4762 { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1",
4763 { .tagFunction = F1xmlTag } },
4764 { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2",
4765 { .tagFunction = F2xmlTag } },
4766 { HEADER_EXT_TAG, "RPMTAG_PROVIDEYAMLENTRY",
4767 { .tagFunction = PyamlTag } },
4768 { HEADER_EXT_TAG, "RPMTAG_REQUIREYAMLENTRY",
4769 { .tagFunction = RyamlTag } },
4770 { HEADER_EXT_TAG, "RPMTAG_CONFLICTYAMLENTRY",
4771 { .tagFunction = CyamlTag } },
4772 { HEADER_EXT_TAG, "RPMTAG_OBSOLETEYAMLENTRY",
4773 { .tagFunction = OyamlTag } },
4774 { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY1",
4775 { .tagFunction = F1yamlTag } },
4776 { HEADER_EXT_TAG, "RPMTAG_FILESYAMLENTRY2",
4777 { .tagFunction = F2yamlTag } },
4778 { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY",
4779 { .tagFunction = PsqlTag } },
4780 { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY",
4781 { .tagFunction = RsqlTag } },
4782 { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY",
4783 { .tagFunction = CsqlTag } },
4784 { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY",
4785 { .tagFunction = OsqlTag } },
4786 { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1",
4787 { .tagFunction = F1sqlTag } },
4788 { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2",
4789 { .tagFunction = F2sqlTag } },
4790 { HEADER_EXT_TAG, "RPMTAG_DEBCONFLICTS",
4791 { .tagFunction = debconflictsTag } },
4792 { HEADER_EXT_TAG, "RPMTAG_DEBDEPENDS",
4793 { .tagFunction = debdependsTag } },
4794 { HEADER_EXT_TAG, "RPMTAG_DEBMD5SUMS",
4795 { .tagFunction = debmd5sumsTag } },
4796 { HEADER_EXT_TAG, "RPMTAG_DEBOBSOLETES",
4797 { .tagFunction = debobsoletesTag } },
4798 { HEADER_EXT_TAG, "RPMTAG_DEBPROVIDES",
4799 { .tagFunction = debprovidesTag } },
4800 { HEADER_EXT_TAG, "RPMTAG_NEEDSWHAT",
4801 { .tagFunction = needswhatTag } },
4802 { HEADER_EXT_TAG, "RPMTAG_WHATNEEDS",
4803 { .tagFunction = whatneedsTag } },
4804 { HEADER_EXT_FORMAT, "armor",
4805 { .fmtFunction = armorFormat } },
4806 { HEADER_EXT_FORMAT, "base64",
4807 { .fmtFunction = base64Format } },
4808 { HEADER_EXT_FORMAT, "bncdata",
4809 { .fmtFunction = bncdataFormat } },
4810 { HEADER_EXT_FORMAT, "cdata",
4811 { .fmtFunction = cdataFormat } },
4812 { HEADER_EXT_FORMAT, "depflags",
4813 { .fmtFunction = depflagsFormat } },
4814 { HEADER_EXT_FORMAT, "deptype",
4815 { .fmtFunction = deptypeFormat } },
4816 { HEADER_EXT_FORMAT, "digest",
4817 { .fmtFunction = digestFormat } },
4818 { HEADER_EXT_FORMAT, "fflags",
4819 { .fmtFunction = fflagsFormat } },
4820 { HEADER_EXT_FORMAT, "iconv",
4821 { .fmtFunction = iconvFormat } },
4822 { HEADER_EXT_FORMAT, "perms",
4823 { .fmtFunction = permsFormat } },
4824 { HEADER_EXT_FORMAT, "permissions",
4825 { .fmtFunction = permsFormat } },
4826 { HEADER_EXT_FORMAT, "pgpsig",
4827 { .fmtFunction = pgpsigFormat } },
4828 { HEADER_EXT_FORMAT, "rpn",
4829 { .fmtFunction = rpnFormat } },
4830 { HEADER_EXT_FORMAT, "sqlescape",
4831 { .fmtFunction = sqlescapeFormat } },
4832 { HEADER_EXT_FORMAT, "stat",
4833 { .fmtFunction = statFormat } },
4834 { HEADER_EXT_FORMAT, "strsub",
4835 { .fmtFunction = strsubFormat } },
4836 { HEADER_EXT_FORMAT, "triggertype",
4837 { .fmtFunction = triggertypeFormat } },
4838 { HEADER_EXT_FORMAT, "utf8",
4839 { .fmtFunction = iconvFormat } },
4840 { HEADER_EXT_FORMAT, "uuid",
4841 { .fmtFunction = uuidFormat } },
4842 { HEADER_EXT_FORMAT, "xml",
4843 { .fmtFunction = xmlFormat } },
4844 { HEADER_EXT_FORMAT, "yaml",
4845 { .fmtFunction = yamlFormat } },
4846 { HEADER_EXT_MORE, NULL, { (void *) &headerDefaultFormats } }
4847 } ;
4848
4849 headerSprintfExtension headerCompoundFormats = &_headerCompoundFormats[0];
4850
4851 /*====================================================================*/
4852
4853 void rpmDisplayQueryTags(FILE * fp, headerTagTableEntry _rpmTagTable, headerSprintfExtension _rpmHeaderFormats)
4854 {
4855 const struct headerTagTableEntry_s * t;
4856 headerSprintfExtension exts;
4857 headerSprintfExtension ext;
4858 int extNum;
4859
4860 if (fp == NULL)
4861 fp = stdout;
4862 if (_rpmTagTable == NULL)
4863 _rpmTagTable = rpmTagTable;
4864
4865 /* XXX this should use rpmHeaderFormats, but there are linkage problems. */
4866 if (_rpmHeaderFormats == NULL)
4867 _rpmHeaderFormats = headerCompoundFormats;
4868
4869 for (t = _rpmTagTable; t && t->name; t++) {
4870 /*@observer@*/
4871 static const char * tagtypes[] = {
4872 "", "char", "uint8", "uint16", "uint32", "uint64",
4873 "string", "octets", "argv", "i18nstring",
4874 };
4875 rpmuint32_t ttype;
4876
4877 if (rpmIsVerbose()) {
4878 fprintf(fp, "%-20s %6d", t->name + 7, t->val);
4879 ttype = t->type & RPM_MASK_TYPE;
4880 if (ttype < RPM_MIN_TYPE || ttype > RPM_MAX_TYPE)
4881 continue;
4882 if (t->type & RPM_OPENPGP_RETURN_TYPE)
4883 fprintf(fp, " openpgp");
4884 if (t->type & RPM_X509_RETURN_TYPE)
4885 fprintf(fp, " x509");
4886 if (t->type & RPM_ASN1_RETURN_TYPE)
4887 fprintf(fp, " asn1");
4888 if (t->type & RPM_OPAQUE_RETURN_TYPE)
4889 fprintf(fp, " opaque");
4890 fprintf(fp, " %s", tagtypes[ttype]);
4891 if (t->type & RPM_ARRAY_RETURN_TYPE)
4892 fprintf(fp, " array");
4893 if (t->type & RPM_MAPPING_RETURN_TYPE)
4894 fprintf(fp, " mapping");
4895 if (t->type & RPM_PROBE_RETURN_TYPE)
4896 fprintf(fp, " probe");
4897 if (t->type & RPM_TREE_RETURN_TYPE)
4898 fprintf(fp, " tree");
4899 } else
4900 fprintf(fp, "%s", t->name + 7);
4901 fprintf(fp, "\n");
4902 }
4903
4904 exts = _rpmHeaderFormats;
4905 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
4906 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
4907 {
4908 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
4909 continue;
4910
4911 /* XXX don't print header tags twice. */
4912 if (tagValue(ext->name) > 0)
4913 continue;
4914 fprintf(fp, "%s\n", ext->name + 7);
4915 }
4916 }
4917
4918 /*====================================================================*/
4919
4920 #define PARSER_BEGIN 0
4921 #define PARSER_IN_ARRAY 1
4922 #define PARSER_IN_EXPR 2
4923
4926 typedef /*@abstract@*/ struct sprintfTag_s * sprintfTag;
4927
4930 struct sprintfTag_s {
4931 HE_s he;
4932 /*@null@*/
4933 headerTagFormatFunction * fmtfuncs;
4934 /*@null@*/
4935 headerTagTagFunction ext;
4936 int extNum;
4937 /*@only@*/ /*@relnull@*/
4938 rpmTag * tagno;
4939 int justOne;
4940 int arrayCount;
4941 /*@kept@*/
4942 char * format;
4943 /*@only@*/ /*@relnull@*/
4944 ARGV_t av;
4945 /*@only@*/ /*@relnull@*/
4946 ARGV_t params;
4947 unsigned pad;
4948 };
4949
4952 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken;
4953
4956 struct sprintfToken_s {
4957 enum {
4958 PTOK_NONE = 0,
4959 PTOK_TAG = 1,
4960 PTOK_ARRAY = 2,
4961 PTOK_STRING = 3,
4962 PTOK_COND = 4
4963 } type;
4964 union {
4965 struct sprintfTag_s tag;
4966 struct {
4967 /*@only@*/
4968 sprintfToken format;
4969 size_t numTokens;
4970 } array;
4971 struct {
4972 /*@dependent@*/
4973 char * string;
4974 size_t len;
4975 } string;
4976 struct {
4977 /*@only@*/ /*@null@*/
4978 sprintfToken ifFormat;
4979 size_t numIfTokens;
4980 /*@only@*/ /*@null@*/
4981 sprintfToken elseFormat;
4982 size_t numElseTokens;
4983 struct sprintfTag_s tag;
4984 } cond;
4985 } u;
4986 };
4987
4990 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs;
4991
4994 struct headerSprintfArgs_s {
4995 Header h;
4996 char * fmt;
4997 /*@observer@*/ /*@temp@*/
4998 headerTagTableEntry tags;
4999 /*@observer@*/ /*@temp@*/
5000 headerSprintfExtension exts;
5001 /*@observer@*/ /*@null@*/
5002 const char * errmsg;
5003 HE_t ec;
5004 int nec;
5005 sprintfToken format;
5006 /*@relnull@*/
5007 HeaderIterator hi;
5008 /*@owned@*/
5009 char * val;
5010 size_t vallen;
5011 size_t alloced;
5012 size_t numTokens;
5013 size_t i;
5014 };
5015
5016 /*@access sprintfTag @*/
5017 /*@access sprintfToken @*/
5018 /*@access headerSprintfArgs @*/
5019
5022 static char escapedChar(const char ch)
5023 /*@*/
5024 {
5025 /*@-modfilesys@*/
5026 if (_hdrqf_debug)
5027 fprintf(stderr, "\t\t\\%c\n", ch);
5028 /*@=modfilesys@*/
5029 switch (ch) {
5030 case 'a': return '\a';
5031 case 'b': return '\b';
5032 case 'f': return '\f';
5033 case 'n': return '\n';
5034 case 'r': return '\r';
5035 case 't': return '\t';
5036 case 'v': return '\v';
5037 default: return ch;
5038 }
5039 }
5040
5045 /*@relnull@*/
5046 static HE_t rpmheClean(/*@returned@*/ /*@null@*/ HE_t he)
5047 /*@modifies he @*/
5048 {
5049 if (he) {
5050 if (he->freeData && he->p.ptr != NULL)
5051 he->p.ptr = _free(he->p.ptr);
5052 memset(he, 0, sizeof(*he));
5053 }
5054 return he;
5055 }
5056
5063 static /*@null@*/ sprintfToken
5064 freeFormat( /*@only@*/ /*@null@*/ sprintfToken format, size_t num)
5065 /*@modifies *format @*/
5066 {
5067 unsigned i;
5068
5069 if (format == NULL) return NULL;
5070
5071 for (i = 0; i < (unsigned) num; i++) {
5072 switch (format[i].type) {
5073 case PTOK_TAG:
5074 (void) rpmheClean(&format[i].u.tag.he);
5075 format[i].u.tag.tagno = _free(format[i].u.tag.tagno);
5076 format[i].u.tag.av = argvFree(format[i].u.tag.av);
5077 format[i].u.tag.params = argvFree(format[i].u.tag.params);
5078 /*@-type@*/
5079 format[i].u.tag.fmtfuncs = _free(format[i].u.tag.fmtfuncs);
5080 /*@=type@*/
5081 /*@switchbreak@*/ break;
5082 case PTOK_ARRAY:
5083 format[i].u.array.format =
5084 freeFormat(format[i].u.array.format,
5085 format[i].u.array.numTokens);
5086 /*@switchbreak@*/ break;
5087 case PTOK_COND:
5088 format[i].u.cond.ifFormat =
5089 freeFormat(format[i].u.cond.ifFormat,
5090 format[i].u.cond.numIfTokens);
5091 format[i].u.cond.elseFormat =
5092 freeFormat(format[i].u.cond.elseFormat,
5093 format[i].u.cond.numElseTokens);
5094 (void) rpmheClean(&format[i].u.cond.tag.he);
5095 format[i].u.cond.tag.tagno = _free(format[i].u.cond.tag.tagno);
5096 format[i].u.cond.tag.av = argvFree(format[i].u.cond.tag.av);
5097 format[i].u.cond.tag.params = argvFree(format[i].u.cond.tag.params);
5098 /*@-type@*/
5099 format[i].u.cond.tag.fmtfuncs = _free(format[i].u.cond.tag.fmtfuncs);
5100 /*@=type@*/
5101 /*@switchbreak@*/ break;
5102 case PTOK_NONE:
5103 case PTOK_STRING:
5104 default:
5105 /*@switchbreak@*/ break;
5106 }
5107 }
5108 format = _free(format);
5109 return NULL;
5110 }
5111
5117 static headerSprintfArgs hsaInit(/*@returned@*/ headerSprintfArgs hsa)
5118 /*@globals fileSystem @*/
5119 /*@modifies hsa, fileSystem @*/
5120 {
5121 sprintfTag tag =
5122 (hsa->format->type == PTOK_TAG
5123 ? &hsa->format->u.tag :
5124 (hsa->format->type == PTOK_ARRAY
5125 ? &hsa->format->u.array.format->u.tag :
5126 NULL));
5127
5128 if (hsa != NULL) {
5129 hsa->i = 0;
5130 if (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2)
5131 hsa->hi = headerInit(hsa->h);
5132 }
5133 /*@-nullret@*/
5134 return hsa;
5135 /*@=nullret@*/
5136 }
5137
5143 /*@null@*/
5144 static sprintfToken hsaNext(/*@returned@*/ headerSprintfArgs hsa)
5145 /*@globals internalState @*/
5146 /*@modifies hsa, internalState @*/
5147 {
5148 sprintfToken fmt = NULL;
5149 sprintfTag tag =
5150 (hsa->format->type == PTOK_TAG
5151 ? &hsa->format->u.tag :
5152 (hsa->format->type == PTOK_ARRAY
5153 ? &hsa->format->u.array.format->u.tag :
5154 NULL));
5155
5156 if (hsa != NULL && hsa->i < hsa->numTokens) {
5157 fmt = hsa->format + hsa->i;
5158 if (hsa->hi == NULL) {
5159 hsa->i++;
5160 } else {
5161 HE_t he = rpmheClean(&tag->he);
5162 if (!headerNext(hsa->hi, he, 0))
5163 {
5164 tag->tagno[0] = 0;
5165 return NULL;
5166 }
5167 he->avail = 1;
5168 tag->tagno[0] = he->tag;
5169 }
5170 }
5171
5172 /*@-dependenttrans -onlytrans@*/
5173 return fmt;
5174 /*@=dependenttrans =onlytrans@*/
5175 }
5176
5182 static headerSprintfArgs hsaFini(/*@returned@*/ headerSprintfArgs hsa)
5183 /*@globals fileSystem @*/
5184 /*@modifies hsa, fileSystem @*/
5185 {
5186 if (hsa != NULL) {
5187 hsa->hi = headerFini(hsa->hi);
5188 hsa->i = 0;
5189 }
5190 /*@-nullret@*/
5191 return hsa;
5192 /*@=nullret@*/
5193 }
5194
5201 /*@dependent@*/ /*@exposed@*/
5202 static char * hsaReserve(headerSprintfArgs hsa, size_t need)
5203 /*@modifies hsa */
5204 {
5205 if ((hsa->vallen + need) >= hsa->alloced) {
5206 if (hsa->alloced <= need)
5207 hsa->alloced += need;
5208 hsa->alloced <<= 1;
5209 hsa->val = xrealloc(hsa->val, hsa->alloced+1);
5210 }
5211 return hsa->val + hsa->vallen;
5212 }
5213
5221 /*@observer@*/ /*@null@*/
5222 static const char * myTagName(headerTagTableEntry tbl, rpmuint32_t val,
5223 /*@null@*/ rpmuint32_t *typep)
5224 /*@modifies *typep @*/
5225 {
5226 static char name[128]; /* XXX Ick. */
5227 const char * s;
5228 char *t;
5229
5230 /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
5231 if (tbl == NULL || tbl == rpmTagTable) {
5232 s = tagName(val);
5233 if (s != NULL && typep != NULL)
5234 *typep = tagType(val);
5235 return s;
5236 }
5237
5238 for (; tbl->name != NULL; tbl++) {
5239 if (tbl->val == val)
5240 break;
5241 }
5242 if ((s = tbl->name) == NULL)
5243 return NULL;
5244 s += sizeof("RPMTAG_") - 1;
5245 t = name;
5246 *t++ = *s++;
5247 while (*s != '\0')
5248 *t++ = (char)xtolower((int)*s++);
5249 *t = '\0';
5250 if (typep)
5251 *typep = tbl->type;
5252 return name;
5253 }
5254
5261 static rpmuint32_t myTagValue(headerTagTableEntry tbl, const char * name)
5262 /*@*/
5263 {
5264 rpmuint32_t val = 0;
5265
5266 /* XXX Use bsearch on the "normal" rpmTagTable lookup. */
5267 if (tbl == NULL || tbl == rpmTagTable)
5268 val = tagValue(name);
5269 else
5270 for (; tbl->name != NULL; tbl++) {
5271 if (xstrcasecmp(tbl->name, name))
5272 continue;
5273 val = tbl->val;
5274 break;
5275 }
5276 return val;
5277 }
5278
5286 static int findTag(headerSprintfArgs hsa, sprintfToken token, const char * name)
5287 /*@modifies token @*/
5288 {
5289 headerSprintfExtension exts = hsa->exts;
5290 headerSprintfExtension ext;
5291 sprintfTag stag = (token->type == PTOK_COND
5292 ? &token->u.cond.tag : &token->u.tag);
5293 int extNum;
5294 rpmTag tagno = (rpmTag)-1;
5295
5296 stag->fmtfuncs = NULL;
5297 stag->ext = NULL;
5298 stag->extNum = 0;
5299
5300 if (!strcmp(name, "*")) {
5301 tagno = (rpmTag)-2;
5302 goto bingo;
5303 }
5304
5305 if (strncmp("RPMTAG_", name, sizeof("RPMTAG_")-1)) {
5306 char * t = alloca(strlen(name) + sizeof("RPMTAG_"));
5307 (void) stpcpy( stpcpy(t, "RPMTAG_"), name);
5308 name = t;
5309 }
5310
5311 /* Search extensions for specific tag override. */
5312 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
5313 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
5314 {
5315 if (ext->name == NULL || ext->type != HEADER_EXT_TAG)
5316 continue;
5317 if (!xstrcasecmp(ext->name, name)) {
5318 stag->ext = ext->u.tagFunction;
5319 stag->extNum = extNum;
5320 tagno = tagValue(name);
5321 goto bingo;
5322 }
5323 }
5324
5325 /* Search tag names. */
5326 tagno = myTagValue(hsa->tags, name);
5327 if (tagno != 0)
5328 goto bingo;
5329
5330 return 1;
5331
5332 bingo:
5333 stag->tagno = xcalloc(1, sizeof(*stag->tagno));
5334 stag->tagno[0] = tagno;
5335 /* Search extensions for specific format(s). */
5336 if (stag->av != NULL) {
5337 int i;
5338 /*@-type@*/
5339 stag->fmtfuncs = xcalloc(argvCount(stag->av) + 1, sizeof(*stag->fmtfuncs));
5340 /*@=type@*/
5341 for (i = 0; stag->av[i] != NULL; i++) {
5342 for (ext = exts; ext != NULL && ext->type != HEADER_EXT_LAST;
5343 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1))
5344 {
5345 if (ext->name == NULL || ext->type != HEADER_EXT_FORMAT)
5346 /*@innercontinue@*/ continue;
5347 if (strcmp(ext->name, stag->av[i]+1))
5348 /*@innercontinue@*/ continue;
5349 stag->fmtfuncs[i] = ext->u.fmtFunction;
5350 /*@innerbreak@*/ break;
5351 }
5352 }
5353 }
5354 return 0;
5355 }
5356
5357 /* forward ref */
5366 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
5367 char * str, /*@out@*/char ** endPtr)
5368 /*@modifies hsa, str, token, *endPtr @*/
5369 /*@requires maxSet(endPtr) >= 0 @*/;
5370
5381 static int parseFormat(headerSprintfArgs hsa, char * str,
5382 /*@out@*/ sprintfToken * formatPtr,
5383 /*@out@*/ size_t * numTokensPtr,
5384 /*@null@*/ /*@out@*/ char ** endPtr, int state)
5385 /*@modifies hsa, str, *formatPtr, *numTokensPtr, *endPtr @*/
5386 /*@requires maxSet(formatPtr) >= 0 /\ maxSet(numTokensPtr) >= 0
5387 /\ maxSet(endPtr) >= 0 @*/
5388 {
5389 /*@observer@*/
5390 static const char *pstates[] = {
5391 "NORMAL", "ARRAY", "EXPR", "WTF?"
5392 };
5393 char * chptr, * start, * next, * dst;
5394 sprintfToken format;
5395 sprintfToken token;
5396 size_t numTokens;
5397 unsigned i;
5398 int done = 0;
5399 int xx;
5400
5401 /*@-modfilesys@*/
5402 if (_hdrqf_debug)
5403 fprintf(stderr, "--> parseFormat(%p, \"%.20s...\", %p, %p, %p, %s)\n", hsa, str, formatPtr, numTokensPtr, endPtr, pstates[(state & 0x3)]);
5404 /*@=modfilesys@*/
5405
5406 /* upper limit on number of individual formats */
5407 numTokens = 0;
5408 if (str != NULL)
5409 for (chptr = str; *chptr != '\0'; chptr++)
5410 if (*chptr == '%') numTokens++;
5411 numTokens = numTokens * 2 + 1;
5412
5413 format = xcalloc(numTokens, sizeof(*format));
5414 if (endPtr) *endPtr = NULL;
5415
5416 /*@-infloops@*/ /* LCL: can't detect (start, *start) termination */
5417 dst = start = str;
5418 numTokens = 0;
5419 token = NULL;
5420 if (start != NULL)
5421 while (*start != '\0') {
5422 switch (*start) {
5423 case '%':
5424 /* handle %% */
5425 if (*(start + 1) == '%') {
5426 if (token == NULL || token->type != PTOK_STRING) {
5427 token = format + numTokens++;
5428 token->type = PTOK_STRING;
5429 /*@-temptrans -assignexpose@*/
5430 dst = token->u.string.string = start;
5431 /*@=temptrans =assignexpose@*/
5432 }
5433 start++;
5434 *dst++ = *start++;
5435 /*@switchbreak@*/ break;
5436 }
5437
5438 token = format + numTokens++;
5439 *dst++ = '\0';
5440 start++;
5441
5442 if (*start == '|') {
5443 char * newEnd;
5444
5445 start++;
5446 if (parseExpression(hsa, token, start, &newEnd))
5447 {
5448 format = freeFormat(format, numTokens);
5449 return 1;
5450 }
5451 start = newEnd;
5452 /*@switchbreak@*/ break;
5453 }
5454
5455 /*@-assignexpose@*/
5456 token->u.tag.format = start;
5457 /*@=assignexpose@*/
5458 token->u.tag.pad = 0;
5459 token->u.tag.justOne = 0;
5460 token->u.tag.arrayCount = 0;
5461
5462 chptr = start;
5463 while (*chptr && *chptr != '{' && *chptr != '%') chptr++;
5464 if (!*chptr || *chptr == '%') {
5465 hsa->errmsg = _("missing { after %");
5466 format = freeFormat(format, numTokens);
5467 return 1;
5468 }
5469
5470 /*@-modfilesys@*/
5471 if (_hdrqf_debug)
5472 fprintf(stderr, "\tchptr *%p = NUL\n", chptr);
5473 /*@=modfilesys@*/
5474 *chptr++ = '\0';
5475
5476 while (start < chptr) {
5477 if (xisdigit((int)*start)) {
5478 i = strtoul(start, &start, 10);
5479 token->u.tag.pad += i;
5480 start = chptr;
5481 /*@innerbreak@*/ break;
5482 } else {
5483 start++;
5484 }
5485 }
5486
5487 if (*start == '=') {
5488 token->u.tag.justOne = 1;
5489 start++;
5490 } else if (*start == '#') {
5491 token->u.tag.justOne = 1;
5492 token->u.tag.arrayCount = 1;
5493 start++;
5494 }
5495
5496 next = start;
5497 while (*next && *next != '}') next++;
5498 if (!*next) {
5499 hsa->errmsg = _("missing } after %{");
5500 format = freeFormat(format, numTokens);
5501 return 1;
5502 }
5503 /*@-modfilesys@*/
5504 if (_hdrqf_debug)
5505 fprintf(stderr, "\tnext *%p = NUL\n", next);
5506 /*@=modfilesys@*/
5507 *next++ = '\0';
5508
5509 #define isSEP(_c) ((_c) == ':' || (_c) == '|')
5510 chptr = start;
5511 while (!(*chptr == '\0' || isSEP(*chptr))) chptr++;
5512 /* Split ":bing|bang:boom" --qf pipeline formatters (if any) */
5513 while (isSEP(*chptr)) {
5514 if (chptr[1] == '\0' || isSEP(chptr[1])) {
5515 hsa->errmsg = _("empty tag format");
5516 format = freeFormat(format, numTokens);
5517 return 1;
5518 }
5519 /* Parse the formatter parameter list. */
5520 { char * te = chptr + 1;
5521 char * t = strchr(te, '(');
5522 char c;
5523
5524 while (!(*te == '\0' || isSEP(*te))) {
5525 #ifdef NOTYET /* XXX some means of escaping is needed */
5526 if (te[0] == '\\' && te[1] != '\0') te++;
5527 #endif
5528 te++;
5529 }
5530 c = *te; *te = '\0';
5531 /* Parse (a,b,c) parameter list. */
5532 if (t != NULL) {
5533 *t++ = '\0';
5534 if (te <= t || te[-1] != ')') {
5535 hsa->errmsg = _("malformed parameter list");
5536 format = freeFormat(format, numTokens);
5537 return 1;
5538 }
5539 te[-1] = '\0';
5540 xx = argvAdd(&token->u.tag.params, t);
5541 } else
5542 xx = argvAdd(&token->u.tag.params, "");
5543 /*@-modfilesys@*/
5544 if (_hdrqf_debug)
5545 fprintf(stderr, "\tformat \"%s\" params \"%s\"\n", chptr, (t ? t : ""));
5546 /*@=modfilesys@*/
5547 xx = argvAdd(&token->u.tag.av, chptr);
5548 *te = c;
5549 *chptr = '\0';
5550 chptr = te;
5551 }
5552 }
5553 #undef isSEP
5554
5555 if (*start == '\0') {
5556 hsa->errmsg = _("empty tag name");
5557 format = freeFormat(format, numTokens);
5558 return 1;
5559 }
5560
5561 i = 0;
5562 token->type = PTOK_TAG;
5563
5564 if (findTag(hsa, token, start)) {
5565 hsa->errmsg = _("unknown tag");
5566 format = freeFormat(format, numTokens);
5567 return 1;
5568 }
5569
5570 dst = start = next;
5571 /*@-modfilesys@*/
5572 if (_hdrqf_debug)
5573 fprintf(stderr, "\tdst = start = next %p\n", dst);
5574 /*@=modfilesys@*/
5575 /*@switchbreak@*/ break;
5576
5577 case '[':
5578 /*@-modfilesys@*/
5579 if (_hdrqf_debug)
5580 fprintf(stderr, "\t%s => %s *%p = NUL\n", pstates[(state & 0x3)], pstates[PARSER_IN_ARRAY], start);
5581 /*@=modfilesys@*/
5582 *start++ = '\0';
5583 token = format + numTokens++;
5584
5585 if (parseFormat(hsa, start,
5586 &token->u.array.format,
5587 &token->u.array.numTokens,
5588 &start, PARSER_IN_ARRAY))
5589 {
5590 format = freeFormat(format, numTokens);
5591 return 1;
5592 }
5593
5594 if (!start) {
5595 hsa->errmsg = _("] expected at end of array");
5596 format = freeFormat(format, numTokens);
5597 return 1;
5598 }
5599
5600 dst = start;
5601 /*@-modfilesys@*/
5602 if (_hdrqf_debug)
5603 fprintf(stderr, "\tdst = start %p\n", dst);
5604 /*@=modfilesys@*/
5605
5606 token->type = PTOK_ARRAY;
5607
5608 /*@switchbreak@*/ break;
5609
5610 case ']':
5611 if (state != PARSER_IN_ARRAY) {
5612 hsa->errmsg = _("unexpected ]");
5613 format = freeFormat(format, numTokens);
5614 return 1;
5615 }
5616 *start++ = '\0';
5617 /*@-modfilesys@*/
5618 if (_hdrqf_debug)
5619 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
5620 /*@=modfilesys@*/
5621 if (endPtr) *endPtr = start;
5622 done = 1;
5623 /*@switchbreak@*/ break;
5624
5625 case '}':
5626 if (state != PARSER_IN_EXPR) {
5627 hsa->errmsg = _("unexpected }");
5628 format = freeFormat(format, numTokens);
5629 return 1;
5630 }
5631 *start++ = '\0';
5632 /*@-modfilesys@*/
5633 if (_hdrqf_debug)
5634 fprintf(stderr, "\t<= %s %p[-1] = NUL\n", pstates[(state & 0x3)], start);
5635 /*@=modfilesys@*/
5636 if (endPtr) *endPtr = start;
5637 done = 1;
5638 /*@switchbreak@*/ break;
5639
5640 default:
5641 if (token == NULL || token->type != PTOK_STRING) {
5642 token = format + numTokens++;
5643 token->type = PTOK_STRING;
5644 /*@-temptrans -assignexpose@*/
5645 dst = token->u.string.string = start;
5646 /*@=temptrans =assignexpose@*/
5647 }
5648
5649 /*@-modfilesys@*/
5650 if (_hdrqf_debug)
5651 fprintf(stderr, "\t*%p = *%p \"%.30s\"\n", dst, start, start);
5652 /*@=modfilesys@*/
5653 if (start[0] == '\\' && start[1] != '\0') {
5654 start++;
5655 *dst++ = escapedChar(*start);
5656 *start++ = '\0';
5657 } else {
5658 *dst++ = *start++;
5659 }
5660 /*@switchbreak@*/ break;
5661 }
5662 if (dst < start) *dst = '\0';
5663 if (done)
5664 break;
5665 }
5666 /*@=infloops@*/
5667
5668 if (dst != NULL)
5669 *dst = '\0';
5670
5671 for (i = 0; i < (unsigned) numTokens; i++) {
5672 token = format + i;
5673 switch(token->type) {
5674 default:
5675 /*@switchbreak@*/ break;
5676 case PTOK_STRING:
5677 token->u.string.len = strlen(token->u.string.string);
5678 /*@switchbreak@*/ break;
5679 }
5680 }
5681
5682 if (numTokensPtr != NULL)
5683 *numTokensPtr = numTokens;
5684 if (formatPtr != NULL)
5685 *formatPtr = format;
5686
5687 return 0;
5688 }
5689
5690 static int parseExpression(headerSprintfArgs hsa, sprintfToken token,
5691 char * str, /*@out@*/ char ** endPtr)
5692 {
5693 char * chptr;
5694 char * end;
5695
5696 /*@-modfilesys@*/
5697 if (_hdrqf_debug)
5698 fprintf(stderr, "--> parseExpression(%p, %p, \"%.20s...\", %p)\n", hsa, token, str, endPtr);
5699 /*@=modfilesys@*/
5700
5701 hsa->errmsg = NULL;
5702 chptr = str;
5703 while (*chptr && *chptr != '?') chptr++;
5704
5705 if (*chptr != '?') {
5706 hsa->errmsg = _("? expected in expression");
5707 return 1;
5708 }
5709
5710 *chptr++ = '\0';
5711
5712 if (*chptr != '{') {
5713 hsa->errmsg = _("{ expected after ? in expression");
5714 return 1;
5715 }
5716
5717 chptr++;
5718
5719 if (parseFormat(hsa, chptr, &token->u.cond.ifFormat,
5720 &token->u.cond.numIfTokens, &end, PARSER_IN_EXPR))
5721 return 1;
5722
5723 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{%}:{NAME}|\n'"*/
5724 if (!(end && *end)) {
5725 hsa->errmsg = _("} expected in expression");
5726 token->u.cond.ifFormat =
5727 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
5728 return 1;
5729 }
5730
5731 chptr = end;
5732 if (*chptr != ':' && *chptr != '|') {
5733 hsa->errmsg = _(": expected following ? subexpression");
5734 token->u.cond.ifFormat =
5735 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
5736 return 1;
5737 }
5738
5739 if (*chptr == '|') {
5740 if (parseFormat(hsa, NULL, &token->u.cond.elseFormat,
5741 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
5742 {
5743 token->u.cond.ifFormat =
5744 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
5745 return 1;
5746 }
5747 } else {
5748 chptr++;
5749
5750 if (*chptr != '{') {
5751 hsa->errmsg = _("{ expected after : in expression");
5752 token->u.cond.ifFormat =
5753 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
5754 return 1;
5755 }
5756
5757 chptr++;
5758
5759 if (parseFormat(hsa, chptr, &token->u.cond.elseFormat,
5760 &token->u.cond.numElseTokens, &end, PARSER_IN_EXPR))
5761 return 1;
5762
5763 /* XXX fix segfault on "rpm -q rpm --qf='%|NAME?{a}:{%}|{NAME}\n'" */
5764 if (!(end && *end)) {
5765 hsa->errmsg = _("} expected in expression");
5766 token->u.cond.ifFormat =
5767 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
5768 return 1;
5769 }
5770
5771 chptr = end;
5772 if (*chptr != '|') {
5773 hsa->errmsg = _("| expected at end of expression");
5774 token->u.cond.ifFormat =
5775 freeFormat(token->u.cond.ifFormat, token->u.cond.numIfTokens);
5776 token->u.cond.elseFormat =
5777 freeFormat(token->u.cond.elseFormat, token->u.cond.numElseTokens);
5778 return 1;
5779 }
5780 }
5781
5782 chptr++;
5783
5784 *endPtr = chptr;
5785
5786 token->type = PTOK_COND;
5787
5788 (void) findTag(hsa, token, str);
5789
5790 return 0;
5791 }
5792
5801 static int getExtension(headerSprintfArgs hsa, headerTagTagFunction fn,
5802 HE_t he, HE_t ec)
5803 /*@modifies he, ec @*/
5804 {
5805 int rc = 0;
5806 if (!ec->avail) {
5807 he = rpmheClean(he);
5808 rc = fn(hsa->h, he);
5809 *ec = *he; /* structure copy. */
5810 if (!rc)
5811 ec->avail = 1;
5812 } else
5813 *he = *ec; /* structure copy. */
5814 he->freeData = 0;
5815 rc = (rc == 0); /* XXX invert getExtension return. */
5816 return rc;
5817 }
5818
5826 /*@observer@*/ /*@null@*/
5827 static char * formatValue(headerSprintfArgs hsa, sprintfTag tag,
5828 size_t element)
5829 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
5830 /*@modifies hsa, tag, rpmGlobalMacroContext, internalState @*/
5831 {
5832 HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
5833 HE_t he = &tag->he;
5834 char * val = NULL;
5835 size_t need = 0;
5836 char * t, * te;
5837 rpmuint64_t ival = 0;
5838 rpmTagCount countBuf;
5839 int xx;
5840
5841 if (!he->avail) {
5842 if (tag->ext)
5843 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
5844 else {
5845 he->tag = tag->tagno[0]; /* XXX necessary? */
5846 xx = headerGet(hsa->h, he, 0);
5847 }
5848 if (!xx) {
5849 (void) rpmheClean(he);
5850 he->t = RPM_STRING_TYPE;
5851 he->p.str = xstrdup("(none)");
5852 he->c = 1;
5853 he->freeData = 1;
5854 }
5855 he->avail = 1;
5856 }
5857
5858 if (tag->arrayCount) {
5859 countBuf = he->c;
5860 he = rpmheClean(he);
5861 he->t = RPM_UINT32_TYPE;
5862 he->p.ui32p = &countBuf;
5863 he->c = 1;
5864 he->freeData = 0;
5865 }
5866
5867 vhe->tag = he->tag;
5868
5869 if (he->p.ptr)
5870 switch (he->t) {
5871 default:
5872 val = xstrdup("(unknown type)");
5873 need = strlen(val) + 1;
5874 goto exit;
5875 /*@notreached@*/ break;
5876 case RPM_I18NSTRING_TYPE:
5877 case RPM_STRING_ARRAY_TYPE:
5878 vhe->t = RPM_STRING_TYPE;
5879 vhe->p.str = he->p.argv[element];
5880 vhe->c = he->c;
5881 vhe->ix = (he->t == RPM_STRING_ARRAY_TYPE || he->c > 1 ? 0 : -1);
5882 break;
5883 case RPM_STRING_TYPE:
5884 vhe->p.str = he->p.str;
5885 vhe->t = RPM_STRING_TYPE;
5886 vhe->c = 0;
5887 vhe->ix = -1;
5888 break;
5889 case RPM_UINT8_TYPE:
5890 case RPM_UINT16_TYPE:
5891 case RPM_UINT32_TYPE:
5892 case RPM_UINT64_TYPE:
5893 switch (he->t) {
5894 default:
5895 assert(0); /* XXX keep gcc quiet. */
5896 /*@innerbreak@*/ break;
5897 case RPM_UINT8_TYPE:
5898 ival = (rpmuint64_t)he->p.ui8p[element];
5899 /*@innerbreak@*/ break;
5900 case RPM_UINT16_TYPE:
5901 ival = (rpmuint64_t)he->p.ui16p[element];
5902 /*@innerbreak@*/ break;
5903 case RPM_UINT32_TYPE:
5904 ival = (rpmuint64_t)he->p.ui32p[element];
5905 /*@innerbreak@*/ break;
5906 case RPM_UINT64_TYPE:
5907 ival = he->p.ui64p[element];
5908 /*@innerbreak@*/ break;
5909 }
5910 vhe->t = RPM_UINT64_TYPE;
5911 vhe->p.ui64p = &ival;
5912 vhe->c = he->c;
5913 vhe->ix = (he->c > 1 ? 0 : -1);
5914 if ((tagType(he->tag) & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
5915 vhe->ix = 0;
5916 break;
5917
5918 case RPM_BIN_TYPE:
5919 vhe->t = RPM_BIN_TYPE;
5920 vhe->p.ptr = he->p.ptr;
5921 vhe->c = he->c;
5922 vhe->ix = -1;
5923 break;
5924 }
5925
5926 /*@-compmempass@*/ /* vhe->p.ui64p is stack, not owned */
5927 if (tag->fmtfuncs) {
5928 char * nval;
5929 int i;
5930 for (i = 0; tag->av[i] != NULL; i++) {
5931 headerTagFormatFunction fmt;
5932 ARGV_t av;
5933 if ((fmt = tag->fmtfuncs[i]) == NULL)
5934 continue;
5935 /* If !1st formatter, and transformer, not extractor, save val. */
5936 if (val != NULL && *tag->av[i] == '|') {
5937 int ix = vhe->ix;
5938 vhe = rpmheClean(vhe);
5939 vhe->tag = he->tag;
5940 vhe->t = RPM_STRING_TYPE;
5941 vhe->p.str = xstrdup(val);
5942 vhe->c = he->c;
5943 vhe->ix = ix;
5944 vhe->freeData = 1;
5945 }
5946 av = NULL;
5947 if (tag->params && tag->params[i] && *tag->params[i] != '\0')
5948 xx = argvSplit(&av, tag->params[i], ",");
5949
5950 nval = fmt(vhe, av);
5951
5952 /*@-castfcnptr -modfilesys@*/
5953 if (_hdrqf_debug)
5954 fprintf(stderr, "\t%s(%s) %p(%p,%p) ret \"%s\"\n", tag->av[i], (tag->params ? tag->params[i] : NULL), (void *)fmt, (void *)vhe, (void *)(av ? av : NULL), (val ? val : "(null)"));
5955 /*@=castfcnptr =modfilesys@*/
5956
5957 /* Accumulate (by appending) next formmatter's return string. */
5958 if (val == NULL)
5959 val = xstrdup((nval ? nval : ""));
5960 else {
5961 char * oval = val;
5962 /* XXX using ... | ... as separator is feeble. */
5963 val = rpmExpand(val, (*val != '\0' ? " | " : ""), nval, NULL);
5964 oval = _free(oval);
5965 }
5966 nval = _free(nval);
5967 av = argvFree(av);
5968 }
5969 }
5970 if (val == NULL)
5971 val = intFormat(vhe, NULL, NULL);
5972 /*@=compmempass@*/
5973 assert(val != NULL);
5974 if (val)
5975 need = strlen(val) + 1;
5976
5977 exit:
5978 if (val && need > 0) {
5979 if (tag->format && *tag->format && tag->pad > 0) {
5980 size_t nb;
5981 nb = strlen(tag->format) + sizeof("%s");
5982 t = alloca(nb);
5983 (void) stpcpy( stpcpy( stpcpy(t, "%"), tag->format), "s");
5984 nb = tag->pad + strlen(val) + 1;
5985 te = xmalloc(nb);
5986 /*@-formatconst@*/
5987 (void) snprintf(te, nb, t, val);
5988 /*@=formatconst@*/
5989 te[nb-1] = '\0';
5990 val = _free(val);
5991 val = te;
5992 need += tag->pad;
5993 }
5994 t = hsaReserve(hsa, need);
5995 te = stpcpy(t, val);
5996 hsa->vallen += (te - t);
5997 val = _free(val);
5998 }
5999
6000 return (hsa->val + hsa->vallen);
6001 }
6002
6010 /*@observer@*/ /*@null@*/
6011 static char * singleSprintf(headerSprintfArgs hsa, sprintfToken token,
6012 size_t element)
6013 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
6014 /*@modifies hsa, token, rpmGlobalMacroContext, internalState @*/
6015 {
6016 char * t, * te;
6017 size_t i, j;
6018 size_t numElements;
6019 sprintfToken spft;
6020 sprintfTag tag = NULL;
6021 HE_t he = NULL;
6022 size_t condNumFormats;
6023 size_t need;
6024 int xx;
6025
6026 /* we assume the token and header have been validated already! */
6027
6028 switch (token->type) {
6029 case PTOK_NONE:
6030 break;
6031
6032 case PTOK_STRING:
6033 need = token->u.string.len;
6034 if (need == 0) break;
6035 t = hsaReserve(hsa, need);
6036 te = stpcpy(t, token->u.string.string);
6037 hsa->vallen += (te - t);
6038 break;
6039
6040 case PTOK_TAG:
6041 t = hsa->val + hsa->vallen;
6042 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6043 te = formatValue(hsa, &token->u.tag,
6044 (token->u.tag.justOne ? 0 : element));
6045 /*@=modobserver@*/
6046 if (te == NULL)
6047 return NULL;
6048 break;
6049
6050 case PTOK_COND:
6051 if (token->u.cond.tag.ext
6052 || headerIsEntry(hsa->h, token->u.cond.tag.tagno[0]))
6053 {
6054 spft = token->u.cond.ifFormat;
6055 condNumFormats = token->u.cond.numIfTokens;
6056 } else {
6057 spft = token->u.cond.elseFormat;
6058 condNumFormats = token->u.cond.numElseTokens;
6059 }
6060
6061 need = condNumFormats * 20;
6062 if (spft == NULL || need == 0) break;
6063
6064 t = hsaReserve(hsa, need);
6065 for (i = 0; i < condNumFormats; i++, spft++) {
6066 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6067 te = singleSprintf(hsa, spft, element);
6068 /*@=modobserver@*/
6069 if (te == NULL)
6070 return NULL;
6071 }
6072 break;
6073
6074 case PTOK_ARRAY:
6075 numElements = 0;
6076 spft = token->u.array.format;
6077 for (i = 0; i < token->u.array.numTokens; i++, spft++)
6078 {
6079 tag = &spft->u.tag;
6080 if (spft->type != PTOK_TAG || tag->arrayCount || tag->justOne)
6081 continue;
6082 he = &tag->he;
6083 if (!he->avail) {
6084 he->tag = tag->tagno[0];
6085 if (tag->ext)
6086 xx = getExtension(hsa, tag->ext, he, hsa->ec + tag->extNum);
6087 else
6088 xx = headerGet(hsa->h, he, 0);
6089 if (!xx) {
6090 (void) rpmheClean(he);
6091 continue;
6092 }
6093 he->avail = 1;
6094 }
6095
6096 /* Check iteration arrays are same dimension (or scalar). */
6097 switch (he->t) {
6098 default:
6099 if (numElements == 0) {
6100 numElements = he->c;
6101 /*@switchbreak@*/ break;
6102 }
6103 if ((size_t)he->c == numElements)
6104 /*@switchbreak@*/ break;
6105 hsa->errmsg =
6106 _("array iterator used with different sized arrays");
6107 he = rpmheClean(he);
6108 return NULL;
6109 /*@notreached@*/ /*@switchbreak@*/ break;
6110 case RPM_BIN_TYPE:
6111 case RPM_STRING_TYPE:
6112 if (numElements == 0)
6113 numElements = 1;
6114 /*@switchbreak@*/ break;
6115 }
6116 }
6117 spft = token->u.array.format;
6118
6119 if (numElements == 0) {
6120 #ifdef DYING /* XXX lots of pugly "(none)" lines with --conflicts. */
6121 need = sizeof("(none)\n") - 1;
6122 t = hsaReserve(hsa, need);
6123 te = stpcpy(t, "(none)\n");
6124 hsa->vallen += (te - t);
6125 #endif
6126 } else {
6127 int isxml;
6128 int isyaml;
6129
6130 need = numElements * token->u.array.numTokens;
6131 if (need == 0) break;
6132
6133 tag = &spft->u.tag;
6134
6135 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
6136 isxml = (spft->type == PTOK_TAG && tag->av != NULL &&
6137 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"));
6138 isyaml = (spft->type == PTOK_TAG && tag->av != NULL &&
6139 tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"));
6140
6141 if (isxml) {
6142 const char * tagN;
6143 /* XXX display "Tag_0x01234567" for arbitrary tags. */
6144 if (tag->tagno != NULL && tag->tagno[0] & 0x40000000) {
6145 tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6146 } else
6147 tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6148 assert(tagN != NULL); /* XXX can't happen */
6149 need = sizeof(" <rpmTag name=\"\">\n") + strlen(tagN);
6150 te = t = hsaReserve(hsa, need);
6151 te = stpcpy( stpcpy( stpcpy(te, " <rpmTag name=\""), tagN), "\">\n");
6152 hsa->vallen += (te - t);
6153 }
6154 if (isyaml) {
6155 rpmTagReturnType tagT = 0;
6156 const char * tagN;
6157 /* XXX display "Tag_0x01234567" for arbitrary tags. */
6158 if (tag->tagno != NULL && tag->tagno[0] & 0x40000000) {
6159 tagN = myTagName(hsa->tags, tag->tagno[0], NULL);
6160 tagT = numElements > 1
6161 ? RPM_ARRAY_RETURN_TYPE : RPM_SCALAR_RETURN_TYPE;
6162 } else
6163 tagN = myTagName(hsa->tags, tag->tagno[0], &tagT);
6164 assert(tagN != NULL); /* XXX can't happen */
6165 need = sizeof(" : - ") + strlen(tagN);
6166 te = t = hsaReserve(hsa, need);
6167 *te++ = ' ';
6168 *te++ = ' ';
6169 te = stpcpy(te, tagN);
6170 *te++ = ':';
6171 *te++ = (((tagT & RPM_MASK_RETURN_TYPE) == RPM_ARRAY_RETURN_TYPE)
6172 ? '\n' : ' ');
6173 *te = '\0';
6174 hsa->vallen += (te - t);
6175 }
6176
6177 need = numElements * token->u.array.numTokens * 10;
6178 t = hsaReserve(hsa, need);
6179 for (j = 0; j < numElements; j++) {
6180 spft = token->u.array.format;
6181 for (i = 0; i < token->u.array.numTokens; i++, spft++) {
6182 /*@-modobserver@*/ /* headerCompoundFormats not modified. */
6183 te = singleSprintf(hsa, spft, j);
6184 /*@=modobserver@*/
6185 if (te == NULL)
6186 return NULL;
6187 }
6188 }
6189
6190 if (isxml) {
6191 need = sizeof(" </rpmTag>\n") - 1;
6192 te = t = hsaReserve(hsa, need);
6193 te = stpcpy(te, " </rpmTag>\n");
6194 hsa->vallen += (te - t);
6195 }
6196 if (isyaml) {
6197 #if 0
6198 need = sizeof("\n") - 1;
6199 te = t = hsaReserve(hsa, need);
6200 te = stpcpy(te, "\n");
6201 hsa->vallen += (te - t);
6202 #endif
6203 }
6204
6205 }
6206 break;
6207 }
6208
6209 return (hsa->val + hsa->vallen);
6210 }
6211
6218 static /*@only@*/ HE_t
6219 rpmecNew(const headerSprintfExtension exts, /*@null@*/ int * necp)
6220 /*@modifies *necp @*/
6221 {
6222 headerSprintfExtension ext;
6223 HE_t ec;
6224 int extNum = 0;
6225
6226 if (exts != NULL)
6227 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
6228 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
6229 {
6230 ;
6231 }
6232 if (necp)
6233 *necp = extNum;
6234 ec = xcalloc(extNum+1, sizeof(*ec)); /* XXX +1 unnecessary */
6235 return ec;
6236 }
6237
6244 static /*@null@*/ HE_t
6245 rpmecFree(const headerSprintfExtension exts, /*@only@*/ HE_t ec)
6246 /*@modifies ec @*/
6247 {
6248 headerSprintfExtension ext;
6249 int extNum;
6250
6251 for (ext = exts, extNum = 0; ext != NULL && ext->type != HEADER_EXT_LAST;
6252 ext = (ext->type == HEADER_EXT_MORE ? *ext->u.more : ext+1), extNum++)
6253 {
6254 (void) rpmheClean(&ec[extNum]);
6255 }
6256
6257 ec = _free(ec);
6258 return NULL;
6259 }
6260
6261 char * headerSprintf(Header h, const char * fmt,
6262 headerTagTableEntry tags,
6263 headerSprintfExtension exts,
6264 errmsg_t * errmsg)
6265 {
6266 headerSprintfArgs hsa = memset(alloca(sizeof(*hsa)), 0, sizeof(*hsa));
6267 sprintfToken nextfmt;
6268 sprintfTag tag;
6269 char * t, * te;
6270 int isxml;
6271 int isyaml;
6272 int need;
6273
6274 /*@-modfilesys@*/
6275 if (_hdrqf_debug)
6276 fprintf(stderr, "==> headerSprintf(%p, \"%s\", %p, %p, %p)\n", h, fmt, tags, exts, errmsg);
6277 /*@=modfilesys@*/
6278
6279 /* Set some reasonable defaults */
6280 if (tags == NULL)
6281 tags = rpmTagTable;
6282 /* XXX this loses the extensions in lib/formats.c. */
6283 if (exts == NULL)
6284 exts = headerCompoundFormats;
6285
6286 /*@-assignexpose -castexpose @*/
6287 hsa->h = headerLink(h);
6288 /*@=assignexpose =castexpose @*/
6289 hsa->fmt = xstrdup(fmt);
6290 /*@-assignexpose -dependenttrans@*/
6291 hsa->exts = exts;
6292 hsa->tags = tags;
6293 /*@=assignexpose =dependenttrans@*/
6294 hsa->errmsg = NULL;
6295
6296 if (parseFormat(hsa, hsa->fmt, &hsa->format, &hsa->numTokens, NULL, PARSER_BEGIN))
6297 goto exit;
6298
6299 hsa->nec = 0;
6300 hsa->ec = rpmecNew(hsa->exts, &hsa->nec);
6301 hsa->val = xstrdup("");
6302
6303 tag =
6304 (hsa->format->type == PTOK_TAG
6305 ? &hsa->format->u.tag :
6306 (hsa->format->type == PTOK_ARRAY
6307 ? &hsa->format->u.array.format->u.tag :
6308 NULL));
6309
6310 /* XXX Ick: +1 needed to handle :extractor |transformer marking. */
6311 isxml = (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 && tag->av != NULL
6312 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "xml"));
6313 isyaml = (tag != NULL && tag->tagno != NULL && tag->tagno[0] == (rpmTag)-2 && tag->av != NULL
6314 && tag->av[0] != NULL && !strcmp(tag->av[0]+1, "yaml"));
6315
6316 if (isxml) {
6317 need = sizeof("<rpmHeader>\n") - 1;
6318 t = hsaReserve(hsa, need);
6319 te = stpcpy(t, "<rpmHeader>\n");
6320 hsa->vallen += (te - t);
6321 }
6322 if (isyaml) {
6323 need = sizeof("- !!omap\n") - 1;
6324 t = hsaReserve(hsa, need);
6325 te = stpcpy(t, "- !!omap\n");
6326 hsa->vallen += (te - t);
6327 }
6328
6329 hsa = hsaInit(hsa);
6330 while ((nextfmt = hsaNext(hsa)) != NULL) {
6331 /*@-globs -mods@*/ /* XXX rpmGlobalMacroContext @*/
6332 te = singleSprintf(hsa, nextfmt, 0);
6333 /*@=globs =mods @*/
6334 if (te == NULL) {
6335 hsa->val = _free(hsa->val);
6336 break;
6337 }
6338 }
6339 hsa = hsaFini(hsa);
6340
6341 if (isxml) {
6342 need = sizeof("</rpmHeader>\n") - 1;
6343 t = hsaReserve(hsa, need);
6344 te = stpcpy(t, "</rpmHeader>\n");
6345 hsa->vallen += (te - t);
6346 }
6347 if (isyaml) {
6348 need = sizeof("\n") - 1;
6349 t = hsaReserve(hsa, need);
6350 te = stpcpy(t, "\n");
6351 hsa->vallen += (te - t);
6352 }
6353
6354 if (hsa->val != NULL && hsa->vallen < hsa->alloced)
6355 hsa->val = xrealloc(hsa->val, hsa->vallen+1);
6356
6357 hsa->ec = rpmecFree(hsa->exts, hsa->ec);
6358 hsa->nec = 0;
6359 hsa->format = freeFormat(hsa->format, hsa->numTokens);
6360
6361 exit:
6362 /*@-dependenttrans -observertrans @*/
6363 if (errmsg)
6364 *errmsg = hsa->errmsg;
6365 /*@=dependenttrans =observertrans @*/
6366 (void)headerFree(hsa->h);
6367 hsa->h = NULL;
6368 hsa->fmt = _free(hsa->fmt);
6369 /*@-retexpose@*/
6370 return hsa->val;
6371 /*@=retexpose@*/
6372 }