rpm  5.2.1
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@*/
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;
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:
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 
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@*/
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,
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,
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,
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,
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] == '/')
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;
3150 }
3151 
3152 static int RxmlTag(Header h, HE_t he)
3153  /*@globals internalState @*/
3154  /*@modifies he, internalState @*/
3155 {
3156  he->tag = RPMTAG_REQUIRENAME;
3158 }
3159 
3160 static int CxmlTag(Header h, HE_t he)
3161  /*@globals internalState @*/
3162  /*@modifies he, internalState @*/
3163 {
3164  he->tag = RPMTAG_CONFLICTNAME;
3166 }
3167 
3168 static int OxmlTag(Header h, HE_t he)
3169  /*@globals internalState @*/
3170  /*@modifies he, internalState @*/
3171 {
3172  he->tag = RPMTAG_OBSOLETENAME;
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;
3375 }
3376 
3377 static int RsqlTag(Header h, HE_t he)
3378  /*@globals internalState @*/
3379  /*@modifies he, internalState @*/
3380 {
3381  he->tag = RPMTAG_REQUIRENAME;
3383 }
3384 
3385 static int CsqlTag(Header h, HE_t he)
3386  /*@globals internalState @*/
3387  /*@modifies he, internalState @*/
3388 {
3389  he->tag = RPMTAG_CONFLICTNAME;
3391 }
3392 
3393 static int OsqlTag(Header h, HE_t he)
3394  /*@globals internalState @*/
3395  /*@modifies he, internalState @*/
3396 {
3397  he->tag = RPMTAG_OBSOLETENAME;
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;
3502 }
3503 
3504 static int RyamlTag(Header h, HE_t he)
3505  /*@globals internalState @*/
3506  /*@modifies he, internalState @*/
3507 {
3508  he->tag = RPMTAG_REQUIRENAME;
3510 }
3511 
3512 static int CyamlTag(Header h, HE_t he)
3513  /*@globals internalState @*/
3514  /*@modifies he, internalState @*/
3515 {
3516  he->tag = RPMTAG_CONFLICTNAME;
3518 }
3519 
3520 static int OyamlTag(Header h, HE_t he)
3521  /*@globals internalState @*/
3522  /*@modifies he, internalState @*/
3523 {
3524  he->tag = RPMTAG_OBSOLETENAME;
3526 }
3527 
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 */
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 
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 
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 
4854 {
4855  const struct headerTagTableEntry_s * t;
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 
4932 /*@null@*/
4933  headerTagFormatFunction * fmtfuncs;
4934 /*@null@*/
4935  headerTagTagFunction ext;
4936  int extNum;
4937 /*@only@*/ /*@relnull@*/
4939  int justOne;
4941 /*@kept@*/
4942  char * format;
4943 /*@only@*/ /*@relnull@*/
4945 /*@only@*/ /*@relnull@*/
4947  unsigned pad;
4948 };
4949 
4952 typedef /*@abstract@*/ struct sprintfToken_s * sprintfToken;
4953 
4957  enum {
4963  } type;
4964  union {
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;
4983  struct sprintfTag_s tag;
4984  } cond;
4985  } u;
4986 };
4987 
4990 typedef /*@abstract@*/ struct headerSprintfArgs_s * headerSprintfArgs;
4991 
4996  char * fmt;
4997 /*@observer@*/ /*@temp@*/
4999 /*@observer@*/ /*@temp@*/
5001 /*@observer@*/ /*@null@*/
5002  const char * errmsg;
5004  int nec;
5005  sprintfToken format;
5006 /*@relnull@*/
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 
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;
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);
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
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 {
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 {
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,
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 }