rpm  4.5
formats.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include "rpmio_internal.h"
8 #include <rpmlib.h>
9 #include <rpmmacro.h> /* XXX for %_i18ndomains */
10 #include <rpmuuid.h>
11 
12 #define _RPMEVR_INTERNAL
13 #include <rpmds.h>
14 #include <rpmfi.h>
15 
16 #include "legacy.h"
17 #include "argv.h"
18 #include "ugid.h"
19 #include "misc.h"
20 #include "fs.h"
21 
22 #include "debug.h"
23 
24 /*@access pgpDig @*/
25 /*@access pgpDigParams @*/
26 
27 /* XXX FIXME: static for now, refactor from manifest.c later. */
28 static char * rpmPermsString(int mode)
29  /*@*/
30 {
31  char *perms = xstrdup("----------");
32 
33  if (S_ISREG(mode))
34  perms[0] = '-';
35  else if (S_ISDIR(mode))
36  perms[0] = 'd';
37  else if (S_ISLNK(mode))
38  perms[0] = 'l';
39  else if (S_ISFIFO(mode))
40  perms[0] = 'p';
41  /*@-unrecog@*/
42  else if (S_ISSOCK(mode))
43  perms[0] = 's';
44  /*@=unrecog@*/
45  else if (S_ISCHR(mode))
46  perms[0] = 'c';
47  else if (S_ISBLK(mode))
48  perms[0] = 'b';
49  else
50  perms[0] = '?';
51 
52  if (mode & S_IRUSR) perms[1] = 'r';
53  if (mode & S_IWUSR) perms[2] = 'w';
54  if (mode & S_IXUSR) perms[3] = 'x';
55 
56  if (mode & S_IRGRP) perms[4] = 'r';
57  if (mode & S_IWGRP) perms[5] = 'w';
58  if (mode & S_IXGRP) perms[6] = 'x';
59 
60  if (mode & S_IROTH) perms[7] = 'r';
61  if (mode & S_IWOTH) perms[8] = 'w';
62  if (mode & S_IXOTH) perms[9] = 'x';
63 
64  if (mode & S_ISUID)
65  perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
66 
67  if (mode & S_ISGID)
68  perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
69 
70  if (mode & S_ISVTX)
71  perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
72 
73  return perms;
74 }
75 
82 static /*@only@*/ char * triggertypeFormat(HE_t he, /*@null@*/ const char ** av)
83 {
84  rpmTagData data = { .ptr = he->p.ptr };
85  int ix = (he->ix > 0 ? he->ix : 0);
86  char * val;
87 
88 assert(ix == 0);
89  if (he->t != RPM_INT64_TYPE)
90  val = xstrdup(_("(invalid type)"));
91  else {
92  int anint = data.i64p[ix];
93  if (anint & RPMSENSE_TRIGGERPREIN)
94  val = xstrdup("prein");
95  else if (anint & RPMSENSE_TRIGGERIN)
96  val = xstrdup("in");
97  else if (anint & RPMSENSE_TRIGGERUN)
98  val = xstrdup("un");
99  else if (anint & RPMSENSE_TRIGGERPOSTUN)
100  val = xstrdup("postun");
101  else
102  val = xstrdup("");
103  }
104  return val;
105 }
106 
113 static /*@only@*/ char * permsFormat(HE_t he, /*@null@*/ const char ** av)
114 {
115  int ix = (he->ix > 0 ? he->ix : 0);
116  char * val;
117 
118 assert(ix == 0);
119  if (he->t != RPM_INT64_TYPE) {
120  val = xstrdup(_("(invalid type)"));
121  } else {
122  int_32 anint = he->p.i64p[0];
123  val = rpmPermsString(anint);
124  }
125 
126  return val;
127 }
128 
135 static /*@only@*/ char * fflagsFormat(HE_t he, /*@null@*/ const char ** av)
136 {
137  rpmTagData data = { .ptr = he->p.ptr };
138  int ix = (he->ix >= 0 ? he->ix : 0);
139  char * val;
140 
141 assert(ix == 0);
142  if (he->t != RPM_INT64_TYPE) {
143  val = xstrdup(_("(invalid type)"));
144  } else {
145  char buf[15];
146  unsigned anint = data.i64p[ix];
147  buf[0] = '\0';
148  if (anint & RPMFILE_DOC)
149  strcat(buf, "d");
150  if (anint & RPMFILE_CONFIG)
151  strcat(buf, "c");
152  if (anint & RPMFILE_SPECFILE)
153  strcat(buf, "s");
154  if (anint & RPMFILE_MISSINGOK)
155  strcat(buf, "m");
156  if (anint & RPMFILE_NOREPLACE)
157  strcat(buf, "n");
158  if (anint & RPMFILE_GHOST)
159  strcat(buf, "g");
160  if (anint & RPMFILE_LICENSE)
161  strcat(buf, "l");
162  if (anint & RPMFILE_README)
163  strcat(buf, "r");
164  val = xstrdup(buf);
165  }
166 
167  return val;
168 }
169 
177 static /*@only@*/ char * armorFormat(HE_t he, /*@null@*/ const char ** av)
178  /*@*/
179 {
180  rpmTagData data = { .ptr = he->p.ptr };
181  int ix = (he->ix > 0 ? he->ix : 0);
182  const char * enc;
183  const unsigned char * s;
184  size_t ns;
185  int atype;
186  char * val;
187 
188 assert(ix == 0);
189  switch (he->t) {
190  case RPM_OPENPGP_TYPE:
191  case RPM_ASN1_TYPE: /* XXX WRONG */
192  case RPM_BIN_TYPE:
193  s = data.ui8p;
194  ns = he->c;
195  atype = PGPARMOR_SIGNATURE; /* XXX check pkt for signature */
196  break;
197  case RPM_STRING_TYPE:
199  enc = data.str;
200  s = NULL;
201  ns = 0;
202 /*@-moduncon@*/
203  if (b64decode(enc, (void **)&s, &ns))
204  return xstrdup(_("(not base64)"));
205 /*@=moduncon@*/
206  atype = PGPARMOR_PUBKEY; /* XXX check pkt for pubkey */
207  break;
208  case RPM_NULL_TYPE:
209  case RPM_CHAR_TYPE:
210  case RPM_INT8_TYPE:
211  case RPM_INT16_TYPE:
212  case RPM_INT32_TYPE:
213  case RPM_INT64_TYPE:
214  case RPM_I18NSTRING_TYPE:
215  default:
216  return xstrdup(_("(invalid type)"));
217  /*@notreached@*/ break;
218  }
219 
220  val = pgpArmorWrap(atype, s, ns);
221  if (atype == PGPARMOR_PUBKEY)
222  s = _free(s);
223  return val;
224 }
225 
233 static /*@only@*/ char * base64Format(HE_t he, /*@null@*/ const char ** av)
234  /*@*/
235 {
236  rpmTagData data = { .ptr = he->p.ptr };
237  int ix = (he->ix > 0 ? he->ix : 0);
238  char * val;
239 
240 assert(ix == 0);
241  if (!(he->t == RPM_BIN_TYPE || he->t == RPM_ASN1_TYPE || he->t == RPM_OPENPGP_TYPE)) {
242  val = xstrdup(_("(not a blob)"));
243  } else {
244  const char * enc;
245  char * t;
246  int lc;
247  size_t ns = he->c;
248  size_t nt = ((ns + 2) / 3) * 4;
249 
250  /*@-globs@*/
251  /* Add additional bytes necessary for eol string(s). */
252  if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
253  lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
254  if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
255  ++lc;
256  nt += lc * strlen(b64encode_eolstr);
257  }
258  /*@=globs@*/
259 
260  val = t = xcalloc(1, nt + 1);
261  *t = '\0';
262 
263  /* XXX b64encode accesses uninitialized memory. */
264  { unsigned char * _data = xcalloc(1, ns+1);
265  memcpy(_data, data.ptr, ns);
266 /*@-moduncon@*/
267  if ((enc = b64encode(_data, ns)) != NULL) {
268  t = stpcpy(t, enc);
269  enc = _free(enc);
270  }
271 /*@=moduncon@*/
272  _data = _free(_data);
273  }
274  }
275 
276 /*@-globstate@*/
277  return val;
278 /*@=globstate@*/
279 }
280 
286 static size_t xmlstrlen(const char * s)
287  /*@*/
288 {
289  size_t len = 0;
290  int c;
291 
292  while ((c = *s++) != '\0')
293  {
294  switch (c) {
295  case '<':
296  case '>': len += sizeof("&lt;") - 1; /*@switchbreak@*/ break;
297  case '&': len += sizeof("&amp;") - 1; /*@switchbreak@*/ break;
298  default: len += 1; /*@switchbreak@*/ break;
299  }
300  }
301  return len;
302 }
303 
310 static char * xmlstrcpy(/*@returned@*/ char * t, const char * s)
311  /*@modifies t @*/
312 {
313  char * te = t;
314  int c;
315 
316  while ((c = *s++) != '\0') {
317  switch (c) {
318  case '<': te = stpcpy(te, "&lt;"); /*@switchbreak@*/ break;
319  case '>': te = stpcpy(te, "&gt;"); /*@switchbreak@*/ break;
320  case '&': te = stpcpy(te, "&amp;"); /*@switchbreak@*/ break;
321  default: *te++ = c; /*@switchbreak@*/ break;
322  }
323  }
324  *te = '\0';
325  return t;
326 }
327 
328 static /*@only@*/ /*@null@*/ char *
329 strdup_locale_convert (/*@null@*/ const char * buffer,
330  /*@null@*/ const char * tocode)
331  /*@*/
332 {
333  char *dest_str;
334 #if defined(HAVE_ICONV)
335  char *fromcode = NULL;
336  iconv_t fd;
337 
338  if (buffer == NULL)
339  return NULL;
340 
341  if (tocode == NULL)
342  tocode = "UTF-8";
343 
344 #ifdef HAVE_LANGINFO_H
345 /*@-type@*/
346  fromcode = nl_langinfo (CODESET);
347 /*@=type@*/
348 #endif
349 
350  if (fromcode != NULL && strcmp(tocode, fromcode) != 0
351  && (fd = iconv_open(tocode, fromcode)) != (iconv_t)-1)
352  {
353  const char *pin = buffer;
354  char *pout = NULL;
355  size_t ib, ob, dest_size;
356  int done;
357  int is_error;
358  size_t err;
359  const char *shift_pin = NULL;
360  int xx;
361 
362  err = iconv(fd, NULL, &ib, &pout, &ob);
363  dest_size = ob = ib = strlen(buffer);
364  dest_str = pout = malloc((dest_size + 1) * sizeof(*dest_str));
365  if (dest_str)
366  *dest_str = '\0';
367  done = is_error = 0;
368  if (pout != NULL)
369  while (done == 0 && is_error == 0) {
370  err = iconv(fd, (char **)&pin, &ib, &pout, &ob);
371 
372  if (err == (size_t)-1) {
373  switch (errno) {
374  case EINVAL:
375  done = 1;
376  /*@switchbreak@*/ break;
377  case E2BIG:
378  { size_t used = (size_t)(pout - dest_str);
379  dest_size *= 2;
380  dest_str = realloc(dest_str, (dest_size + 1) * sizeof(*dest_str));
381  if (dest_str == NULL) {
382  is_error = 1;
383  continue;
384  }
385  pout = dest_str + used;
386  ob = dest_size - used;
387  } /*@switchbreak@*/ break;
388  case EILSEQ:
389  is_error = 1;
390  /*@switchbreak@*/ break;
391  default:
392  is_error = 1;
393  /*@switchbreak@*/ break;
394  }
395  } else {
396  if (shift_pin == NULL) {
397  shift_pin = pin;
398  pin = NULL;
399  ib = 0;
400  } else {
401  done = 1;
402  }
403  }
404  }
405  xx = iconv_close(fd);
406  if (pout)
407  *pout = '\0';
408  if (dest_str != NULL)
409  dest_str = xstrdup(dest_str);
410  } else
411 #endif
412  {
413  dest_str = xstrdup((buffer ? buffer : ""));
414  }
415 
416  return dest_str;
417 }
418 
425 static /*@only@*/ char * cdataFormat(HE_t he, /*@null@*/ const char ** av)
426  /*@*/
427 {
428  int ix = (he->ix > 0 ? he->ix : 0);
429  char * val;
430 
431 assert(ix == 0);
432  if (he->t != RPM_STRING_TYPE) {
433  val = xstrdup(_("(not a string)"));
434  } else {
435  const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
436  size_t nb = xmlstrlen(s);
437  char * t;
438 
439  val = t = xcalloc(1, nb + 1);
440  t = xmlstrcpy(t, s); t += strlen(t);
441  *t = '\0';
442  s = _free(s);
443  }
444 
445 /*@-globstate@*/
446  return val;
447 /*@=globstate@*/
448 }
449 
456 static /*@only@*/ char * iconvFormat(HE_t he, /*@null@*/ const char ** av)
457  /*@*/
458 {
459  int ix = (he->ix > 0 ? he->ix : 0);
460  char * val;
461 
462 assert(ix == 0);
463  if (he->t != RPM_STRING_TYPE) {
464  val = xstrdup(_("(not a string)"));
465  } else {
466  val = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
467  }
468 
469 /*@-globstate@*/
470  return val;
471 /*@=globstate@*/
472 }
473 
480 static /*@only@*/ char * xmlFormat(HE_t he, /*@null@*/ const char ** av)
481  /*@*/
482 {
483  rpmTagData data = { .ptr = he->p.ptr };
484  int ix = (he->ix > 0 ? he->ix : 0);
485  const char * xtag = NULL;
486  size_t nb;
487  char * val;
488  const char * s = NULL;
489  char * t, * te;
490  unsigned long long anint = 0;
491  int freeit = 0;
492  int xx;
493 
494 assert(ix == 0);
495 assert(he->t == RPM_STRING_TYPE || he->t == RPM_INT64_TYPE || he->t == RPM_BIN_TYPE);
496  switch (he->t) {
498  s = data.argv[ix];
499  xtag = "string";
500  /* XXX Force utf8 strings. */
501  s = xstrdup(s);
502  s = xstrtolocale(s);
503  freeit = 1;
504  break;
505  case RPM_I18NSTRING_TYPE:
506  case RPM_STRING_TYPE:
507  s = data.str;
508  xtag = "string";
509  /* XXX Force utf8 strings. */
510  s = xstrdup(s);
511  s = xstrtolocale(s);
512  freeit = 1;
513  break;
514  case RPM_OPENPGP_TYPE:
515  case RPM_ASN1_TYPE:
516  case RPM_BIN_TYPE:
517 /*@-globs -mods@*/
518  { int cpl = b64encode_chars_per_line;
519  b64encode_chars_per_line = 0;
520 /*@-formatconst@*/
521  s = base64Format(he, NULL);
522 /*@=formatconst@*/
523  b64encode_chars_per_line = cpl;
524  xtag = "base64";
525  freeit = 1;
526  } break;
527 /*@=globs =mods@*/
528  case RPM_CHAR_TYPE:
529  case RPM_INT8_TYPE:
530  anint = data.i8p[ix];
531  break;
532  case RPM_INT16_TYPE:
533  anint = data.ui16p[ix]; /* XXX note unsigned */
534  break;
535  case RPM_INT32_TYPE:
536  anint = data.i32p[ix];
537  break;
538  case RPM_INT64_TYPE:
539  anint = data.i64p[ix];
540  break;
541  case RPM_NULL_TYPE:
542  default:
543  return xstrdup(_("(invalid xml type)"));
544  /*@notreached@*/ break;
545  }
546 
547  if (s == NULL) {
548  int tlen = 64;
549  t = memset(alloca(tlen+1), 0, tlen+1);
550 /*@-duplicatequals@*/
551  if (anint != 0)
552  xx = snprintf(t, tlen, "%llu", anint);
553 /*@=duplicatequals@*/
554  s = t;
555  xtag = "integer";
556  }
557 
558  nb = xmlstrlen(s);
559  if (nb == 0) {
560  nb += strlen(xtag) + sizeof("\t</>");
561  te = t = alloca(nb);
562  te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), "/>");
563  } else {
564  nb += 2 * strlen(xtag) + sizeof("\t<></>");
565  te = t = alloca(nb);
566  te = stpcpy( stpcpy( stpcpy(te, "\t<"), xtag), ">");
567  te = xmlstrcpy(te, s);
568  te += strlen(te);
569  te = stpcpy( stpcpy( stpcpy(te, "</"), xtag), ">");
570  }
571 
572  if (freeit)
573  s = _free(s);
574 
575  val = xstrdup(t);
576 
577  return val;
578 }
579 
586 static size_t yamlstrlen(const char * s, int lvl)
587  /*@*/
588 {
589  size_t len = 0;
590  int indent = (lvl > 0);
591  int c;
592 
593  while ((c = (int) *s++) != (int) '\0')
594  {
595  if (indent) {
596  len += 2 * lvl;
597  indent = 0;
598  }
599  if (c == (int) '\n')
600  indent = (lvl > 0);
601  len++;
602  }
603  return len;
604 }
605 
613 static char * yamlstrcpy(/*@out@*/ /*@returned@*/ char * t, const char * s, int lvl)
614  /*@modifies t @*/
615 {
616  char * te = t;
617  int indent = (lvl > 0);
618  int c;
619 
620  while ((c = (int) *s++) != (int) '\0') {
621  if (indent) {
622  int i;
623  for (i = 0; i < lvl; i++) {
624  *te++ = ' ';
625  *te++ = ' ';
626  }
627  indent = 0;
628  }
629  if (c == (int) '\n')
630  indent = (lvl > 0);
631  *te++ = (char) c;
632  }
633  *te = '\0';
634  return t;
635 }
636 
643 static /*@only@*/ char * yamlFormat(HE_t he, /*@null@*/ const char ** av)
644  /*@*/
645 {
646  int element = he->ix;
647  int ix = (he->ix > 0 ? he->ix : 0);
648  const char * xtag = NULL;
649  size_t nb;
650  char * val;
651  const char * s = NULL;
652  char * t, * te;
653  unsigned long long anint = 0;
654  int freeit = 0;
655  int lvl = 0;
656  int xx;
657  int c;
658 
659 assert(ix == 0);
660 assert(he->t == RPM_STRING_TYPE || he->t == RPM_UINT64_TYPE || he->t == RPM_BIN_TYPE);
661  xx = 0;
662  switch (he->t) {
663  case RPM_STRING_ARRAY_TYPE: /* XXX currently never happens */
664  case RPM_I18NSTRING_TYPE: /* XXX currently never happens */
665  case RPM_STRING_TYPE:
666  s = (he->t == RPM_STRING_ARRAY_TYPE ? he->p.argv[ix] : he->p.str);
667  if (strchr("[", s[0])) /* leading [ */
668  xx = 1;
669  if (xx == 0)
670  while ((c = (int) *s++) != (int) '\0') {
671  switch (c) {
672  default:
673  continue;
674  case '\n': /* multiline */
675  xx = 1;
676  /*@switchbreak@*/ break;
677  case '-': /* leading "- \"" */
678  case ':': /* embedded ": " or ":" at EOL */
679  if (s[0] != ' ' && s[0] != '\0' && s[1] != '"')
680  continue;
681  xx = 1;
682  /*@switchbreak@*/ break;
683  }
684  /*@loopbreak@*/ break;
685  }
686  if (xx) {
687  if (element >= 0) {
688  xtag = "- |-\n";
689  lvl = 3;
690  } else {
691  xtag = "|-\n";
692  lvl = 2;
693  if (he->ix < 0) lvl++; /* XXX extra indent for array[1] */
694  }
695  } else {
696  xtag = (element >= 0 ? "- " : NULL);
697  }
698 
699  /* XXX Force utf8 strings. */
700  s = xstrdup(he->p.str);
701  s = xstrtolocale(s);
702  freeit = 1;
703  break;
704  case RPM_OPENPGP_TYPE:
705  case RPM_ASN1_TYPE:
706  case RPM_BIN_TYPE:
707 /*@-globs -mods@*/
708  { int cpl = b64encode_chars_per_line;
709  b64encode_chars_per_line = 0;
710 /*@-formatconst@*/
711  s = base64Format(he, NULL);
712  element = -element; /* XXX skip " " indent. */
713 /*@=formatconst@*/
714  b64encode_chars_per_line = cpl;
715  xtag = "!!binary ";
716  freeit = 1;
717  } break;
718 /*@=globs =mods@*/
719  case RPM_CHAR_TYPE:
720  case RPM_UINT8_TYPE:
721  anint = he->p.ui8p[ix];
722  break;
723  case RPM_UINT16_TYPE:
724  anint = he->p.ui16p[ix];
725  break;
726  case RPM_UINT32_TYPE:
727  anint = he->p.ui32p[ix];
728  break;
729  case RPM_UINT64_TYPE:
730  anint = he->p.ui64p[ix];
731  break;
732  case RPM_NULL_TYPE:
733  default:
734  return xstrdup(_("(invalid yaml type)"));
735  /*@notreached@*/ break;
736  }
737 
738  if (s == NULL) {
739  int tlen = 64;
740  t = memset(alloca(tlen+1), 0, tlen+1);
741 /*@-duplicatequals@*/
742  xx = snprintf(t, tlen, "%llu", (unsigned long long)anint);
743 /*@=duplicatequals@*/
744  s = t;
745  xtag = (element >= 0 ? "- " : NULL);
746  }
747 
748  nb = yamlstrlen(s, lvl);
749  if (nb == 0) {
750  if (element >= 0)
751  nb += sizeof(" ") - 1;
752  nb += sizeof("- ~") - 1;
753  nb++;
754  te = t = alloca(nb);
755  if (element >= 0)
756  te = stpcpy(te, " ");
757  te = stpcpy(te, "- ~");
758  } else {
759  if (element >= 0)
760  nb += sizeof(" ") - 1;
761  if (xtag)
762  nb += strlen(xtag);
763  nb++;
764  te = t = alloca(nb);
765  if (element >= 0)
766  te = stpcpy(te, " ");
767  if (xtag)
768  te = stpcpy(te, xtag);
769  te = yamlstrcpy(te, s, lvl);
770  te += strlen(te);
771  }
772 
773  /* XXX s was malloc'd */
774  if (freeit)
775  s = _free(s);
776 
777  val = xstrdup(t);
778 
779  return val;
780 }
781 
788 static /*@only@*/ char * pgpsigFormat(HE_t he, /*@null@*/ const char ** av)
789  /*@globals fileSystem, internalState @*/
790  /*@modifies fileSystem, internalState @*/
791 {
792  rpmTagData data = { .ptr = he->p.ptr };
793  int ix = (he->ix > 0 ? he->ix : 0);
794  char * val, * t;
795 
796 assert(ix == 0);
797  if (!(he->t == RPM_BIN_TYPE || he->t == RPM_ASN1_TYPE || he->t == RPM_OPENPGP_TYPE)) {
798  val = xstrdup(_("(not a blob)"));
799  } else {
800  unsigned char * pkt = (byte *) data.ptr;
801  unsigned int pktlen = 0;
802  unsigned int v = *pkt;
803  pgpTag tag = 0;
804  unsigned int plen;
805  unsigned int hlen = 0;
806 
807  if (v & 0x80) {
808  if (v & 0x40) {
809  tag = (v & 0x3f);
810  plen = pgpLen(pkt+1, &hlen);
811  } else {
812  tag = (v >> 2) & 0xf;
813  plen = (1 << (v & 0x3));
814  hlen = pgpGrab(pkt+1, plen);
815  }
816 
817  pktlen = 1 + plen + hlen;
818  }
819 
820  if (pktlen == 0 || tag != PGPTAG_SIGNATURE) {
821  val = xstrdup(_("(not an OpenPGP signature)"));
822  } else {
823  pgpDig dig = pgpNewDig();
824  pgpDigParams sigp = &dig->signature;
825  size_t nb = 0;
826  const char *tempstr;
827 
828  (void) pgpPrtPkts(pkt, pktlen, dig, 0);
829 
830  val = NULL;
831  again:
832  nb += 100;
833  val = t = xrealloc(val, nb + 1);
834 
835  switch (sigp->pubkey_algo) {
836  case PGPPUBKEYALGO_DSA:
837  t = stpcpy(t, "DSA");
838  break;
839  case PGPPUBKEYALGO_RSA:
840  t = stpcpy(t, "RSA");
841  break;
842  default:
843  (void) snprintf(t, nb - (t - val), "%d", sigp->pubkey_algo);
844  t += strlen(t);
845  break;
846  }
847  if (t + 5 >= val + nb)
848  goto again;
849  *t++ = '/';
850  switch (sigp->hash_algo) {
851  case PGPHASHALGO_MD5:
852  t = stpcpy(t, "MD5");
853  break;
854  case PGPHASHALGO_SHA1:
855  t = stpcpy(t, "SHA1");
856  break;
857  default:
858  (void) snprintf(t, nb - (t - val), "%d", sigp->hash_algo);
859  t += strlen(t);
860  break;
861  }
862  if (t + strlen (", ") + 1 >= val + nb)
863  goto again;
864 
865  t = stpcpy(t, ", ");
866 
867  /* this is important if sizeof(int_32) ! sizeof(time_t) */
868  { time_t dateint = pgpGrab(sigp->time, sizeof(sigp->time));
869  struct tm * tstruct = localtime(&dateint);
870  if (tstruct)
871  (void) strftime(t, (nb - (t - val)), "%c", tstruct);
872  }
873  t += strlen(t);
874  if (t + strlen (", Key ID ") + 1 >= val + nb)
875  goto again;
876  t = stpcpy(t, ", Key ID ");
877  tempstr = pgpHexStr(sigp->signid, sizeof(sigp->signid));
878  if (t + strlen (tempstr) > val + nb)
879  goto again;
880  t = stpcpy(t, tempstr);
881 
882  dig = pgpFreeDig(dig);
883  }
884  }
885 
886  return val;
887 }
888 
895 static /*@only@*/ char * depflagsFormat(HE_t he, /*@null@*/ const char ** av)
896  /*@*/
897 {
898  rpmTagData data = { .ptr = he->p.ptr };
899  int ix = (he->ix > 0 ? he->ix : 0);;
900  char * val;
901 
902 assert(ix == 0);
903  if (he->t != RPM_INT64_TYPE) {
904  val = xstrdup(_("(invalid type)"));
905  } else {
906  int anint = data.i64p[ix];
907  char *t, *buf;
908 
909  t = buf = alloca(32);
910  *t = '\0';
911 
912 #ifdef NOTYET /* XXX appending markers breaks :depflags format. */
913  if (anint & RPMSENSE_SCRIPT_PRE)
914  t = stpcpy(t, "(pre)");
915  else if (anint & RPMSENSE_SCRIPT_POST)
916  t = stpcpy(t, "(post)");
917  else if (anint & RPMSENSE_SCRIPT_PREUN)
918  t = stpcpy(t, "(preun)");
919  else if (anint & RPMSENSE_SCRIPT_POSTUN)
920  t = stpcpy(t, "(postun)");
921 #endif
922  if (anint & RPMSENSE_SENSEMASK)
923  *t++ = ' ';
924  if (anint & RPMSENSE_LESS)
925  *t++ = '<';
926  if (anint & RPMSENSE_GREATER)
927  *t++ = '>';
928  if (anint & RPMSENSE_EQUAL)
929  *t++ = '=';
930  if (anint & RPMSENSE_SENSEMASK)
931  *t++ = ' ';
932  *t = '\0';
933 
934  val = xstrdup(buf);
935  }
936 
937  return val;
938 }
939 
946 static int instprefixTag(Header h, HE_t he)
947  /*@modifies he @*/
948 {
949  rpmTagType ipt;
950  rpmTagData array;
951 
953  if (headerGetEntry(h, RPMTAG_INSTALLPREFIX, (hTYP_t)&he->t, &he->p, &he->c)) {
954  he->freeData = 0;
955  return 0;
956  }
957  he->tag = RPMTAG_INSTPREFIXES;
958  if (headerGetEntry(h, he->tag, (hTYP_t)&ipt, &array, &he->c)) {
959  he->t = RPM_STRING_TYPE;
960  he->c = 1;
961  he->p.str = xstrdup(array.argv[0]);
962  he->freeData = 1;
963  array.ptr = headerFreeData(array.ptr, ipt);
964  return 0;
965  }
966  return 1;
967 }
968 
976 static int tv2uuidv1(Header h, HE_t he, struct timeval *tv)
977  /*@modifies he @*/
978 {
979  uint64_t uuid_time = ((uint64_t)tv->tv_sec * 10000000) +
980  (tv->tv_usec * 10) + 0x01B21DD213814000ULL;
981 
982  he->t = RPM_BIN_TYPE;
983  he->c = 128/8;
984  he->p.ptr = xcalloc(1, he->c);
985  he->freeData = 1;
986  if (rpmuuidMake(1, NULL, NULL, NULL, (unsigned char *)he->p.ui8p)) {
987  he->p.ptr = _free(he->p.ptr);
988  he->freeData = 0;
989  return 1;
990  }
991 
992  he->p.ui8p[6] &= 0xf0; /* preserve version, clear time_hi nibble */
993  he->p.ui8p[8] &= 0x3f; /* preserve reserved, clear clock */
994  he->p.ui8p[9] &= 0x00;
995 
996  he->p.ui8p[3] = (uuid_time >> 0);
997  he->p.ui8p[2] = (uuid_time >> 8);
998  he->p.ui8p[1] = (uuid_time >> 16);
999  he->p.ui8p[0] = (uuid_time >> 24);
1000  he->p.ui8p[5] = (uuid_time >> 32);
1001  he->p.ui8p[4] = (uuid_time >> 40);
1002  he->p.ui8p[6] |= (uuid_time >> 56) & 0x0f;
1003 
1004 #ifdef NOTYET
1005  /* XXX Jigger up a non-zero (but constant) clock value. Is this needed? */
1006  he->p.ui8p[8] |= (he->p.ui8p[2] & 0x3f);
1007  he->p.ui8p[9] |= he->p.ui8p[3]
1008 #endif
1009 
1010  return 0;
1011 }
1012 
1019 static int tag2uuidv1(Header h, HE_t he)
1020  /*@modifies he @*/
1021 {
1022  struct timeval tv;
1023 
1024  if (!headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c))
1025  return 1;
1026  tv.tv_sec = he->p.ui32p[0];
1027  tv.tv_usec = (he->c > 1 ? he->p.ui32p[1] : 0);
1028  he->p.ptr = headerFreeData(he->p.ptr, he->t);
1029  return tv2uuidv1(h, he, &tv);
1030 }
1031 
1039  /*@modifies he @*/
1040 {
1041  he->tag = RPMTAG_INSTALLTIME;
1042  return tag2uuidv1(h, he);
1043 }
1044 
1051 static int buildtime_uuidTag(Header h, HE_t he)
1052  /*@modifies he @*/
1053 {
1054  he->tag = RPMTAG_BUILDTIME;
1055  return tag2uuidv1(h, he);
1056 }
1057 
1064 static int origintime_uuidTag(Header h, HE_t he)
1065  /*@modifies he @*/
1066 {
1067  he->tag = RPMTAG_ORIGINTIME;
1068  return tag2uuidv1(h, he);
1069 }
1070 
1077 static int installtid_uuidTag(Header h, HE_t he)
1078  /*@modifies he @*/
1079 {
1080  he->tag = RPMTAG_INSTALLTID;
1081  return tag2uuidv1(h, he);
1082 }
1083 
1090 static int removetid_uuidTag(Header h, HE_t he)
1091  /*@modifies he @*/
1092 {
1093  he->tag = RPMTAG_REMOVETID;
1094  return tag2uuidv1(h, he);
1095 }
1096 
1103 static int origintid_uuidTag(Header h, HE_t he)
1104  /*@modifies he @*/
1105 {
1106  he->tag = RPMTAG_ORIGINTID;
1107  return tag2uuidv1(h, he);
1108 }
1109 
1110 /*@unchecked@*/ /*@observer@*/
1111 static const char uuid_ns[] = "ns:URL";
1112 /*@unchecked@*/ /*@observer@*/
1113 static const char uuid_auth[] = "%{?_uuid_auth}%{!?_uuid_auth:http://rpm5.org}";
1114 /*@unchecked@*/ /*@observer@*/
1115 static const char uuid_path[] = "%{?_uuid_path}%{!?_uuid_path:/package}";
1116 /*@unchecked@*/ /*@observer@*/
1117 static int uuid_version = 5;
1118 
1127 static int str2uuid(HE_t he, /*@null@*/ const char ** av,
1128  int version, /*@null@*/ char * val)
1129  /*@modifies he @*/
1130 {
1131  const char * ns = NULL;
1132  const char * tagn = tagName(he->tag);
1133  const char * s = NULL;
1134  int rc;
1135 
1136  /* XXX Substitute Pkgid & Hdrid strings for aliases. */
1137  if (!strcmp("Sigmd5", tagn))
1138  tagn = "Pkgid";
1139  else if (!strcmp("Sha1header", tagn))
1140  tagn = "Hdrid";
1141 
1142  switch (version) {
1143  default:
1144  version = uuid_version;
1145  /*@fallthrough@*/
1146  case 3:
1147  case 5:
1148 assert(he->t == RPM_STRING_TYPE);
1149  ns = uuid_ns;
1150  s = rpmGetPath(uuid_auth, "/", uuid_path, "/", tagn, "/",
1151  he->p.str, NULL);
1152  /*@fallthrough@*/
1153  case 4:
1154  break;
1155  }
1156  he->p.ptr = headerFreeData(he->p.ptr, he->t);
1157  he->t = RPM_BIN_TYPE;
1158  he->c = 128/8;
1159  he->p.ptr = xcalloc(1, he->c);
1160  he->freeData = 1;
1161  rc = rpmuuidMake(version, ns, s, val, (unsigned char *)he->p.ui8p);
1162  if (rc) {
1163  he->p.ptr = _free(he->p.ptr);
1164  he->freeData = 0;
1165  }
1166  s = _free(s);
1167  return rc;
1168 }
1169 
1176 static int tag2uuidv5(Header h, HE_t he)
1177  /*@modifies he @*/
1178 {
1179  if (!headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c))
1180  return 1;
1181  switch (he->t) {
1182  default:
1183 assert(0);
1184  /*@notreached@*/ break;
1185  case RPM_BIN_TYPE: { /* Convert RPMTAG_PKGID from binary => hex. */
1186  static const char hex[] = "0123456789abcdef";
1187  char * t;
1188  char * te;
1189  uint32_t i;
1190 
1191  t = te = xmalloc (2*he->c + 1);
1192  for (i = 0; i < he->c; i++) {
1193  *te++ = hex[ ((he->p.ui8p[i] >> 4) & 0x0f) ];
1194  *te++ = hex[ ((he->p.ui8p[i] ) & 0x0f) ];
1195  }
1196  *te = '\0';
1197  he->p.ptr = headerFreeData(he->p.ptr, he->t);
1198  he->t = RPM_STRING_TYPE;
1199  he->p.ptr = t;
1200  he->c = 1;
1201  he->freeData = 1;
1202  } break;
1203  case RPM_STRING_TYPE:
1204  break;
1205  }
1206  return str2uuid(he, NULL, 0, NULL);
1207 }
1208 
1215 static int pkguuidTag(Header h, HE_t he)
1216  /*@modifies he @*/
1217 {
1218  he->tag = RPMTAG_PKGID;
1219  return tag2uuidv5(h, he);
1220 }
1221 
1228 static int sourcepkguuidTag(Header h, HE_t he)
1229  /*@modifies he @*/
1230 {
1231  he->tag = RPMTAG_SOURCEPKGID;
1232  return tag2uuidv5(h, he);
1233 }
1234 
1241 static int hdruuidTag(Header h, HE_t he)
1242  /*@modifies he @*/
1243 {
1244  he->tag = RPMTAG_HDRID;
1245  return tag2uuidv5(h, he);
1246 }
1247 
1254 static int triggercondsTag(Header h, HE_t he)
1255  /*@modifies he @*/
1256 {
1257  HE_t _he = memset(alloca(sizeof(*_he)), 0, sizeof(*_he));
1258  rpmTagData flags;
1259  rpmTagData indices;
1260  rpmTagData names;
1261  rpmTagData versions;
1262  int numNames, numScripts;
1263  const char ** conds;
1264  rpmTagData s;
1265  char * item, * flagsStr;
1266  char * chptr;
1267  int i, j, xx;
1268 
1269  he->freeData = 0;
1270  xx = headerGetEntry(h, RPMTAG_TRIGGERNAME, NULL, &names, &numNames);
1271  if (!xx)
1272  return 0;
1273 
1274  _he->tag = he->tag;
1275  _he->t = RPM_INT32_TYPE;
1276  _he->p.i32p = NULL;
1277  _he->c = 1;
1278  _he->freeData = -1;
1279 
1280  xx = headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, &indices, NULL);
1281  xx = headerGetEntry(h, RPMTAG_TRIGGERFLAGS, NULL, &flags, NULL);
1282  xx = headerGetEntry(h, RPMTAG_TRIGGERVERSION, NULL, &versions, NULL);
1283  xx = headerGetEntry(h, RPMTAG_TRIGGERSCRIPTS, NULL, &s, &numScripts);
1284 
1285  he->t = RPM_STRING_ARRAY_TYPE;
1286  he->c = numScripts;
1287 
1288  he->freeData = 1;
1289  he->p.argv = conds = xmalloc(sizeof(*conds) * numScripts);
1290  for (i = 0; i < numScripts; i++) {
1291  chptr = xstrdup("");
1292 
1293  for (j = 0; j < numNames; j++) {
1294  if (indices.i32p[j] != i)
1295  /*@innercontinue@*/ continue;
1296 
1297  item = xmalloc(strlen(names.argv[j]) + strlen(versions.argv[j]) + 20);
1298  if (flags.i32p[j] & RPMSENSE_SENSEMASK) {
1299  _he->p.i32p = &flags.i32p[j];
1300  flagsStr = depflagsFormat(_he, NULL);
1301  sprintf(item, "%s %s %s", names.argv[j], flagsStr, versions.argv[j]);
1302  flagsStr = _free(flagsStr);
1303  } else
1304  strcpy(item, names.argv[j]);
1305 
1306  chptr = xrealloc(chptr, strlen(chptr) + strlen(item) + 5);
1307  if (*chptr != '\0') strcat(chptr, ", ");
1308  strcat(chptr, item);
1309  item = _free(item);
1310  }
1311 
1312  conds[i] = chptr;
1313  }
1314 
1315  names.ptr = headerFreeData(names.ptr, -1);
1316  versions.ptr = headerFreeData(versions.ptr, -1);
1317  s.ptr = headerFreeData(s.ptr, -1);
1318 
1319  return 0;
1320 }
1321 
1328 static int triggertypeTag(Header h, HE_t he)
1329  /*@modifies he @*/
1330 {
1331  rpmTagData indices;
1332  rpmTagData flags;
1333  const char ** conds;
1334  rpmTagData s;
1335  int i, j, xx;
1336  int numScripts, numNames;
1337 
1338  he->freeData = 0;
1339  if (!headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, &indices, &numNames))
1340  return 1;
1341 
1342  xx = headerGetEntry(h, RPMTAG_TRIGGERFLAGS, NULL, &flags, NULL);
1343  xx = headerGetEntry(h, RPMTAG_TRIGGERSCRIPTS, NULL, &s, &numScripts);
1344 
1345  he->t = RPM_STRING_ARRAY_TYPE;
1346  he->c = numScripts;
1347 
1348  he->freeData = 1;
1349  he->p.argv = conds = xmalloc(sizeof(*conds) * numScripts);
1350  for (i = 0; i < numScripts; i++) {
1351  for (j = 0; j < numNames; j++) {
1352  if (indices.i32p[j] != i)
1353  /*@innercontinue@*/ continue;
1354 
1355  if (flags.i32p[j] & RPMSENSE_TRIGGERPREIN)
1356  conds[i] = xstrdup("prein");
1357  else if (flags.i32p[j] & RPMSENSE_TRIGGERIN)
1358  conds[i] = xstrdup("in");
1359  else if (flags.i32p[j] & RPMSENSE_TRIGGERUN)
1360  conds[i] = xstrdup("un");
1361  else if (flags.i32p[j] & RPMSENSE_TRIGGERPOSTUN)
1362  conds[i] = xstrdup("postun");
1363  else
1364  conds[i] = xstrdup("");
1365  /*@innerbreak@*/ break;
1366  }
1367  }
1368 
1369  s.ptr = headerFreeData(s.ptr, -1);
1370  return 0;
1371 }
1372 
1373 /* I18N look aside diversions */
1374 
1375 #if defined(ENABLE_NLS)
1376 /*@-exportlocal -exportheadervar@*/
1377 /*@unchecked@*/
1378 extern int _nl_msg_cat_cntr; /* XXX GNU gettext voodoo */
1379 /*@=exportlocal =exportheadervar@*/
1380 #endif
1381 /*@observer@*/ /*@unchecked@*/
1382 static const char * language = "LANGUAGE";
1383 
1384 /*@observer@*/ /*@unchecked@*/
1385 static const char * _macro_i18ndomains = "%{?_i18ndomains}";
1386 
1393 static int i18nTag(Header h, HE_t he)
1394  /*@globals rpmGlobalMacroContext, h_errno @*/
1395  /*@modifies he, rpmGlobalMacroContext @*/
1396 {
1397  char * dstring = rpmExpand(_macro_i18ndomains, NULL);
1398  int rc = 1; /* assume failure */
1399 
1400  he->t = RPM_STRING_TYPE;
1401  he->p.str = NULL;
1402  he->c = 0;
1403  he->freeData = 0;
1404 
1405  if (dstring && *dstring) {
1406  char *domain, *de;
1407  const char * langval;
1408  const char * msgkey;
1409  const char * msgid;
1410 
1411  { const char * tn = tagName(he->tag);
1412  rpmTagData n = { .ptr = NULL };
1413  char * mk;
1414  size_t nb = sizeof("()");
1415  int xx = headerGetEntry(h, RPMTAG_NAME, NULL, &n, NULL);
1416  xx = 0; /* XXX keep gcc quiet */
1417  if (tn) nb += strlen(tn);
1418  if (n.str) nb += strlen(n.str);
1419  mk = alloca(nb);
1420  sprintf(mk, "%s(%s)", (n.str ? n.str : ""), (tn ? tn : ""));
1421  msgkey = mk;
1422  }
1423 
1424  /* change to en_US for msgkey -> msgid resolution */
1425  langval = getenv(language);
1426  (void) setenv(language, "en_US", 1);
1427 #if defined(ENABLE_NLS)
1428 /*@i@*/ ++_nl_msg_cat_cntr;
1429 #endif
1430 
1431  msgid = NULL;
1432  for (domain = dstring; domain != NULL; domain = de) {
1433  de = strchr(domain, ':');
1434  if (de) *de++ = '\0';
1435  msgid = /*@-unrecog@*/ dgettext(domain, msgkey) /*@=unrecog@*/;
1436  if (msgid != msgkey) break;
1437  }
1438 
1439  /* restore previous environment for msgid -> msgstr resolution */
1440  if (langval)
1441  (void) setenv(language, langval, 1);
1442  else
1443  unsetenv(language);
1444 #if defined(ENABLE_NLS)
1445 /*@i@*/ ++_nl_msg_cat_cntr;
1446 #endif
1447 
1448  if (domain && msgid) {
1449  const char * s = /*@-unrecog@*/ dgettext(domain, msgid) /*@=unrecog@*/;
1450  if (s) {
1451  rc = 0;
1452  he->p.str = xstrdup(s);
1453  he->c = 1;
1454  he->freeData = 1;
1455  }
1456  }
1457  }
1458 
1459 /*@-dependenttrans@*/
1460  dstring = _free(dstring);
1461 /*@=dependenttrans@*/
1462  if (!rc)
1463  return rc;
1464 
1465  rc = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
1466  if (rc) {
1467  rc = 0;
1468  he->p.str = xstrdup(he->p.str);
1469  he->p.str = xstrtolocale(he->p.str);
1470  he->freeData = 1;
1471 /*@-nullstate@*/
1472  return rc;
1473 /*@=nullstate@*/
1474  }
1475 
1476  he->t = RPM_STRING_TYPE;
1477  he->p.str = NULL;
1478  he->c = 0;
1479  he->freeData = 0;
1480 
1481  return 1;
1482 }
1483 
1487 static int localeTag(Header h, HE_t he)
1488  /*@modifies he @*/
1489 {
1490  rpmTagType t;
1491  rpmTagData p;
1492  rpmTagCount c;
1493  const char ** argv;
1494  char * te;
1495  int rc;
1496 
1497  rc = headerGetEntry(h, he->tag, (hTYP_t)&t, &p, &c);
1498  if (!rc || p.ptr == NULL || c == 0) {
1499  he->t = RPM_STRING_TYPE;
1500  he->p.str = NULL;
1501  he->c = 0;
1502  he->freeData = 0;
1503  return 1;
1504  }
1505 
1506  if (t == RPM_STRING_TYPE) {
1507  p.str = xstrdup(p.str);
1508  p.str = xstrtolocale(p.str);
1509  he->freeData = 1;
1510  } else if (t == RPM_STRING_ARRAY_TYPE) {
1511  size_t l = 0;
1512  int i;
1513  for (i = 0; i < c; i++) {
1514  p.argv[i] = xstrdup(p.argv[i]);
1515  p.argv[i] = xstrtolocale(p.argv[i]);
1516 assert(p.argv[i] != NULL);
1517  l += strlen(p.argv[i]) + 1;
1518  }
1519  argv = xmalloc(c * sizeof(*argv) + l);
1520  te = (char *)&argv[c];
1521  for (i = 0; i < c; i++) {
1522  argv[i] = te;
1523  te = stpcpy(te, p.argv[i]);
1524  te++;
1525  p.argv[i] = _free(p.argv[i]);
1526  }
1527  p.ptr = _free(p.ptr);
1528  p.argv = argv;
1529  he->freeData = 1;
1530  } else
1531  he->freeData = 0;
1532 
1533  he->t = t;
1534  he->p.ptr = p.ptr;
1535  he->c = c;
1536  return 0;
1537 }
1538 
1545 static int summaryTag(Header h, HE_t he)
1546  /*@globals rpmGlobalMacroContext, h_errno @*/
1547  /*@modifies he, rpmGlobalMacroContext @*/
1548 {
1549  he->tag = RPMTAG_SUMMARY;
1550  return i18nTag(h, he);
1551 }
1552 
1559 static int descriptionTag(Header h, HE_t he)
1560  /*@globals rpmGlobalMacroContext, h_errno @*/
1561  /*@modifies he, rpmGlobalMacroContext @*/
1562 {
1563  he->tag = RPMTAG_DESCRIPTION;
1564  return i18nTag(h, he);
1565 }
1566 
1567 static int changelognameTag(Header h, HE_t he)
1568  /*@modifies he @*/
1569 {
1570  he->tag = RPMTAG_CHANGELOGNAME;
1571  return localeTag(h, he);
1572 }
1573 
1574 static int changelogtextTag(Header h, HE_t he)
1575  /*@modifies he @*/
1576 {
1577  he->tag = RPMTAG_CHANGELOGTEXT;
1578  return localeTag(h, he);
1579 }
1580 
1587 static int groupTag(Header h, HE_t he)
1588  /*@globals rpmGlobalMacroContext, h_errno @*/
1589  /*@modifies he, rpmGlobalMacroContext @*/
1590 {
1591  he->tag = RPMTAG_GROUP;
1592  return i18nTag(h, he);
1593 }
1594 
1601 /*@-globuse@*/
1602 static int dbinstanceTag(Header h, HE_t he)
1603  /*@globals rpmGlobalMacroContext, h_errno,
1604  fileSystem, internalState @*/
1605  /*@modifies he, rpmGlobalMacroContext,
1606  fileSystem, internalState @*/
1607 {
1608  he->tag = RPMTAG_DBINSTANCE;
1609  he->t = RPM_INT32_TYPE;
1610  he->p.i32p = xmalloc(sizeof(*he->p.i32p));
1611  he->p.i32p[0] = headerGetInstance(h);
1612  he->freeData = 1;
1613  he->c = 1;
1614  return 0;
1615 }
1616 /*@=globuse@*/
1617 
1624 /*@-globuse@*/
1625 static int headerstartoffTag(Header h, HE_t he)
1626  /*@globals rpmGlobalMacroContext, h_errno,
1627  fileSystem, internalState @*/
1628  /*@modifies he, rpmGlobalMacroContext,
1629  fileSystem, internalState @*/
1630 {
1631  he->tag = RPMTAG_HEADERSTARTOFF;
1632  he->t = RPM_INT64_TYPE;
1633  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
1634  he->p.ui64p[0] = headerGetStartOff(h);
1635  he->freeData = 1;
1636  he->c = 1;
1637  return 0;
1638 }
1639 /*@=globuse@*/
1640 
1647 /*@-globuse@*/
1648 static int headerendoffTag(Header h, HE_t he)
1649  /*@globals rpmGlobalMacroContext, h_errno,
1650  fileSystem, internalState @*/
1651  /*@modifies he, rpmGlobalMacroContext,
1652  fileSystem, internalState @*/
1653 {
1654  he->tag = RPMTAG_HEADERENDOFF;
1655  he->t = RPM_INT64_TYPE;
1656  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
1657  he->p.ui64p[0] = headerGetEndOff(h);
1658  he->freeData = 1;
1659  he->c = 1;
1660  return 0;
1661 }
1662 /*@=globuse@*/
1663 
1670 /*@-globuse@*/
1671 static int pkgoriginTag(Header h, HE_t he)
1672  /*@globals rpmGlobalMacroContext, h_errno,
1673  fileSystem, internalState @*/
1674  /*@modifies he, rpmGlobalMacroContext,
1675  fileSystem, internalState @*/
1676 {
1677  const char * origin;
1678 
1679  he->tag = RPMTAG_PACKAGEORIGIN;
1680  if (!headerGetEntry(h, he->tag, NULL, &origin, NULL)
1681  && (origin = headerGetOrigin(h)) != NULL)
1682  {
1683  he->t = RPM_STRING_TYPE;
1684  he->p.str = xstrdup(origin);
1685  he->c = 1;
1686  he->freeData = 1;
1687  }
1688  return 0;
1689 }
1690 /*@=globuse@*/
1691 
1698 /*@-globuse@*/
1699 static int pkgbaseurlTag(Header h, HE_t he)
1700  /*@globals rpmGlobalMacroContext, h_errno,
1701  fileSystem, internalState @*/
1702  /*@modifies he, rpmGlobalMacroContext,
1703  fileSystem, internalState @*/
1704 {
1705  const char * baseurl;
1706  int rc = 1;
1707 
1708  he->tag = RPMTAG_PACKAGEBASEURL;
1709  if (!headerGetEntry(h, he->tag, NULL, &baseurl, NULL)
1710  && (baseurl = headerGetBaseURL(h)) != NULL)
1711  {
1712  he->t = RPM_STRING_TYPE;
1713  he->p.str = xstrdup(baseurl);
1714  he->c = 1;
1715  he->freeData = 1;
1716  rc = 0;
1717  }
1718  return rc;
1719 }
1720 /*@=globuse@*/
1721 
1728 /*@-globuse@*/
1729 static int pkgdigestTag(Header h, HE_t he)
1730  /*@globals rpmGlobalMacroContext, h_errno,
1731  fileSystem, internalState @*/
1732  /*@modifies he, rpmGlobalMacroContext,
1733  fileSystem, internalState @*/
1734 {
1735  const char * digest;
1736  int rc = 1;
1737 
1738  he->tag = RPMTAG_PACKAGEDIGEST;
1739  if ((digest = headerGetDigest(h)) != NULL)
1740  {
1741  he->t = RPM_STRING_TYPE;
1742  he->p.str = xstrdup(digest);
1743  he->c = 1;
1744  he->freeData = 1;
1745  rc = 0;
1746  }
1747  return rc;
1748 }
1749 /*@=globuse@*/
1750 
1757 /*@-globuse@*/
1758 static int pkgmtimeTag(Header h, HE_t he)
1759  /*@globals rpmGlobalMacroContext, h_errno,
1760  fileSystem, internalState @*/
1761  /*@modifies he, rpmGlobalMacroContext,
1762  fileSystem, internalState @*/
1763 {
1764  struct stat * st = headerGetStatbuf(h);
1765  he->tag = RPMTAG_PACKAGETIME;
1766  he->t = RPM_UINT64_TYPE;
1767  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
1768  he->p.ui64p[0] = st->st_mtime;
1769  he->freeData = 1;
1770  he->c = 1;
1771  return 0;
1772 }
1773 /*@=globuse@*/
1774 
1781 /*@-globuse@*/
1782 static int pkgsizeTag(Header h, HE_t he)
1783  /*@globals rpmGlobalMacroContext, h_errno,
1784  fileSystem, internalState @*/
1785  /*@modifies he, rpmGlobalMacroContext,
1786  fileSystem, internalState @*/
1787 {
1788  struct stat * st = headerGetStatbuf(h);
1789  he->tag = RPMTAG_PACKAGESIZE;
1790  he->t = RPM_UINT64_TYPE;
1791  he->p.ui64p = xmalloc(sizeof(*he->p.ui64p));
1792  he->p.ui64p[0] = st->st_size;
1793  he->freeData = 1;
1794  he->c = 1;
1795  return 0;
1796 }
1797 /*@=globuse@*/
1798 
1804 /*@only@*/
1805 static char * hGetNVRA(Header h)
1806  /*@modifies h @*/
1807 {
1808  const char * N = NULL;
1809  const char * V = NULL;
1810  const char * R = NULL;
1811  const char * A = NULL;
1812  size_t nb = 0;
1813  char * NVRA, * t;
1814 
1815  (void) headerNEVRA(h, &N, NULL, &V, &R, &A);
1816  if (N) nb += strlen(N);
1817  if (V) nb += strlen(V) + 1;
1818  if (R) nb += strlen(R) + 1;
1819  if (A) nb += strlen(A) + 1;
1820  nb++;
1821  NVRA = t = xmalloc(nb);
1822  *t = '\0';
1823  if (N) t = stpcpy(t, N);
1824  if (V) t = stpcpy( stpcpy(t, "-"), V);
1825  if (R) t = stpcpy( stpcpy(t, "-"), R);
1826  if (A) t = stpcpy( stpcpy(t, "."), A);
1827  return NVRA;
1828 }
1829 
1836 /*@-globuse@*/
1837 static int nvraTag(Header h, HE_t he)
1838  /*@globals rpmGlobalMacroContext, h_errno,
1839  fileSystem, internalState @*/
1840  /*@modifies h, he, rpmGlobalMacroContext,
1841  fileSystem, internalState @*/
1842 {
1843  he->t = RPM_STRING_TYPE;
1844  he->p.str = hGetNVRA(h);
1845  he->c = 1;
1846  he->freeData = 1;
1847  return 0;
1848 }
1849 /*@=globuse@*/
1850 
1857 static int _fnTag(Header h, HE_t he)
1858  /*@modifies he @*/
1859 {
1860  he->t = RPM_STRING_ARRAY_TYPE;
1861  rpmfiBuildFNames(h, he->tag, &he->p.argv, &he->c);
1862  he->freeData = 1;
1863  return 0;
1864 }
1865 
1866 static int filepathsTag(Header h, HE_t he)
1867  /*@modifies he @*/
1868 {
1869  he->tag = RPMTAG_BASENAMES;
1870  return _fnTag(h, he);
1871 }
1872 
1873 static int origpathsTag(Header h, HE_t he)
1874  /*@modifies he @*/
1875 {
1876  he->tag = RPMTAG_ORIGBASENAMES;
1877  return _fnTag(h, he);
1878 }
1879 
1886 static int fsnamesTag( /*@unused@*/ Header h, HE_t he)
1887  /*@globals fileSystem, internalState @*/
1888  /*@modifies he, fileSystem, internalState @*/
1889 {
1890  const char ** list;
1891 
1892  if (rpmGetFilesystemList(&list, &he->c))
1893  return 1;
1894 
1895  he->t = RPM_STRING_ARRAY_TYPE;
1896  he->p.argv = list;
1897  he->freeData = 0;
1898 
1899  return 0;
1900 }
1901 
1908 static int fssizesTag(Header h, HE_t he)
1909  /*@globals rpmGlobalMacroContext, h_errno,
1910  fileSystem, internalState @*/
1911  /*@modifies he, rpmGlobalMacroContext,
1912  fileSystem, internalState @*/
1913 {
1914  HE_t vhe = memset(alloca(sizeof(*vhe)), 0, sizeof(*vhe));
1915  const char ** fnames;
1916  uint_64 * usages;
1917  int numFiles;
1918  int rc = 1; /* assume error */
1919  int xx;
1920 
1921  vhe->tag = RPMTAG_FILESIZES;
1922  xx = headerGetEntry(h, vhe->tag, (hTYP_t)&vhe->t, &vhe->p.ptr, &vhe->c);
1923  if (!xx) {
1924  numFiles = 0;
1925  fnames = NULL;
1926  } else
1927  rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fnames, &numFiles);
1928 
1929  if (rpmGetFilesystemList(NULL, &he->c))
1930  goto exit;
1931 
1932  he->t = RPM_INT64_TYPE;
1933  he->freeData = 1;
1934 
1935  if (fnames == NULL)
1936  he->p.ui64p = xcalloc(he->c, sizeof(*usages));
1937  else
1938  if (rpmGetFilesystemUsage(fnames, vhe->p.ui32p, numFiles, &he->p.ui64p, 0))
1939  goto exit;
1940 
1941  rc = 0;
1942 
1943 exit:
1944  fnames = _free(fnames);
1945 
1946  return rc;
1947 }
1948 
1955 static int fileclassTag(Header h, HE_t he)
1956  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1957  /*@modifies h, he,
1958  rpmGlobalMacroContext, fileSystem, internalState @*/
1959 {
1960  he->t = RPM_STRING_ARRAY_TYPE;
1961  rpmfiBuildFClasses(h, &he->p.argv, &he->c);
1962  he->freeData = 1;
1963  return 0;
1964 }
1965 
1972 static int filecontextsTag(Header h, HE_t he)
1973  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1974  /*@modifies h, he,
1975  rpmGlobalMacroContext, fileSystem, internalState @*/
1976 {
1977  he->t = RPM_STRING_ARRAY_TYPE;
1978  rpmfiBuildFContexts(h, &he->p.argv, &he->c);
1979  he->freeData = 1;
1980  return 0;
1981 }
1982 
1989 static int fscontextsTag(Header h, HE_t he)
1990  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1991  /*@modifies h, he,
1992  rpmGlobalMacroContext, fileSystem, internalState @*/
1993 {
1994  he->t = RPM_STRING_ARRAY_TYPE;
1995  rpmfiBuildFSContexts(h, &he->p.argv, &he->c);
1996  he->freeData = 1;
1997  return 0;
1998 }
1999 
2006 static int recontextsTag(Header h, HE_t he)
2007  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2008  /*@modifies h, he,
2009  rpmGlobalMacroContext, fileSystem, internalState @*/
2010 {
2011  he->t = RPM_STRING_ARRAY_TYPE;
2012  rpmfiBuildREContexts(h, &he->p.argv, &he->c);
2013  he->freeData = 1;
2014  return 0;
2015 }
2016 
2023 static int fileprovideTag(Header h, HE_t he)
2024  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2025  /*@modifies h, he,
2026  rpmGlobalMacroContext, fileSystem, internalState @*/
2027 {
2028  he->t = RPM_STRING_ARRAY_TYPE;
2029  rpmfiBuildFDeps(h, RPMTAG_PROVIDENAME, &he->p.argv, &he->c);
2030  he->freeData = 1;
2031  return 0;
2032 }
2033 
2040 static int filerequireTag(Header h, HE_t he)
2041  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2042  /*@modifies h, he,
2043  rpmGlobalMacroContext, fileSystem, internalState @*/
2044 {
2045  he->t = RPM_STRING_ARRAY_TYPE;
2046  rpmfiBuildFDeps(h, RPMTAG_REQUIRENAME, &he->p.argv, &he->c);
2047  he->freeData = 1;
2048  return 0;
2049 }
2050 
2057 static int missingokTag(Header h, HE_t he)
2058  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2059  /*@modifies h, he,
2060  rpmGlobalMacroContext, fileSystem, internalState @*/
2061 {
2062  rpmds ds = rpmdsNew(h, RPMTAG_REQUIRENAME, 0);
2063  ARGV_t av = NULL;
2064  ARGV_t argv;
2065  int argc = 0;
2066  char * t;
2067  size_t nb = 0;
2068  int i;
2069 
2070 assert(ds != NULL);
2071  /* Collect dependencies marked as hints. */
2072  ds = rpmdsInit(ds);
2073  if (ds != NULL)
2074  while (rpmdsNext(ds) >= 0) {
2075  int Flags = rpmdsFlags(ds);
2076  const char * DNEVR;
2077  if (!(Flags & RPMSENSE_MISSINGOK))
2078  continue;
2079  DNEVR = rpmdsDNEVR(ds);
2080  if (DNEVR == NULL)
2081  continue;
2082  nb += sizeof(*argv) + strlen(DNEVR+2) + 1;
2083  (void) argvAdd(&av, DNEVR+2);
2084  argc++;
2085  }
2086  nb += sizeof(*argv); /* final argv NULL */
2087 
2088  /* Create contiguous header string array. */
2089  argv = (ARGV_t) xcalloc(nb, 1);
2090  t = (char *)(argv + argc);
2091  for (i = 0; i < argc; i++) {
2092  argv[i] = t;
2093  t = stpcpy(t, av[i]);
2094  *t++ = '\0';
2095  }
2096  av = argvFree(av);
2097  ds = rpmdsFree(ds);
2098 
2099  /* XXX perhaps return "(none)" inband if no suggests/enhances <shrug>. */
2100 
2101  he->t = RPM_STRING_ARRAY_TYPE;
2102  he->p.argv = argv;
2103  he->c = argc;
2104  he->freeData = 1;
2105  return 0;
2106 }
2107 
2108 static int PRCOSkip(rpmTag tag, rpmTagData N, rpmTagData EVR, rpmTagData F,
2109  uint32_t i)
2110  /*@*/
2111 {
2112  int a = -2, b = -2;
2113 
2114  if (N.argv[i] == NULL || *N.argv[i] == '\0')
2115  return 1;
2116  if (tag == RPMTAG_REQUIRENAME && i > 0
2117  && !(a=strcmp(N.argv[i], N.argv[i-1]))
2118  && !(b=strcmp(EVR.argv[i], EVR.argv[i-1]))
2119  && (F.ui32p[i] & 0x4e) == ((F.ui32p[i-1] & 0x4e)))
2120  return 1;
2121  return 0;
2122 }
2123 
2124 static int PRCOxmlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
2125  /*@modifies he @*/
2126 {
2127  rpmTag tag = he->tag;
2128  rpmTagData N = { .ptr = NULL };
2129  rpmTagData EVR = { .ptr = NULL };
2130  rpmTagData F = { .ptr = NULL };
2131  size_t nb;
2132  uint32_t ac;
2133  uint32_t c;
2134  uint32_t i;
2135  char *t;
2136  int rc = 1; /* assume failure */
2137  int xx;
2138 
2139  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2140  if (xx == 0) goto exit;
2141  N.argv = he->p.argv;
2142  c = he->c;
2143 
2144  he->tag = EVRtag;
2145  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2146  if (xx == 0) goto exit;
2147  EVR.argv = he->p.argv;
2148 
2149  he->tag = Ftag;
2150  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2151  if (xx == 0) goto exit;
2152  F.ui32p = he->p.ui32p;
2153 
2154  nb = sizeof(*he->p.argv);
2155  ac = 0;
2156  for (i = 0; i < c; i++) {
2157  if (PRCOSkip(tag, N, EVR, F, i))
2158  continue;
2159  ac++;
2160  nb += sizeof(*he->p.argv);
2161  nb += sizeof("<rpm:entry name=\"\"/>");
2162  if (*N.argv[i] == '/')
2163  nb += xmlstrlen(N.argv[i]);
2164  else
2165  nb += strlen(N.argv[i]);
2166  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
2167  nb += sizeof(" flags=\"EQ\" epoch=\"0\" ver=\"\"") - 1;
2168  nb += strlen(EVR.argv[i]);
2169  if (strchr(EVR.argv[i], ':') != NULL)
2170  nb -= 2;
2171  if (strchr(EVR.argv[i], '-') != NULL)
2172  nb += sizeof(" rel=\"\"") - 2;
2173  }
2174 #ifdef NOTNOW
2175  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
2176  nb += sizeof(" pre=\"1\"") - 1;
2177 #endif
2178  }
2179 
2180  he->t = RPM_STRING_ARRAY_TYPE;
2181  he->c = ac;
2182  he->freeData = 1;
2183  he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
2184  t = (char *) &he->p.argv[he->c + 1];
2185  ac = 0;
2186  for (i = 0; i < c; i++) {
2187  if (PRCOSkip(tag, N, EVR, F, i))
2188  continue;
2189  he->p.argv[ac++] = t;
2190  t = stpcpy(t, "<rpm:entry");
2191  t = stpcpy(t, " name=\"");
2192  if (*N.argv[i] == '/') {
2193  t = xmlstrcpy(t, N.argv[i]); t += strlen(t);
2194  } else
2195  t = stpcpy(t, N.argv[i]);
2196  t = stpcpy(t, "\"");
2197  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
2198  static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
2199  int Fx = ((F.ui32p[i] >> 1) & 0x7);
2200  const char *E, *V, *R;
2201  char *f, *fe;
2202  t = stpcpy( stpcpy( stpcpy(t, " flags=\""), Fstr[Fx]), "\"");
2203  f = (char *) EVR.argv[i];
2204  for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++);
2205  if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
2206  V = f;
2207  for (fe = f; *fe != '\0' && *fe != '-'; fe++);
2208  if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
2209  t = stpcpy( stpcpy( stpcpy(t, " epoch=\""), (E && *E ? E : "0")), "\"");
2210  t = stpcpy( stpcpy( stpcpy(t, " ver=\""), V), "\"");
2211  if (R != NULL)
2212  t = stpcpy( stpcpy( stpcpy(t, " rel=\""), R), "\"");
2213  }
2214 #ifdef NOTNOW
2215  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
2216  t = stpcpy(t, " pre=\"1\"");
2217 #endif
2218  t = stpcpy(t, "/>");
2219  *t++ = '\0';
2220  }
2221  he->p.argv[he->c] = NULL;
2222  rc = 0;
2223 
2224 exit:
2225  N.argv = _free(N.argv);
2226  EVR.argv = _free(EVR.argv);
2227  return rc;
2228 }
2229 
2230 static int PxmlTag(Header h, HE_t he)
2231  /*@modifies he @*/
2232 {
2233  he->tag = RPMTAG_PROVIDENAME;
2235 }
2236 
2237 static int RxmlTag(Header h, HE_t he)
2238  /*@modifies he @*/
2239 {
2240  he->tag = RPMTAG_REQUIRENAME;
2242 }
2243 
2244 static int CxmlTag(Header h, HE_t he)
2245  /*@modifies he @*/
2246 {
2247  he->tag = RPMTAG_CONFLICTNAME;
2249 }
2250 
2251 static int OxmlTag(Header h, HE_t he)
2252  /*@modifies he @*/
2253 {
2254  he->tag = RPMTAG_OBSOLETENAME;
2256 }
2257 
2263 static size_t sqlstrlen(const char * s)
2264  /*@*/
2265 {
2266  size_t len = 0;
2267  int c;
2268 
2269  while ((c = (int) *s++) != (int) '\0')
2270  {
2271  switch (c) {
2272  case '\'': len += 1; /*@fallthrough@*/
2273  default: len += 1; /*@switchbreak@*/ break;
2274  }
2275  }
2276  return len;
2277 }
2278 
2285 static char * sqlstrcpy(/*@returned@*/ char * t, const char * s)
2286  /*@modifies t @*/
2287 {
2288  char * te = t;
2289  int c;
2290 
2291  while ((c = (int) *s++) != (int) '\0') {
2292  switch (c) {
2293  case '\'': *te++ = (char) c; /*@fallthrough@*/
2294  default: *te++ = (char) c; /*@switchbreak@*/ break;
2295  }
2296  }
2297  *te = '\0';
2298  return t;
2299 }
2300 
2307 static /*@only@*/ char * sqlescapeFormat(HE_t he, /*@null@*/ const char ** av)
2308  /*@*/
2309 {
2310  int ix = (he->ix > 0 ? he->ix : 0);
2311  char * val;
2312 
2313 assert(ix == 0);
2314  if (he->t != RPM_STRING_TYPE) {
2315  val = xstrdup(_("(not a string)"));
2316  } else {
2317  const char * s = strdup_locale_convert(he->p.str, (av ? av[0] : NULL));
2318  size_t nb = sqlstrlen(s);
2319  char * t;
2320 
2321  val = t = xcalloc(1, nb + 1);
2322  t = sqlstrcpy(t, s); t += strlen(t);
2323  *t = '\0';
2324  s = _free(s);
2325  }
2326 
2327 /*@-globstate@*/
2328  return val;
2329 /*@=globstate@*/
2330 }
2331 
2332 static int PRCOsqlTag(Header h, HE_t he, rpmTag EVRtag, rpmTag Ftag)
2333  /*@modifies he @*/
2334 {
2335  rpmTag tag = he->tag;
2336  rpmTagData N = { .ptr = NULL };
2337  rpmTagData EVR = { .ptr = NULL };
2338  rpmTagData F = { .ptr = NULL };
2339  char instance[64];
2340  size_t nb;
2341  uint32_t ac;
2342  uint32_t c;
2343  uint32_t i;
2344  char *t;
2345  int rc = 1; /* assume failure */
2346  int xx;
2347 
2348  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2349  if (xx == 0) goto exit;
2350  N.argv = he->p.argv;
2351  c = he->c;
2352 
2353  he->tag = EVRtag;
2354  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2355  if (xx == 0) goto exit;
2356  EVR.argv = he->p.argv;
2357 
2358  he->tag = Ftag;
2359  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2360  if (xx == 0) goto exit;
2361  F.ui32p = he->p.ui32p;
2362 
2363  xx = snprintf(instance, sizeof(instance), "'%d'", headerGetInstance(h));
2364  nb = sizeof(*he->p.argv);
2365  ac = 0;
2366  for (i = 0; i < c; i++) {
2367  if (PRCOSkip(tag, N, EVR, F, i))
2368  continue;
2369  ac++;
2370  nb += sizeof(*he->p.argv);
2371  nb += strlen(instance) + sizeof(", '', '', '', '', ''");
2372  if (tag == RPMTAG_REQUIRENAME)
2373  nb += sizeof(", ''") - 1;
2374  nb += strlen(N.argv[i]);
2375  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
2376  nb += strlen(EVR.argv[i]);
2377  nb += sizeof("EQ0") - 1;
2378  }
2379 #ifdef NOTNOW
2380  if (tag == RPMTAG_REQUIRENAME && (F.ui32p[i] & 0x40))
2381  nb += sizeof("1") - 1;
2382 #endif
2383  }
2384 
2385  he->t = RPM_STRING_ARRAY_TYPE;
2386  he->c = ac;
2387  he->freeData = 1;
2388  he->p.argv = xmalloc(nb + BUFSIZ); /* XXX hack: leave slop */
2389  t = (char *) &he->p.argv[he->c + 1];
2390  ac = 0;
2391  for (i = 0; i < c; i++) {
2392  if (PRCOSkip(tag, N, EVR, F, i))
2393  continue;
2394  he->p.argv[ac++] = t;
2395  t = stpcpy(t, instance);
2396  t = stpcpy( stpcpy( stpcpy(t, ", '"), N.argv[i]), "'");
2397  if (EVR.argv != NULL && EVR.argv[i] != NULL && *EVR.argv[i] != '\0') {
2398  static char *Fstr[] = { "?0","LT","GT","?3","EQ","LE","GE","?7" };
2399  int Fx = ((F.ui32p[i] >> 1) & 0x7);
2400  const char *E, *V, *R;
2401  char *f, *fe;
2402  t = stpcpy( stpcpy( stpcpy(t, ", '"), Fstr[Fx]), "'");
2403  f = (char *) EVR.argv[i];
2404  for (fe = f; *fe != '\0' && *fe >= '0' && *fe <= '9'; fe++);
2405  if (*fe == ':') { *fe++ = '\0'; E = f; f = fe; } else E = NULL;
2406  V = f;
2407  for (fe = f; *fe != '\0' && *fe != '-'; fe++);
2408  if (*fe == '-') { *fe++ = '\0'; R = fe; } else R = NULL;
2409  t = stpcpy( stpcpy( stpcpy(t, ", '"), (E && *E ? E : "0")), "'");
2410  t = stpcpy( stpcpy( stpcpy(t, ", '"), V), "'");
2411  t = stpcpy( stpcpy( stpcpy(t, ", '"), (R ? R : "")), "'");
2412  } else
2413  t = stpcpy(t, ", '', '', '', ''");
2414 #ifdef NOTNOW
2415  if (tag == RPMTAG_REQUIRENAME)
2416  t = stpcpy(stpcpy(stpcpy(t, ", '"),(F.ui32p[i] & 0x40) ? "1" : "0"), "'");
2417 #endif
2418  *t++ = '\0';
2419  }
2420  he->p.argv[he->c] = NULL;
2421  rc = 0;
2422 
2423 exit:
2424  N.argv = _free(N.argv);
2425  EVR.argv = _free(EVR.argv);
2426  return rc;
2427 }
2428 
2429 static int PsqlTag(Header h, HE_t he)
2430  /*@modifies he @*/
2431 {
2432  he->tag = RPMTAG_PROVIDENAME;
2434 }
2435 
2436 static int RsqlTag(Header h, HE_t he)
2437  /*@modifies he @*/
2438 {
2439  he->tag = RPMTAG_REQUIRENAME;
2441 }
2442 
2443 static int CsqlTag(Header h, HE_t he)
2444  /*@modifies he @*/
2445 {
2446  he->tag = RPMTAG_CONFLICTNAME;
2448 }
2449 
2450 static int OsqlTag(Header h, HE_t he)
2451  /*@modifies he @*/
2452 {
2453  he->tag = RPMTAG_OBSOLETENAME;
2455 }
2456 
2457 static int FDGSkip(rpmTagData DN, rpmTagData BN, rpmTagData DI, uint32_t i)
2458  /*@*/
2459 {
2460  const char * dn = DN.argv[DI.ui32p[i]];
2461  size_t dnlen = strlen(dn);
2462 
2463  if (strstr(dn, "bin/") != NULL)
2464  return 1;
2465  if (dnlen >= sizeof("/etc/")-1 && !strncmp(dn, "/etc/", dnlen))
2466  return 1;
2467  if (!strcmp(dn, "/usr/lib/") && !strcmp(BN.argv[i], "sendmail"))
2468  return 1;
2469  return 2;
2470 }
2471 
2472 static int FDGxmlTag(Header h, HE_t he, int lvl)
2473  /*@modifies he @*/
2474 {
2475  rpmTagData BN = { .ptr = NULL };
2476  rpmTagData DN = { .ptr = NULL };
2477  rpmTagData DI = { .ptr = NULL };
2478  rpmTagData FMODES = { .ptr = NULL };
2479  rpmTagData FFLAGS = { .ptr = NULL };
2480  size_t nb;
2481  uint32_t ac;
2482  uint32_t c;
2483  uint32_t i;
2484  char *t;
2485  int rc = 1; /* assume failure */
2486  int xx;
2487 
2488  he->tag = RPMTAG_BASENAMES;
2489  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2490  if (xx == 0) goto exit;
2491  BN.argv = he->p.argv;
2492  c = he->c;
2493 
2494  he->tag = RPMTAG_DIRNAMES;
2495  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2496  if (xx == 0) goto exit;
2497  DN.argv = he->p.argv;
2498 
2499  he->tag = RPMTAG_DIRINDEXES;
2500  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2501  if (xx == 0) goto exit;
2502  DI.ui32p = he->p.ui32p;
2503 
2504  he->tag = RPMTAG_FILEMODES;
2505  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2506  if (xx == 0) goto exit;
2507  FMODES.ui16p = he->p.ui16p;
2508 
2509  he->tag = RPMTAG_FILEFLAGS;
2510  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2511  if (xx == 0) goto exit;
2512  FFLAGS.ui32p = he->p.ui32p;
2513 
2514  nb = sizeof(*he->p.argv);
2515  ac = 0;
2516  for (i = 0; i < c; i++) {
2517  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2518  continue;
2519  ac++;
2520  nb += sizeof(*he->p.argv);
2521  nb += sizeof("<file></file>");
2522  nb += xmlstrlen(DN.argv[DI.ui32p[i]]);
2523  nb += xmlstrlen(BN.argv[i]);
2524  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
2525  nb += sizeof(" type=\"ghost\"") - 1;
2526  else if (S_ISDIR(FMODES.ui16p[i]))
2527  nb += sizeof(" type=\"dir\"") - 1;
2528  }
2529 
2530  he->t = RPM_STRING_ARRAY_TYPE;
2531  he->c = ac;
2532  he->freeData = 1;
2533  he->p.argv = xmalloc(nb);
2534  t = (char *) &he->p.argv[he->c + 1];
2535  ac = 0;
2536  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
2537  for (i = 0; i < c; i++) {
2538  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2539  continue;
2540  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
2541  continue;
2542  if (S_ISDIR(FMODES.ui16p[i]))
2543  continue;
2544  he->p.argv[ac++] = t;
2545  t = stpcpy(t, "<file>");
2546  t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
2547  t = xmlstrcpy(t, BN.argv[i]); t += strlen(t);
2548  t = stpcpy(t, "</file>");
2549  *t++ = '\0';
2550  }
2551  for (i = 0; i < c; i++) {
2552  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2553  continue;
2554  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
2555  continue;
2556  if (!S_ISDIR(FMODES.ui16p[i]))
2557  continue;
2558  he->p.argv[ac++] = t;
2559  t = stpcpy(t, "<file type=\"dir\">");
2560  t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
2561  t = xmlstrcpy(t, BN.argv[i]); t += strlen(t);
2562  t = stpcpy(t, "</file>");
2563  *t++ = '\0';
2564  }
2565  for (i = 0; i < c; i++) {
2566  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2567  continue;
2568  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
2569  continue;
2570  he->p.argv[ac++] = t;
2571  t = stpcpy(t, "<file type=\"ghost\">");
2572  t = xmlstrcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
2573  t = xmlstrcpy(t, BN.argv[i]); t += strlen(t);
2574  t = stpcpy(t, "</file>");
2575  *t++ = '\0';
2576  }
2577 
2578  he->p.argv[he->c] = NULL;
2579  rc = 0;
2580 
2581 exit:
2582  BN.argv = _free(BN.argv);
2583  DN.argv = _free(DN.argv);
2584  return rc;
2585 }
2586 
2587 static int F1xmlTag(Header h, HE_t he)
2588  /*@modifies he @*/
2589 {
2590  he->tag = RPMTAG_BASENAMES;
2591  return FDGxmlTag(h, he, 1);
2592 }
2593 
2594 static int F2xmlTag(Header h, HE_t he)
2595  /*@modifies he @*/
2596 {
2597  he->tag = RPMTAG_BASENAMES;
2598  return FDGxmlTag(h, he, 2);
2599 }
2600 
2601 static int FDGsqlTag(Header h, HE_t he, int lvl)
2602  /*@modifies he @*/
2603 {
2604  rpmTagData BN = { .ptr = NULL };
2605  rpmTagData DN = { .ptr = NULL };
2606  rpmTagData DI = { .ptr = NULL };
2607  rpmTagData FMODES = { .ptr = NULL };
2608  rpmTagData FFLAGS = { .ptr = NULL };
2609  char instance[64];
2610  size_t nb;
2611  uint32_t ac;
2612  uint32_t c;
2613  uint32_t i;
2614  char *t;
2615  int rc = 1; /* assume failure */
2616  int xx;
2617 
2618  he->tag = RPMTAG_BASENAMES;
2619  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2620  if (xx == 0) goto exit;
2621  BN.argv = he->p.argv;
2622  c = he->c;
2623 
2624  he->tag = RPMTAG_DIRNAMES;
2625  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2626  if (xx == 0) goto exit;
2627  DN.argv = he->p.argv;
2628 
2629  he->tag = RPMTAG_DIRINDEXES;
2630  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2631  if (xx == 0) goto exit;
2632  DI.ui32p = he->p.ui32p;
2633 
2634  he->tag = RPMTAG_FILEMODES;
2635  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2636  if (xx == 0) goto exit;
2637  FMODES.ui16p = he->p.ui16p;
2638 
2639  he->tag = RPMTAG_FILEFLAGS;
2640  xx = headerGetEntry(h, he->tag, (hTYP_t)&he->t, &he->p, &he->c);
2641  if (xx == 0) goto exit;
2642  FFLAGS.ui32p = he->p.ui32p;
2643 
2644  xx = snprintf(instance, sizeof(instance), "'%d'", headerGetInstance(h));
2645  nb = sizeof(*he->p.argv);
2646  ac = 0;
2647  for (i = 0; i < c; i++) {
2648  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2649  continue;
2650  ac++;
2651  nb += sizeof(*he->p.argv);
2652  nb += strlen(instance) + sizeof(", '', ''");
2653  nb += strlen(DN.argv[DI.ui32p[i]]);
2654  nb += strlen(BN.argv[i]);
2655  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
2656  nb += sizeof("ghost") - 1;
2657  else if (S_ISDIR(FMODES.ui16p[i]))
2658  nb += sizeof("dir") - 1;
2659  else
2660  nb += sizeof("file") - 1;
2661  }
2662 
2663  he->t = RPM_STRING_ARRAY_TYPE;
2664  he->c = ac;
2665  he->freeData = 1;
2666  he->p.argv = xmalloc(nb);
2667  t = (char *) &he->p.argv[he->c + 1];
2668  ac = 0;
2669  /* FIXME: Files, then dirs, finally ghosts breaks sort order. */
2670  for (i = 0; i < c; i++) {
2671  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2672  continue;
2673  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
2674  continue;
2675  if (S_ISDIR(FMODES.ui16p[i]))
2676  continue;
2677  he->p.argv[ac++] = t;
2678  t = stpcpy( stpcpy(t, instance), ", '");
2679  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
2680  t = strcpy(t, BN.argv[i]); t += strlen(t);
2681  t = stpcpy(t, "', 'file'");
2682  *t++ = '\0';
2683  }
2684  for (i = 0; i < c; i++) {
2685  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2686  continue;
2687  if (FFLAGS.ui32p[i] & 0x40) /* XXX RPMFILE_GHOST */
2688  continue;
2689  if (!S_ISDIR(FMODES.ui16p[i]))
2690  continue;
2691  he->p.argv[ac++] = t;
2692  t = stpcpy( stpcpy(t, instance), ", '");
2693  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
2694  t = strcpy(t, BN.argv[i]); t += strlen(t);
2695  t = stpcpy(t, "', 'dir'");
2696  *t++ = '\0';
2697  }
2698  for (i = 0; i < c; i++) {
2699  if (lvl > 0 && FDGSkip(DN, BN, DI, i) != lvl)
2700  continue;
2701  if (!(FFLAGS.ui32p[i] & 0x40)) /* XXX RPMFILE_GHOST */
2702  continue;
2703  he->p.argv[ac++] = t;
2704  t = stpcpy( stpcpy(t, instance), ", '");
2705  t = strcpy(t, DN.argv[DI.ui32p[i]]); t += strlen(t);
2706  t = strcpy(t, BN.argv[i]); t += strlen(t);
2707  t = stpcpy(t, "', 'ghost'");
2708  *t++ = '\0';
2709  }
2710 
2711  he->p.argv[he->c] = NULL;
2712  rc = 0;
2713 
2714 exit:
2715  BN.argv = _free(BN.argv);
2716  DN.argv = _free(DN.argv);
2717  return rc;
2718 }
2719 
2720 static int F1sqlTag(Header h, HE_t he)
2721  /*@modifies he @*/
2722 {
2723  he->tag = RPMTAG_BASENAMES;
2724  return FDGsqlTag(h, he, 1);
2725 }
2726 
2727 static int F2sqlTag(Header h, HE_t he)
2728  /*@modifies he @*/
2729 {
2730  he->tag = RPMTAG_BASENAMES;
2731  return FDGsqlTag(h, he, 2);
2732 }
2733 
2740 static /*@only@*/ char * bncdataFormat(HE_t he, /*@null@*/ const char ** av)
2741  /*@*/
2742 {
2743  char * val;
2744 
2745  if (he->t != RPM_STRING_TYPE) {
2746  val = xstrdup(_("(not a string)"));
2747  } else {
2748  const char * bn;
2749  const char * s;
2750  size_t nb;
2751  char * t;
2752 
2753  /* Get rightmost '/' in string (i.e. basename(3) behavior). */
2754  if ((bn = strrchr(he->p.str, '/')) != NULL)
2755  bn++;
2756  else
2757  bn = he->p.str;
2758 
2759  /* Convert to utf8, escape for XML CDATA. */
2760  s = strdup_locale_convert(bn, (av ? av[0] : NULL));
2761  nb = xmlstrlen(s);
2762  val = t = xcalloc(1, nb + 1);
2763  t = xmlstrcpy(t, s); t += strlen(t);
2764  *t = '\0';
2765  s = _free(s);
2766  }
2767 
2768 /*@-globstate@*/
2769  return val;
2770 /*@=globstate@*/
2771 }
2772 
2773 typedef struct key_s {
2774 /*@observer@*/
2775  const char *name; /* key name */
2776  uint32_t value;
2777 } KEY;
2778 
2779 /*@unchecked@*/ /*@observer@*/
2780 static KEY keyDigests[] = {
2781  { "adler32", PGPHASHALGO_ADLER32 },
2782  { "crc32", PGPHASHALGO_CRC32 },
2783  { "crc64", PGPHASHALGO_CRC64 },
2784  { "haval160", PGPHASHALGO_HAVAL_5_160 },
2785  { "jlu32", PGPHASHALGO_JLU32 },
2786  { "md2", PGPHASHALGO_MD2 },
2787  { "md4", PGPHASHALGO_MD4 },
2788  { "md5", PGPHASHALGO_MD5 },
2789  { "rmd128", PGPHASHALGO_RIPEMD128 },
2790  { "rmd160", PGPHASHALGO_RIPEMD160 },
2791  { "rmd256", PGPHASHALGO_RIPEMD256 },
2792  { "rmd320", PGPHASHALGO_RIPEMD320 },
2793  { "salsa10", PGPHASHALGO_SALSA10 },
2794  { "salsa20", PGPHASHALGO_SALSA20 },
2795  { "sha1", PGPHASHALGO_SHA1 },
2796  { "sha224", PGPHASHALGO_SHA224 },
2797  { "sha256", PGPHASHALGO_SHA256 },
2798  { "sha384", PGPHASHALGO_SHA384 },
2799  { "sha512", PGPHASHALGO_SHA512 },
2800  { "tiger192", PGPHASHALGO_TIGER192 },
2801 };
2802 /*@unchecked@*/
2803 static size_t nkeyDigests = sizeof(keyDigests) / sizeof(keyDigests[0]);
2804 
2810  STAT_KEYS_DEV = (1U << 0),
2811  STAT_KEYS_INO = (1U << 1),
2812  STAT_KEYS_MODE = (1U << 2),
2813  STAT_KEYS_NLINK = (1U << 3),
2814  STAT_KEYS_UID = (1U << 4),
2815  STAT_KEYS_GID = (1U << 5),
2816  STAT_KEYS_RDEV = (1U << 6),
2817  STAT_KEYS_SIZE = (1U << 7),
2818  STAT_KEYS_BLKSIZE = (1U << 8),
2819  STAT_KEYS_BLOCKS = (1U << 9),
2820  STAT_KEYS_ATIME = (1U << 10),
2821  STAT_KEYS_CTIME = (1U << 11),
2822  STAT_KEYS_MTIME = (1U << 12),
2823 #ifdef NOTYET
2824  STAT_KEYS_FLAGS = (1U << 13),
2825 #endif
2826  STAT_KEYS_SLINK = (1U << 14),
2827  STAT_KEYS_DIGEST = (1U << 15),
2828 #ifdef NOTYET
2829  STAT_KEYS_FCONTEXT = (1U << 16),
2830 #endif
2831  STAT_KEYS_UNAME = (1U << 17),
2832  STAT_KEYS_GNAME = (1U << 18),
2833 };
2834 
2835 /*@unchecked@*/ /*@observer@*/
2836 static KEY keyStat[] = {
2837  { "adler32", STAT_KEYS_DIGEST },
2838  { "atime", STAT_KEYS_ATIME },
2839  { "ctime", STAT_KEYS_CTIME },
2840  { "blksize", STAT_KEYS_BLKSIZE },
2841  { "blocks", STAT_KEYS_BLOCKS },
2842  { "crc32", STAT_KEYS_DIGEST },
2843  { "crc64", STAT_KEYS_DIGEST },
2844  { "dev", STAT_KEYS_DEV },
2845 #ifdef NOTYET
2846  { "digest", STAT_KEYS_DIGEST },
2847  { "fcontext", STAT_KEYS_FCONTEXT },
2848  { "flags", STAT_KEYS_FLAGS },
2849 #endif
2850  { "gid", STAT_KEYS_GID },
2851  { "gname", STAT_KEYS_GNAME },
2852  { "haval160", STAT_KEYS_DIGEST },
2853  { "ino", STAT_KEYS_INO },
2854  { "jlu32", STAT_KEYS_DIGEST },
2855  { "link", STAT_KEYS_SLINK },
2856  { "md2", STAT_KEYS_DIGEST },
2857  { "md4", STAT_KEYS_DIGEST },
2858  { "md5", STAT_KEYS_DIGEST },
2859  { "mode", STAT_KEYS_MODE },
2860  { "mtime", STAT_KEYS_MTIME },
2861  { "nlink", STAT_KEYS_NLINK },
2862  { "rdev", STAT_KEYS_RDEV },
2863  { "rmd128", STAT_KEYS_DIGEST },
2864  { "rmd160", STAT_KEYS_DIGEST },
2865  { "rmd256", STAT_KEYS_DIGEST },
2866  { "rmd320", STAT_KEYS_DIGEST },
2867  { "salsa10", STAT_KEYS_DIGEST },
2868  { "salsa20", STAT_KEYS_DIGEST },
2869  { "sha1", STAT_KEYS_DIGEST },
2870  { "sha224", STAT_KEYS_DIGEST },
2871  { "sha256", STAT_KEYS_DIGEST },
2872  { "sha384", STAT_KEYS_DIGEST },
2873  { "sha512", STAT_KEYS_DIGEST },
2874  { "size", STAT_KEYS_SIZE },
2875  { "tiger192", STAT_KEYS_DIGEST },
2876  { "uid", STAT_KEYS_UID },
2877  { "uname", STAT_KEYS_UNAME },
2878 };
2879 /*@unchecked@*/
2880 static size_t nkeyStat = sizeof(keyStat) / sizeof(keyStat[0]);
2881 
2886  UUID_KEYS_NONE = (0U << 0),
2887  UUID_KEYS_V1 = (1U << 0),
2888  UUID_KEYS_V3 = (3U << 0),
2889  UUID_KEYS_V4 = (4U << 0),
2890  UUID_KEYS_V5 = (5U << 0),
2891 #ifdef NOTYET
2892  UUID_KEYS_STRING = (0U << 4),
2893  UUID_KEYS_SIV = (1U << 4),
2894  UUID_KEYS_BINARY = (2U << 4),
2895  UUID_KEYS_TEXT = (3U << 4),
2896 #endif
2897 };
2898 
2899 /*@unchecked@*/ /*@observer@*/
2900 static KEY keyUuids[] = {
2901 #ifdef NOTYET
2902  { "binary", UUID_KEYS_BINARY },
2903  { "siv", UUID_KEYS_SIV },
2904  { "string", UUID_KEYS_STRING },
2905  { "text", UUID_KEYS_TEXT },
2906 #endif
2907  { "v1", UUID_KEYS_V1 },
2908  { "v3", UUID_KEYS_V3 },
2909  { "v4", UUID_KEYS_V4 },
2910  { "v5", UUID_KEYS_V5 },
2911 };
2912 /*@unchecked@*/
2913 static size_t nkeyUuids = sizeof(keyUuids) / sizeof(keyUuids[0]);
2914 
2917 static int
2918 keyCmp(const void * a, const void * b)
2919  /*@*/
2920 {
2921  return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
2922 }
2923 
2926 static uint32_t
2927 keyValue(KEY * keys, size_t nkeys, /*@null@*/ const char *name)
2928  /*@*/
2929 {
2930  uint32_t keyval = 0;
2931 
2932  if (name && * name) {
2933  KEY needle = { .name = name };
2934  KEY *k = (KEY *)bsearch(&needle, keys, nkeys, sizeof(*keys), keyCmp);
2935  if (k)
2936  keyval = k->value;
2937  }
2938  return keyval;
2939 }
2940 
2947 static /*@only@*/ char * digestFormat(HE_t he, /*@null@*/ const char ** av)
2948  /*@*/
2949 {
2950  int ix = (he->ix > 0 ? he->ix : 0);
2951  char * val = NULL;
2952  size_t ns;
2953 
2954 assert(ix == 0);
2955  switch(he->t) {
2956  default:
2957  val = xstrdup(_("(invalid type :digest)"));
2958  goto exit;
2959  /*@notreached@*/ break;
2960  case RPM_UINT64_TYPE:
2961  ns = sizeof(he->p.ui64p[0]);
2962  break;
2963  case RPM_STRING_TYPE:
2964  ns = strlen(he->p.str);
2965  break;
2966  case RPM_BIN_TYPE:
2967  ns = he->c;
2968  break;
2969  }
2970 
2971  { uint32_t keyval = keyValue(keyDigests, nkeyDigests, (av ? av[0] : NULL));
2972  uint32_t algo = (keyval ? keyval : PGPHASHALGO_SHA1);
2973  DIGEST_CTX ctx = rpmDigestInit(algo, 0);
2974  int xx = rpmDigestUpdate(ctx, he->p.ptr, ns);
2975  xx = rpmDigestFinal(ctx, &val, NULL, 1);
2976  }
2977 
2978 exit:
2979 /*@-globstate@*/
2980  return val;
2981 /*@=globstate@*/
2982 }
2983 
2990 static /*@only@*/ char * statFormat(HE_t he, /*@null@*/ const char ** av)
2991  /*@*/
2992 {
2993  /*@unchecked@*/
2994  static const char *avdefault[] = { "mode", NULL };
2995  const char * fn = NULL;
2996  struct stat sb, *st = &sb;
2997  int ix = (he->ix > 0 ? he->ix : 0);
2998  char * val = NULL;
2999  int xx;
3000  int i;
3001 
3002 assert(ix == 0);
3003  switch(he->t) {
3004  case RPM_BIN_TYPE:
3005  /* XXX limit to RPMTAG_PACKAGESTAT ... */
3006  if (he->tag == RPMTAG_PACKAGESTAT)
3007  if (he->c == sizeof(*st)) {
3008  st = (struct stat *)he->p.ptr;
3009  break;
3010  }
3011  /*@fallthrough @*/
3012  default:
3013  val = xstrdup(_("(invalid type :stat)"));
3014  goto exit;
3015  /*@notreached@*/ break;
3016  case RPM_STRING_TYPE:
3017  fn = he->p.str;
3018  if (Lstat(fn, st) == 0)
3019  break;
3020  val = rpmExpand("(Lstat:", fn, ":", strerror(errno), ")", NULL);
3021  goto exit;
3022  /*@notreached@*/ break;
3023  }
3024 
3025  if (!(av && av[0] && *av[0]))
3026  av = avdefault;
3027  for (i = 0; av[i] != NULL; i++) {
3028  char b[BUFSIZ];
3029  size_t nb = sizeof(b);
3030  char * nval;
3031  uint32_t keyval = keyValue(keyStat, nkeyStat, av[i]);
3032 
3033  nval = NULL;
3034  b[0] = '\0';
3035  switch (keyval) {
3036  default:
3037  break;
3038  case STAT_KEYS_NONE:
3039  break;
3040  case STAT_KEYS_DEV:
3041  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_dev);
3042  break;
3043  case STAT_KEYS_INO:
3044  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_ino);
3045  break;
3046  case STAT_KEYS_MODE:
3047  xx = snprintf(b, nb, "%06o", (unsigned)st->st_mode);
3048  break;
3049  case STAT_KEYS_NLINK:
3050  xx = snprintf(b, nb, "0x%ld", (unsigned long)st->st_nlink);
3051  break;
3052  case STAT_KEYS_UID:
3053  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_uid);
3054  break;
3055  case STAT_KEYS_GID:
3056  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_gid);
3057  break;
3058  case STAT_KEYS_RDEV:
3059  xx = snprintf(b, nb, "0x%lx", (unsigned long)st->st_rdev);
3060  break;
3061  case STAT_KEYS_SIZE:
3062  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_size);
3063  break;
3064  case STAT_KEYS_BLKSIZE:
3065  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blksize);
3066  break;
3067  case STAT_KEYS_BLOCKS:
3068  xx = snprintf(b, nb, "%ld", (unsigned long)st->st_blocks);
3069  break;
3070  case STAT_KEYS_ATIME:
3071  (void) stpcpy(b, ctime(&st->st_atime));
3072  break;
3073  case STAT_KEYS_CTIME:
3074  (void) stpcpy(b, ctime(&st->st_ctime));
3075  break;
3076  case STAT_KEYS_MTIME:
3077  (void) stpcpy(b, ctime(&st->st_mtime));
3078  break;
3079 #ifdef NOTYET
3080  case STAT_KEYS_FLAGS:
3081  break;
3082 #endif
3083  case STAT_KEYS_SLINK:
3084  if (fn != NULL && S_ISLNK(st->st_mode)) {
3085  ssize_t size = Readlink(fn, b, nb);
3086  if (size == -1) {
3087  nval = rpmExpand("(Readlink:", fn, ":", strerror(errno), ")", NULL);
3088  stpcpy(b, nval);
3089  nval = _free(nval);
3090  } else
3091  b[size] = '\0';
3092  }
3093  break;
3094  case STAT_KEYS_DIGEST:
3095  if (fn != NULL && S_ISREG(st->st_mode)) {
3096  uint32_t digval = keyValue(keyDigests, nkeyDigests, av[i]);
3097  uint32_t algo = (digval ? digval : PGPHASHALGO_SHA1);
3098  FD_t fd = Fopen(fn, "r%{?_rpmgio}");
3099  if (fd == NULL || Ferror(fd)) {
3100  nval = rpmExpand("(Fopen:", fn, ":", Fstrerror(fd), ")", NULL);
3101  } else {
3102  static int asAscii = 1;
3103  char buffer[16 * 1024];
3104  fdInitDigest(fd, algo, 0);
3105  while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
3106  {};
3107  if (Ferror(fd))
3108  nval = rpmExpand("(Fread:", fn, ":", Fstrerror(fd), ")", NULL);
3109  else
3110  fdFiniDigest(fd, algo, &nval, NULL, asAscii);
3111  }
3112  if (nval) {
3113  stpcpy(b, nval);
3114  nval = _free(nval);
3115  }
3116  if (fd != NULL)
3117  xx = Fclose(fd);
3118  }
3119  break;
3120  case STAT_KEYS_UNAME:
3121  (void) stpcpy(b, uidToUname(st->st_uid));
3122  break;
3123  case STAT_KEYS_GNAME:
3124  (void) stpcpy(b, gidToGname(st->st_gid));
3125  break;
3126  }
3127  if (b[0] == '\0')
3128  continue;
3129  b[nb-1] = '\0';
3130 
3131  if (val == NULL)
3132  val = xstrdup(b);
3133  else {
3134  nval = rpmExpand(val, " | ", b, NULL);
3135  val = _free(val);
3136  val = nval;
3137  }
3138  }
3139 
3140 exit:
3141 /*@-globstate@*/
3142  return val;
3143 /*@=globstate@*/
3144 }
3145 
3152 static /*@only@*/ char * uuidFormat(HE_t he, /*@null@*/ const char ** av)
3153  /*@*/
3154 {
3155  /*@unchecked@*/
3156  static const char *avdefault[] = { "v5", NULL };
3157  int version = 0;
3158  int ix = (he->ix > 0 ? he->ix : 0);
3159  char * val = NULL;
3160  int i;
3161 
3162 assert(ix == 0);
3163  switch(he->t) {
3164  default:
3165  val = xstrdup(_("(invalid type :uuid)"));
3166  goto exit;
3167  /*@notreached@*/ break;
3168  case RPM_STRING_TYPE:
3169  break;
3170  }
3171 
3172  if (!(av && av[0] && *av[0]))
3173  av = avdefault;
3174 
3175  for (i = 0; av[i] != NULL; i++) {
3176  uint32_t keyval = keyValue(keyUuids, nkeyUuids, av[i]);
3177 
3178  switch (keyval) {
3179  default:
3180  break;
3181  case UUID_KEYS_V1:
3182  case UUID_KEYS_V3:
3183  case UUID_KEYS_V4:
3184  case UUID_KEYS_V5:
3185  version = keyval;
3186  break;
3187  }
3188  }
3189 
3190  /* XXX use private tag container to avoid memory issues for now. */
3191  { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
3192  int xx;
3193  nhe->tag = he->tag;
3194  nhe->t = he->t;
3195  nhe->p.str = xstrdup(he->p.str);
3196  nhe->c = he->c;
3197  val = xmalloc((128/4 + 4) + 1);
3198  xx = str2uuid(nhe, NULL, version, val);
3199  nhe->p.ptr = _free(nhe->p.ptr);
3200  }
3201 
3202 exit:
3203 /*@-globstate@*/
3204  return val;
3205 /*@=globstate@*/
3206 }
3207 
3214 static /*@only@*/ char * rpnFormat(HE_t he, /*@null@*/ const char ** av)
3215  /*@*/
3216 {
3217  int ac = argvCount(av) + 1;
3218  int64_t * stack = memset(alloca(ac*sizeof(*stack)), 0, (ac*sizeof(*stack)));
3219  char * end;
3220  char * val = NULL;
3221  int ix = 0;
3222  int i;
3223 
3224  switch(he->t) {
3225  default:
3226  val = xstrdup(_("(invalid type :rpn)"));
3227  goto exit;
3228  /*@notreached@*/ break;
3229  case RPM_UINT64_TYPE:
3230  stack[ix] = he->p.ui64p[0];
3231  break;
3232  case RPM_STRING_TYPE:
3233  end = NULL;
3234  stack[ix] = strtoll(he->p.str, &end, 0);
3235  if (*end != '\0') {
3236  val = xstrdup(_("(invalid string :rpn)"));
3237  goto exit;
3238  }
3239  break;
3240  }
3241 
3242  if (av != NULL)
3243  for (i = 0; av[i] != NULL; i++) {
3244  const char * arg = av[i];
3245  size_t len = strlen(arg);
3246  int c = *arg;
3247 
3248  if (len == 0) {
3249  /* do nothing */
3250  } else if (len > 1) {
3251  if (!(xisdigit(c) || (c == '-' && xisdigit(arg[1])))) {
3252  val = xstrdup(_("(expected number :rpn)"));
3253  goto exit;
3254  }
3255  if (++ix == ac) {
3256  val = xstrdup(_("(stack overflow :rpn)"));
3257  goto exit;
3258  }
3259  end = NULL;
3260  stack[ix] = strtoll(arg, &end, 0);
3261  if (*end != '\0') {
3262  val = xstrdup(_("(invalid number :rpn)"));
3263  goto exit;
3264  }
3265  } else {
3266  if (ix-- < 1) {
3267  val = xstrdup(_("(stack underflow :rpn)"));
3268  goto exit;
3269  }
3270  switch (c) {
3271  case '&': stack[ix] &= stack[ix+1]; break;
3272  case '|': stack[ix] |= stack[ix+1]; break;
3273  case '^': stack[ix] ^= stack[ix+1]; break;
3274  case '+': stack[ix] += stack[ix+1]; break;
3275  case '-': stack[ix] -= stack[ix+1]; break;
3276  case '*': stack[ix] *= stack[ix+1]; break;
3277  case '%':
3278  case '/':
3279  if (stack[ix+1] == 0) {
3280  val = xstrdup(_("(divide by zero :rpn)"));
3281  goto exit;
3282  }
3283  if (c == '%')
3284  stack[ix] %= stack[ix+1];
3285  else
3286  stack[ix] /= stack[ix+1];
3287  break;
3288  }
3289  }
3290  }
3291 
3292  { HE_t nhe = memset(alloca(sizeof(*nhe)), 0, sizeof(*nhe));
3293  nhe->tag = he->tag;
3294  nhe->t = RPM_UINT64_TYPE;
3295  nhe->p.ui64p = (uint64_t *)&stack[ix];
3296  nhe->c = 1;
3297  val = intFormat(nhe, NULL, NULL);
3298  }
3299 
3300 exit:
3301 /*@-globstate@*/
3302  return val;
3303 /*@=globstate@*/
3304 }
3305 
3306 /*@-type@*/ /* FIX: cast? */
3308  { HEADER_EXT_TAG, "RPMTAG_BUILDTIMEUUID",
3309  { .tagFunction = buildtime_uuidTag } },
3310  { HEADER_EXT_TAG, "RPMTAG_CHANGELOGNAME",
3311  { .tagFunction = changelognameTag } },
3312  { HEADER_EXT_TAG, "RPMTAG_CHANGELOGTEXT",
3313  { .tagFunction = changelogtextTag } },
3314  { HEADER_EXT_TAG, "RPMTAG_DESCRIPTION",
3315  { .tagFunction = descriptionTag } },
3316  { HEADER_EXT_TAG, "RPMTAG_ENHANCES",
3317  { .tagFunction = missingokTag } },
3318  { HEADER_EXT_TAG, "RPMTAG_FILECLASS",
3319  { .tagFunction = fileclassTag } },
3320  { HEADER_EXT_TAG, "RPMTAG_FILECONTEXTS",
3321  { .tagFunction = filecontextsTag } },
3322  { HEADER_EXT_TAG, "RPMTAG_FILENAMES",
3323  { .tagFunction = filepathsTag } },
3324  { HEADER_EXT_TAG, "RPMTAG_ORIGPATHS",
3325  { .tagFunction = origpathsTag } },
3326  { HEADER_EXT_TAG, "RPMTAG_FILEPROVIDE",
3327  { .tagFunction = fileprovideTag } },
3328  { HEADER_EXT_TAG, "RPMTAG_FILEREQUIRE",
3329  { .tagFunction = filerequireTag } },
3330  { HEADER_EXT_TAG, "RPMTAG_FSCONTEXTS",
3331  { .tagFunction = fscontextsTag } },
3332  { HEADER_EXT_TAG, "RPMTAG_FSNAMES",
3333  { .tagFunction = fsnamesTag } },
3334  { HEADER_EXT_TAG, "RPMTAG_FSSIZES",
3335  { .tagFunction = fssizesTag } },
3336  { HEADER_EXT_TAG, "RPMTAG_GROUP",
3337  { .tagFunction = groupTag } },
3338  { HEADER_EXT_TAG, "RPMTAG_HDRUUID",
3339  { .tagFunction = hdruuidTag } },
3340  { HEADER_EXT_TAG, "RPMTAG_INSTALLPREFIX",
3341  { .tagFunction = instprefixTag } },
3342  { HEADER_EXT_TAG, "RPMTAG_INSTALLTIDUUID",
3343  { .tagFunction = installtid_uuidTag } },
3344  { HEADER_EXT_TAG, "RPMTAG_INSTALLTIMEUUID",
3345  { .tagFunction = installtime_uuidTag } },
3346  { HEADER_EXT_TAG, "RPMTAG_ORIGINTIDUUID",
3347  { .tagFunction = origintid_uuidTag } },
3348  { HEADER_EXT_TAG, "RPMTAG_ORIGINTIMEUUID",
3349  { .tagFunction = origintime_uuidTag } },
3350  { HEADER_EXT_TAG, "RPMTAG_PKGUUID",
3351  { .tagFunction = pkguuidTag } },
3352  { HEADER_EXT_TAG, "RPMTAG_RECONTEXTS",
3353  { .tagFunction = recontextsTag } },
3354  { HEADER_EXT_TAG, "RPMTAG_REMOVETIDUUID",
3355  { .tagFunction = removetid_uuidTag } },
3356  { HEADER_EXT_TAG, "RPMTAG_SUGGESTS",
3357  { .tagFunction = missingokTag } },
3358  { HEADER_EXT_TAG, "RPMTAG_SOURCEPKGUUID",
3359  { .tagFunction = sourcepkguuidTag } },
3360  { HEADER_EXT_TAG, "RPMTAG_SUMMARY",
3361  { .tagFunction = summaryTag } },
3362  { HEADER_EXT_TAG, "RPMTAG_TRIGGERCONDS",
3363  { .tagFunction = triggercondsTag } },
3364  { HEADER_EXT_TAG, "RPMTAG_TRIGGERTYPE",
3365  { .tagFunction = triggertypeTag } },
3366  { HEADER_EXT_TAG, "RPMTAG_DBINSTANCE",
3367  { .tagFunction = dbinstanceTag } },
3368  { HEADER_EXT_TAG, "RPMTAG_HEADERSTARTOFF",
3369  { .tagFunction = headerstartoffTag } },
3370  { HEADER_EXT_TAG, "RPMTAG_HEADERENDOFF",
3371  { .tagFunction = headerendoffTag } },
3372  { HEADER_EXT_TAG, "RPMTAG_PACKAGEBASEURL",
3373  { .tagFunction = pkgbaseurlTag } },
3374  { HEADER_EXT_TAG, "RPMTAG_PACKAGEDIGEST",
3375  { .tagFunction = pkgdigestTag } },
3376  { HEADER_EXT_TAG, "RPMTAG_PACKAGEORIGIN",
3377  { .tagFunction = pkgoriginTag } },
3378  { HEADER_EXT_TAG, "RPMTAG_PACKAGESIZE",
3379  { .tagFunction = pkgsizeTag } },
3380  { HEADER_EXT_TAG, "RPMTAG_PACKAGETIME",
3381  { .tagFunction = pkgmtimeTag } },
3382  { HEADER_EXT_TAG, "RPMTAG_NVRA",
3383  { .tagFunction = nvraTag } },
3384  { HEADER_EXT_TAG, "RPMTAG_PROVIDEXMLENTRY",
3385  { .tagFunction = PxmlTag } },
3386  { HEADER_EXT_TAG, "RPMTAG_REQUIREXMLENTRY",
3387  { .tagFunction = RxmlTag } },
3388  { HEADER_EXT_TAG, "RPMTAG_CONFLICTXMLENTRY",
3389  { .tagFunction = CxmlTag } },
3390  { HEADER_EXT_TAG, "RPMTAG_OBSOLETEXMLENTRY",
3391  { .tagFunction = OxmlTag } },
3392  { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY1",
3393  { .tagFunction = F1xmlTag } },
3394  { HEADER_EXT_TAG, "RPMTAG_FILESXMLENTRY2",
3395  { .tagFunction = F2xmlTag } },
3396  { HEADER_EXT_TAG, "RPMTAG_PROVIDESQLENTRY",
3397  { .tagFunction = PsqlTag } },
3398  { HEADER_EXT_TAG, "RPMTAG_REQUIRESQLENTRY",
3399  { .tagFunction = RsqlTag } },
3400  { HEADER_EXT_TAG, "RPMTAG_CONFLICTSQLENTRY",
3401  { .tagFunction = CsqlTag } },
3402  { HEADER_EXT_TAG, "RPMTAG_OBSOLETESQLENTRY",
3403  { .tagFunction = OsqlTag } },
3404  { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY1",
3405  { .tagFunction = F1sqlTag } },
3406  { HEADER_EXT_TAG, "RPMTAG_FILESSQLENTRY2",
3407  { .tagFunction = F2sqlTag } },
3408  { HEADER_EXT_FORMAT, "armor",
3409  { .fmtFunction = armorFormat } },
3410  { HEADER_EXT_FORMAT, "base64",
3411  { .fmtFunction = base64Format } },
3412  { HEADER_EXT_FORMAT, "bncdata",
3413  { .fmtFunction = bncdataFormat } },
3414  { HEADER_EXT_FORMAT, "cdata",
3415  { .fmtFunction = cdataFormat } },
3416  { HEADER_EXT_FORMAT, "depflags",
3417  { .fmtFunction = depflagsFormat } },
3418  { HEADER_EXT_FORMAT, "digest",
3419  { .fmtFunction = digestFormat } },
3420  { HEADER_EXT_FORMAT, "fflags",
3421  { .fmtFunction = fflagsFormat } },
3422  { HEADER_EXT_FORMAT, "iconv",
3423  { .fmtFunction = iconvFormat } },
3424  { HEADER_EXT_FORMAT, "perms",
3425  { .fmtFunction = permsFormat } },
3426  { HEADER_EXT_FORMAT, "permissions",
3427  { .fmtFunction = permsFormat } },
3428  { HEADER_EXT_FORMAT, "pgpsig",
3429  { .fmtFunction = pgpsigFormat } },
3430  { HEADER_EXT_FORMAT, "rpn",
3431  { .fmtFunction = rpnFormat } },
3432  { HEADER_EXT_FORMAT, "sqlescape",
3433  { .fmtFunction = sqlescapeFormat } },
3434  { HEADER_EXT_FORMAT, "stat",
3435  { .fmtFunction = statFormat } },
3436  { HEADER_EXT_FORMAT, "triggertype",
3437  { .fmtFunction = triggertypeFormat } },
3438  { HEADER_EXT_FORMAT, "utf8",
3439  { .fmtFunction = iconvFormat } },
3440  { HEADER_EXT_FORMAT, "uuid",
3441  { .fmtFunction = uuidFormat } },
3442  { HEADER_EXT_FORMAT, "xml",
3443  { .fmtFunction = xmlFormat } },
3444  { HEADER_EXT_FORMAT, "yaml",
3445  { .fmtFunction = yamlFormat } },
3446  { HEADER_EXT_MORE, NULL,
3447  { .more = (void *) headerDefaultFormats } }
3448 } ;
3449 /*@=type@*/