rpm  5.4.15
macro.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 #include <stdarg.h>
7 
8 #if !defined(isblank)
9 #define isblank(_c) ((char)(_c) == ' ' || (char)(_c) == '\t')
10 #endif
11 #define iseol(_c) ((char)(_c) == '\n' || (char)(_c) == '\r')
12 
13 #define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && !strncmp((_t), (_f), (_fn)))
14 
15 #ifdef DEBUG_MACROS
16 #undef WITH_LUA /* XXX fixme */
17 #include <sys/types.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <getopt.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <popt.h>
26 
27 #define rpmlog fprintf
28 #define RPMLOG_ERR stderr
29 #define RPMLOG_WARNING stderr
30 #undef _
31 #define _(x) x
32 
33 #define vmefail(_nb) (exit(1), NULL)
34 #define URL_IS_DASH 1
35 #define URL_IS_PATH 2
36 #define urlPath(_xr, _r) (*(_r) = (_xr), URL_IS_PATH)
37 #define xisalnum(_c) isalnum(_c)
38 #define xisalpha(_c) isalpha(_c)
39 #define xisdigit(_c) isdigit(_c)
40 #define xisspace(_c) isspace(_c)
41 
42 typedef FILE * FD_t;
43 #define Fopen(_path, _fmode) fopen(_path, "r");
44 #define Ferror ferror
45 #define Fstrerror(_fd) strerror(errno)
46 #define Fread fread
47 #define Fclose fclose
48 
49 #define fdGetFILE(_fd) (_fd)
50 
51 /*@unused@*/ static inline /*@null@*/ void *
52 _free(/*@only@*/ /*@null@*/ const void * p)
53  /*@modifies p@*/
54 {
55  if (p != NULL) free((void *)p);
56  return NULL;
57 }
58 
59 #else
60 
61 /*@observer@*/ /*@checked@*/
62 const char * rpmMacrofiles = MACROFILES;
63 
64 #include <rpmio_internal.h>
65 #include <rpmlog.h>
66 #include <mire.h>
67 
68 #ifdef WITH_LUA
69 #define _RPMLUA_INTERNAL /* XXX lua->printbuf access */
70 #include <rpmlua.h>
71 #endif
72 
73 #define _RPMAUG_INTERNAL /* XXX for _rpmaugFoo globals */
74 #include <rpmaug.h>
75 #include <rpmficl.h>
76 #include <rpmgit.h>
77 #include <rpmjs.h>
78 
79 #if defined(WITH_NIX)
80 #define _RPMNIX_INTERNAL
81 #include <rpmnix.h>
82 #endif
83 
84 #include <rpmjni.h>
85 #include <rpmjs.h>
86 #include <rpmmrb.h>
87 #include <rpmperl.h>
88 #include <rpmpython.h>
89 #include <rpmruby.h>
90 #include <rpmsm.h>
91 #include <rpmsquirrel.h>
92 #include <rpmsql.h>
93 #include <rpmtcl.h>
94 
95 #endif
96 
97 #include <rpmuuid.h>
98 
99 #define _MACRO_INTERNAL
100 #include <rpmmacro.h>
101 
102 #include "debug.h"
103 
104 /*@unchecked@*/
105 #if defined(WITH_AUGEAS) || defined(WITH_FICL) || defined(WITH_GPSEE) || defined(WITH_NIX) || defined(WITH_PERLEMBED) || defined(WITH_PYTHONEMBED) || defined(WITH_RUBYEMBED) || defined(WITH_SQLITE) || defined(WITH_SQUIRREL) || defined(WITH_TCL) || defined(WITH_SEMANAGE)
106 static int _globalI = 0x80000000;
107 #endif
108 
109 #if defined(__LCLINT__)
110 /*@-exportheader@*/
111 extern const unsigned short int **__ctype_b_loc (void) /*@*/;
112 /*@=exportheader@*/
113 #endif
114 
115 /*@access FD_t @*/ /* XXX compared with NULL */
116 /*@access miRE @*/ /* XXX cast */
117 /*@access MacroContext @*/
118 /*@access MacroEntry@ */
119 /*@access rpmlua @*/
120 /*@access rpmtcl @*/
121 
122 static struct MacroContext_s rpmGlobalMacroContext_s;
123 /*@-compmempass@*/
125 /*@=compmempass@*/
126 
127 static struct MacroContext_s rpmCLIMacroContext_s;
128 /*@-compmempass@*/
130 /*@=compmempass@*/
131 
135 typedef /*@abstract@*/ struct MacroBuf_s {
136 /*@kept@*/ /*@exposed@*/
137  const char * s;
138 /*@shared@*/
139  char * t;
140  size_t nb;
141  int depth;
144 /*@kept@*/ /*@exposed@*/ /*@null@*/
145  void * spec;
146 /*@kept@*/ /*@exposed@*/
148 } * MacroBuf;
149 
150 #define SAVECHAR(_mb, _c) { *(_mb)->t = (char) (_c), (_mb)->t++, (_mb)->nb--; }
151 
152 /*@-exportlocal -exportheadervar@*/
153 
154 #define _MAX_MACRO_DEPTH 16
155 /*@unchecked@*/
157 
158 #define _PRINT_MACRO_TRACE 0
159 /*@unchecked@*/
161 
162 #define _PRINT_EXPAND_TRACE 0
163 /*@unchecked@*/
165 
166 #define _MAX_LOAD_DEPTH 2
167 /*@unchecked@*/
169 /*@=exportlocal =exportheadervar@*/
170 
171 #define MACRO_CHUNK_SIZE 16
172 
173 /* Size of expansion buffers. */
174 /*@unchecked@*/
175 static size_t _macro_BUFSIZ = 16 * 1024;
176 
177 /* forward ref */
178 static int expandMacro(MacroBuf mb)
179  /*@globals rpmGlobalMacroContext,
180  print_macro_trace, print_expand_trace, h_errno,
181  fileSystem, internalState @*/
182  /*@modifies mb, rpmGlobalMacroContext,
183  print_macro_trace, print_expand_trace,
184  fileSystem, internalState @*/;
185 
186 /* =============================================================== */
187 
194 static int
195 compareMacroName(const void * ap, const void * bp)
196  /*@*/
197 {
198  MacroEntry ame = *((MacroEntry *)ap);
199  MacroEntry bme = *((MacroEntry *)bp);
200 
201  if (ame == NULL && bme == NULL)
202  return 0;
203  if (ame == NULL)
204  return 1;
205  if (bme == NULL)
206  return -1;
207  return strcmp(ame->name, bme->name);
208 }
209 
214 static void
216  /*@modifies mc @*/
217 {
218  if (mc->macroTable == NULL) {
219  mc->macrosAllocated = MACRO_CHUNK_SIZE;
220  mc->macroTable = (MacroEntry *)
221  xmalloc(sizeof(*mc->macroTable) * mc->macrosAllocated);
222  mc->firstFree = 0;
223  } else {
224  mc->macrosAllocated += MACRO_CHUNK_SIZE;
225  mc->macroTable = (MacroEntry *)
226  xrealloc(mc->macroTable, sizeof(*mc->macroTable) *
227  mc->macrosAllocated);
228  }
229  memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
230 }
231 
236 static void
238  /*@modifies mc @*/
239 {
240  int i;
241 
242  if (mc == NULL || mc->macroTable == NULL)
243  return;
244 
245  qsort(mc->macroTable, mc->firstFree, sizeof(mc->macroTable[0]),
247 
248  /* Empty pointers are now at end of table. Reset first free index. */
249  for (i = 0; i < mc->firstFree; i++) {
250  if (mc->macroTable[i] != NULL)
251  continue;
252  mc->firstFree = i;
253  break;
254  }
255 }
256 
257 #if !defined(DEBUG_MACROS)
258 /*@only@*/
259 static char * dupMacroEntry(MacroEntry me)
260  /*@*/
261 {
262  char * t, * te;
263  size_t nb;
264 
265 assert(me != NULL);
266  nb = strlen(me->name) + sizeof("%") - 1;
267  if (me->opts)
268  nb += strlen(me->opts) + sizeof("()") - 1;
269  if (me->body)
270  nb += strlen(me->body) + sizeof("\t") - 1;
271  nb++;
272 
273  t = te = (char *) xmalloc(nb);
274  *te = '\0';
275  te = stpcpy( stpcpy(te, "%"), me->name);
276  if (me->opts)
277  te = stpcpy( stpcpy( stpcpy(te, "("), me->opts), ")");
278  if (me->body)
279  te = stpcpy( stpcpy(te, "\t"), me->body);
280  *te = '\0';
281 
282  return t;
283 }
284 #endif
285 
286 void
288 {
289  int nempty = 0;
290  int nactive = 0;
291 
292  if (mc == NULL) mc = rpmGlobalMacroContext;
293  if (fp == NULL) fp = stderr;
294 
295  fprintf(fp, "========================\n");
296  if (mc->macroTable != NULL) {
297  int i;
298  for (i = 0; i < mc->firstFree; i++) {
299  MacroEntry me;
300  if ((me = mc->macroTable[i]) == NULL) {
301  /* XXX this should never happen */
302  nempty++;
303  continue;
304  }
305  fprintf(fp, "%3d%c %s", me->level,
306  (me->used > 0 ? '=' : ':'), me->name);
307  if (me->opts && *me->opts)
308  fprintf(fp, "(%s)", me->opts);
309  if (me->body && *me->body)
310  fprintf(fp, "\t%s", me->body);
311  fprintf(fp, "\n");
312  nactive++;
313  }
314  }
315  fprintf(fp, _("======================== active %d empty %d\n"),
316  nactive, nempty);
317 }
318 
319 #if !defined(DEBUG_MACROS)
320 int
321 rpmGetMacroEntries(MacroContext mc, void * _mire, int used,
322  const char *** avp)
323 {
324 /*@-assignexpose -castexpose @*/
325  miRE mire = (miRE) _mire;
326 /*@=assignexpose =castexpose @*/
327  const char ** av;
328  int ac = 0;
329  int i;
330 
331  if (mc == NULL)
333 
334  if (avp == NULL)
335  return mc->firstFree;
336 
337  av = (const char **) xcalloc( (mc->firstFree+1), sizeof(mc->macroTable[0]));
338  if (mc->macroTable != NULL)
339  for (i = 0; i < mc->firstFree; i++) {
340  MacroEntry me;
341  me = mc->macroTable[i];
342  if (used > 0 && me->used < used)
343  continue;
344  if (used == 0 && me->used != 0)
345  continue;
346 #if !defined(DEBUG_MACROS) /* XXX preserve standalone build */
347  if (mire != NULL && mireRegexec(mire, me->name, 0) < 0)
348  continue;
349 #endif
350  av[ac++] = dupMacroEntry(me);
351  }
352  av[ac] = NULL;
353  *avp = av = (const char **) xrealloc(av, (ac+1) * sizeof(*av));
354 
355  return ac;
356 }
357 #endif
358 
366 /*@dependent@*/ /*@null@*/
367 static MacroEntry *
368 findEntry(MacroContext mc, const char * name, size_t namelen)
369  /*@*/
370 {
371  MacroEntry key, *ret;
372 
373 /*@-globs@*/
374  if (mc == NULL) mc = rpmGlobalMacroContext;
375 /*@=globs@*/
376  if (mc->macroTable == NULL || mc->firstFree == 0)
377  return NULL;
378 
379  if (namelen > 0) {
380  char * t = strncpy((char *)alloca(namelen + 1), name, namelen);
381  t[namelen] = '\0';
382  name = t;
383  }
384 
385  key = (MacroEntry) memset(alloca(sizeof(*key)), 0, sizeof(*key));
386  /*@-temptrans -assignexpose@*/
387  key->name = (char *)name;
388  /*@=temptrans =assignexpose@*/
389  ret = (MacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
390  sizeof(*(mc->macroTable)), compareMacroName);
391  /* XXX TODO: find 1st empty slot and return that */
392  return ret;
393 }
394 
395 /* =============================================================== */
396 
404 /*@null@*/
405 static char *
406 rdcl(/*@returned@*/ char * buf, size_t size, FD_t fd)
407  /*@globals fileSystem @*/
408  /*@modifies buf, fileSystem @*/
409 {
410  char *q = buf - 1; /* initialize just before buffer. */
411  size_t nb = 0;
412  size_t nread = 0;
413  FILE * f = fdGetFILE(fd);
414  int pc = 0, bc = 0;
415  char *p = buf;
416 
417  if (f != NULL)
418  do {
419  *(++q) = '\0'; /* terminate and move forward. */
420  if (fgets(q, (int)size, f) == NULL) /* read next line. */
421  break;
422  nb = strlen(q);
423  nread += nb; /* trim trailing \r and \n */
424  for (q += nb - 1; nb > 0 && iseol(*q); q--)
425  nb--;
426  for (; p <= q; p++) {
427  switch (*p) {
428  case '\\':
429  switch (*(p+1)) {
430  case '\r': /*@switchbreak@*/ break;
431  case '\n': /*@switchbreak@*/ break;
432  case '\0': /*@switchbreak@*/ break;
433  default: p++; /*@switchbreak@*/ break;
434  }
435  /*@switchbreak@*/ break;
436  case '%':
437  switch (*(p+1)) {
438  case '{': p++, bc++; /*@switchbreak@*/ break;
439  case '(': p++, pc++; /*@switchbreak@*/ break;
440  case '%': p++; /*@switchbreak@*/ break;
441  }
442  /*@switchbreak@*/ break;
443  case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
444  case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
445  case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
446  case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
447  }
448  }
449  if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
450  *(++q) = '\0'; /* trim trailing \r, \n */
451  break;
452  }
453  q++; p++; nb++; /* copy newline too */
454  size -= nb;
455  if (*q == '\r') /* XXX avoid \r madness */
456  *q = '\n';
457  } while (size > 0);
458  return (nread > 0 ? buf : NULL);
459 }
460 
468 /*@null@*/
469 static const char *
470 matchchar(const char * p, char pl, char pr)
471  /*@*/
472 {
473  int lvl = 0;
474  char c;
475 
476  while ((c = *p++) != '\0') {
477  if (c == '\\') { /* Ignore escaped chars */
478  p++;
479  continue;
480  }
481  if (c == pr) {
482  if (--lvl <= 0) return --p;
483  } else if (c == pl)
484  lvl++;
485  }
486  return (const char *)NULL;
487 }
488 
495 static void
496 printMacro(MacroBuf mb, const char * s, const char * se)
497  /*@globals fileSystem @*/
498  /*@modifies fileSystem @*/
499 {
500  const char *senl;
501  const char *ellipsis;
502  int choplen;
503 
504  if (s >= se) { /* XXX just in case */
505  fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
506  (2 * mb->depth + 1), "");
507  return;
508  }
509 
510  if (s[-1] == '{')
511  s--;
512 
513  /* Print only to first end-of-line (or end-of-string). */
514  for (senl = se; *senl && !iseol(*senl); senl++)
515  {};
516 
517  /* Limit trailing non-trace output */
518  choplen = 61 - (2 * mb->depth);
519  if ((senl - s) > choplen) {
520  senl = s + choplen;
521  ellipsis = "...";
522  } else
523  ellipsis = "";
524 
525  /* Substitute caret at end-of-macro position */
526  fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
527  (2 * mb->depth + 1), "", (int)(se - s), s);
528  if (se[1] != '\0' && (senl - (se+1)) > 0)
529  fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
530  fprintf(stderr, "\n");
531 }
532 
539 static void
540 printExpansion(MacroBuf mb, const char * t, const char * te)
541  /*@globals fileSystem @*/
542  /*@modifies fileSystem @*/
543 {
544  const char *ellipsis;
545  int choplen;
546 
547  if (!(te > t)) {
548  fprintf(stderr, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
549  return;
550  }
551 
552  /* Shorten output which contains newlines */
553  while (te > t && iseol(te[-1]))
554  te--;
555  ellipsis = "";
556  if (mb->depth > 0) {
557  const char *tenl;
558 
559  /* Skip to last line of expansion */
560  while ((tenl = strchr(t, '\n')) && tenl < te)
561  t = ++tenl;
562 
563  /* Limit expand output */
564  choplen = 61 - (2 * mb->depth);
565  if ((te - t) > choplen) {
566  te = t + choplen;
567  ellipsis = "...";
568  }
569  }
570 
571  fprintf(stderr, "%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
572  if (te > t)
573  fprintf(stderr, "%.*s%s", (int)(te - t), t, ellipsis);
574  fprintf(stderr, "\n");
575 }
576 
577 #define SKIPBLANK(_s, _c) \
578  /*@-globs@*/ /* FIX: __ctype_b */ \
579  while (((_c) = (int) *(_s)) && isblank(_c)) \
580  (_s)++; \
581  /*@=globs@*/
582 
583 #define SKIPNONBLANK(_s, _c) \
584  /*@-globs@*/ /* FIX: __ctype_b */ \
585  while (((_c) = (int) *(_s)) && !(isblank(_c) || iseol(_c))) \
586  (_s)++; \
587  /*@=globs@*/
588 
589 #define COPYNAME(_ne, _s, _c) \
590  { SKIPBLANK(_s,_c); \
591  while(((_c) = (int) *(_s)) && (xisalnum(_c) || (_c) == (int) '_')) \
592  *(_ne)++ = *(_s)++; \
593  *(_ne) = '\0'; \
594  }
595 
596 #define COPYOPTS(_oe, _s, _c) \
597  { while(((_c) = (int) *(_s)) && (_c) != (int) ')') \
598  *(_oe)++ = *(_s)++; \
599  *(_oe) = '\0'; \
600  }
601 
609 static int
610 expandT(MacroBuf mb, const char * f, size_t flen)
611  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
612  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
613 {
614  char *sbuf;
615  const char *s = mb->s;
616  int rc;
617 
618  sbuf = (char *) alloca(flen + 1);
619  memset(sbuf, 0, (flen + 1));
620 
621  strncpy(sbuf, f, flen);
622  sbuf[flen] = '\0';
623  mb->s = sbuf;
624  rc = expandMacro(mb);
625  mb->s = s;
626  return rc;
627 }
628 
629 #if 0
630 
637 static int
638 expandS(MacroBuf mb, char * tbuf, size_t tbuflen)
639  /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
640  /*@modifies mb, *tbuf, rpmGlobalMacroContext, fileSystem, internalState @*/
641 {
642  const char *t = mb->t;
643  size_t nb = mb->nb;
644  int rc;
645 
646  mb->t = tbuf;
647  mb->nb = tbuflen;
648  rc = expandMacro(mb);
649  mb->t = t;
650  mb->nb = nb;
651  return rc;
652 }
653 #endif
654 
662 static int
663 expandU(MacroBuf mb, char * u, size_t ulen)
664  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
665  /*@modifies mb, *u, rpmGlobalMacroContext, fileSystem, internalState @*/
666 {
667  const char *s = mb->s;
668  char *t = mb->t;
669  size_t nb = mb->nb;
670  char *tbuf;
671  int rc;
672 
673  tbuf = (char *) alloca(ulen + 1);
674  memset(tbuf, 0, (ulen + 1));
675 
676  mb->s = u;
677  mb->t = tbuf;
678  mb->nb = ulen;
679  rc = expandMacro(mb);
680 
681  tbuf[ulen] = '\0'; /* XXX just in case */
682  if (ulen > mb->nb)
683  strncpy(u, tbuf, (ulen - mb->nb + 1));
684 
685  mb->s = s;
686  mb->t = t;
687  mb->nb = nb;
688 
689  return rc;
690 }
691 
699 static int
700 doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
701  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
702  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
703 {
704  size_t bufn = _macro_BUFSIZ + clen;
705  char * buf = (char *) alloca(bufn);
706  FILE *shf;
707  int rc;
708  int c;
709  char * start;
710 
711  start = mb->t;
712  strncpy(buf, cmd, clen);
713  buf[clen] = '\0';
714  rc = expandU(mb, buf, bufn);
715  if (rc)
716  return rc;
717 
718  if ((shf = popen(buf, "r")) == NULL)
719  return 1;
720  while(mb->nb > 0 && (c = fgetc(shf)) != EOF)
721  SAVECHAR(mb, c);
722  (void) pclose(shf);
723 
724  /* XXX delete trailing \r \n */
725  while (mb->t > start && iseol(mb->t[-1])) {
726  *(mb->t--) = '\0';
727  mb->nb++;
728  }
729  return 0;
730 }
731 
740 /*@dependent@*/ static const char *
741 doDefine(MacroBuf mb, /*@returned@*/ const char * se, int level, int expandbody)
742  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
743  /*@modifies mb, rpmGlobalMacroContext, internalState @*/
744 {
745  const char *s = se;
746  size_t bufn = _macro_BUFSIZ;
747  char *buf = (char *) alloca(bufn);
748  char *n = buf, *ne;
749  char *o = NULL, *oe;
750  char *b, *be;
751  int c;
752  int oc = (int) ')';
753 
754  SKIPBLANK(s, c);
755  if (c == (int) '.') /* XXX readonly macros */
756 /*@i@*/ *n++ = c = *s++;
757  if (c == (int) '.') /* XXX readonly macros */
758 /*@i@*/ *n++ = c = *s++;
759  ne = n;
760 
761  /* Copy name */
762  COPYNAME(ne, s, c);
763 
764  /* Copy opts (if present) */
765  oe = ne + 1;
766  if (*s == '(') {
767  s++; /* skip ( */
768  o = oe;
769  COPYOPTS(oe, s, oc);
770  /* Options must be terminated with ')' */
771  if (oc != ')') {
772  rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
773  se = s; /* XXX W2DO? */
774  return se;
775  }
776  s++; /* skip ) */
777  }
778 
779  /* Copy body, skipping over escaped newlines */
780  b = be = oe + 1;
781  SKIPBLANK(s, c);
782  if (c == (int) '{') { /* XXX permit silent {...} grouping */
783  if ((se = matchchar(s, (char) c, '}')) == NULL) {
785  _("Macro %%%s has unterminated body\n"), n);
786  se = s; /* XXX W2DO? */
787  return se;
788  }
789  s++; /* XXX skip { */
790  strncpy(b, s, (se - s));
791  b[se - s] = '\0';
792  be += strlen(b);
793  se++; /* XXX skip } */
794  s = se; /* move scan forward */
795  } else { /* otherwise free-field */
796  int bc = 0, pc = 0;
797  while (*s && (bc || pc || !iseol(*s))) {
798  switch (*s) {
799  case '\\':
800  switch (*(s+1)) {
801  case '\0': /*@switchbreak@*/ break;
802  default: s++; /*@switchbreak@*/ break;
803  }
804  /*@switchbreak@*/ break;
805  case '%':
806  switch (*(s+1)) {
807  case '{': *be++ = *s++; bc++; /*@switchbreak@*/ break;
808  case '(': *be++ = *s++; pc++; /*@switchbreak@*/ break;
809  case '%': *be++ = *s++; /*@switchbreak@*/ break;
810  }
811  /*@switchbreak@*/ break;
812  case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
813  case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
814  case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
815  case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
816  }
817  *be++ = *s++;
818  }
819  *be = '\0';
820 
821  if (bc || pc) {
823  _("Macro %%%s has unterminated body\n"), n);
824  se = s; /* XXX W2DO? */
825  return se;
826  }
827 
828  /* Trim trailing blanks/newlines */
829 /*@-globs@*/
830  while (--be >= b && (c = (int) *be) && (isblank(c) || iseol(c)))
831  {};
832 /*@=globs@*/
833  *(++be) = '\0'; /* one too far */
834  }
835 
836  /* Move scan over body */
837  while (iseol(*s))
838  s++;
839  se = s;
840 
841  /* Names must start with alphabetic or _ and be at least 3 chars */
842  if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) {
844  _("Macro %%%s has illegal name (%%define)\n"), n);
845  return se;
846  }
847 
848  if ((be - b) < 1) {
849  rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
850  return se;
851  }
852 
853 /*@-modfilesys@*/
854  if (expandbody && expandU(mb, b, (&buf[bufn] - b))) {
855  rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
856  return se;
857  }
858 /*@=modfilesys@*/
859 
860  if (n != buf) /* XXX readonly macros */
861  n--;
862  if (n != buf) /* XXX readonly macros */
863  n--;
864  addMacro(mb->mc, n, o, b, (level - 1));
865 
866  return se;
867 }
868 
869 void delMacroAll(MacroContext mc, const char * n);
870 
877 /*@dependent@*/ static const char *
878 doUndefine(MacroContext mc, /*@returned@*/ const char * se)
879  /*@globals rpmGlobalMacroContext @*/
880  /*@modifies mc, rpmGlobalMacroContext @*/
881 {
882  const char *s = se;
883  char *buf = (char *) alloca(_macro_BUFSIZ);
884  char *n = buf, *ne = n;
885  int c;
886 
887  COPYNAME(ne, s, c);
888 
889  /* Move scan over body */
890  while (iseol(*s))
891  s++;
892  se = s;
893 
894  /* Names must start with alphabetic or _ and be at least 3 chars */
895  if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) {
897  _("Macro %%%s has illegal name (%%undefine)\n"), n);
898  return se;
899  }
900 
901  delMacro(mc, n);
902 
903  return se;
904 }
905 
912 /*@dependent@*/ static const char *
913 doUnglobal(MacroContext mc, /*@returned@*/ const char * se)
914  /*@globals rpmGlobalMacroContext @*/
915  /*@modifies mc, rpmGlobalMacroContext @*/
916 {
917  const char *s = se;
918  char *buf = alloca(_macro_BUFSIZ);
919  char *n = buf, *ne = n;
920  int c;
921 
922  COPYNAME(ne, s, c);
923 
924  /* Move scan over body */
925  while (iseol(*s))
926  s++;
927  se = s;
928 
929  /* Names must start with alphabetic or _ and be at least 3 chars */
930  if (!((c = *n) && (xisalpha(c) || c == '_') && (ne - n) > 2)) {
932  _("Macro %%%s has illegal name (%%unglobal)\n"), n);
933  return se;
934  }
935 
936  delMacroAll(mc, n);
937 
938  return se;
939 }
940 
941 #ifdef DYING
942 static void
943 dumpME(const char * msg, MacroEntry me)
944  /*@globals fileSystem @*/
945  /*@modifies fileSystem @*/
946 {
947  if (msg)
948  fprintf(stderr, "%s", msg);
949  fprintf(stderr, "\tme %p", me);
950  if (me)
951  fprintf(stderr,"\tname %p(%s) prev %p",
952  me->name, me->name, me->prev);
953  fprintf(stderr, "\n");
954 }
955 #endif
956 
965 static void
966 pushMacro(/*@out@*/ MacroEntry * mep, const char * n, /*@null@*/ const char * o,
967  /*@null@*/ const char * b, int level)
968  /*@modifies *mep @*/
969 {
970  MacroEntry prev = (mep && *mep ? *mep : NULL);
971  MacroEntry me = (MacroEntry) xmalloc(sizeof(*me));
972  const char *name = n;
973 
974  if (*name == '.') /* XXX readonly macros */
975  name++;
976  if (*name == '.') /* XXX readonly macros */
977  name++;
978 
979  /*@-assignexpose@*/
980  me->prev = prev;
981  /*@=assignexpose@*/
982  me->name = (prev ? prev->name : xstrdup(name));
983  me->opts = (o ? xstrdup(o) : NULL);
984  me->body = xstrdup(b ? b : "");
985  me->used = 0;
986  me->level = level;
987  me->flags = (name != n);
988  if (mep)
989  *mep = me;
990  else {
991  if (me) free(me);
992  me = NULL;
993  }
994 }
995 
1000 static void
1002  /*@modifies *mep @*/
1003 {
1004  MacroEntry me = (*mep ? *mep : NULL);
1005 
1006  if (me) {
1007  /* XXX cast to workaround const */
1008  /*@-onlytrans@*/
1009  if ((*mep = me->prev) == NULL)
1010  me->name = _free(me->name);
1011  me->opts = _free(me->opts);
1012  me->body = _free(me->body);
1013  if (me) free(me);
1014  me = NULL;
1015  /*@=onlytrans@*/
1016  }
1017 }
1018 
1023 static void
1025  /*@modifies mb @*/
1026 {
1027  MacroContext mc = mb->mc;
1028  int ndeleted = 0;
1029  int i;
1030 
1031  if (mc == NULL || mc->macroTable == NULL)
1032  return;
1033 
1034  /* Delete dynamic macro definitions */
1035  for (i = 0; i < mc->firstFree; i++) {
1036  MacroEntry *mep, me;
1037  int skiptest = 0;
1038  mep = &mc->macroTable[i];
1039  me = *mep;
1040 
1041  if (me == NULL) /* XXX this should never happen */
1042  continue;
1043  if (me->level < mb->depth)
1044  continue;
1045  if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
1046  if (*me->name == '*' && me->used > 0)
1047  skiptest = 1; /* XXX skip test for %# %* %0 */
1048  } else if (!skiptest && me->used <= 0) {
1049 #if NOTYET
1051  _("Macro %%%s (%s) was not used below level %d\n"),
1052  me->name, me->body, me->level);
1053 #endif
1054  }
1055  popMacro(mep);
1056  if (!(mep && *mep))
1057  ndeleted++;
1058  }
1059 
1060  /* If any deleted macros, sort macro table */
1061  if (ndeleted)
1062  sortMacroTable(mc);
1063 }
1064 
1074 /*@dependent@*/ static const char *
1075 grabArgs(MacroBuf mb, const MacroEntry me, /*@returned@*/ const char * se,
1076  const char * lastc)
1077  /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
1078  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1079 {
1080  poptContext optCon;
1081  struct poptOption *optTbl;
1082  size_t bufn = _macro_BUFSIZ;
1083  char *buf = (char *) alloca(bufn);
1084  char *b, *be;
1085  char aname[16];
1086  const char *opts;
1087  int argc = 0;
1088  const char **argv;
1089  int c;
1090  unsigned int popt_flags;
1091 
1092  /* Copy macro name as argv[0], save beginning of args. */
1093  buf[0] = '\0';
1094  b = be = stpcpy(buf, me->name);
1095 
1096  addMacro(mb->mc, "0", NULL, buf, mb->depth);
1097 
1098  argc = 1; /* XXX count argv[0] */
1099 
1100  /* Copy args into buf until lastc */
1101  *be++ = ' ';
1102  while ((c = (int) *se++) != (int) '\0' && (se-1) != lastc) {
1103 /*@-globs@*/
1104  if (!isblank(c)) {
1105  *be++ = (char) c;
1106  continue;
1107  }
1108 /*@=globs@*/
1109  /* c is blank */
1110  if (be[-1] == ' ')
1111  continue;
1112  /* a word has ended */
1113  *be++ = ' ';
1114  argc++;
1115  }
1116  if (c == (int) '\0') se--; /* one too far */
1117  if (be[-1] != ' ')
1118  argc++, be++; /* last word has not trailing ' ' */
1119  be[-1] = '\0';
1120  if (*b == ' ') b++; /* skip the leading ' ' */
1121 
1122 /*
1123  * The macro %* analoguous to the shell's $* means "Pass all non-macro
1124  * parameters." Consequently, there needs to be a macro that means "Pass all
1125  * (including macro parameters) options". This is useful for verifying
1126  * parameters during expansion and yet transparently passing all parameters
1127  * through for higher level processing (e.g. %description and/or %setup).
1128  * This is the (potential) justification for %{**} ...
1129  */
1130  /* Add unexpanded args as macro */
1131  addMacro(mb->mc, "**", NULL, b, mb->depth);
1132 
1133 #ifdef NOTYET
1134  /* XXX if macros can be passed as args ... */
1135  expandU(mb, buf, bufn);
1136 #endif
1137 
1138  /* Build argv array */
1139  argv = (const char **) alloca((argc + 1) * sizeof(*argv));
1140  be[-1] = ' '; /* assert((be - 1) == (b + strlen(b) == buf + strlen(buf))) */
1141  be[0] = '\0';
1142 
1143  b = buf;
1144  for (c = 0; c < argc; c++) {
1145  argv[c] = b;
1146  b = strchr(b, ' ');
1147  *b++ = '\0';
1148  }
1149  /* assert(b == be); */
1150  argv[argc] = NULL;
1151 
1152  /* '+' as the first character means that options are recognized
1153  * only before positional arguments, as POSIX requires.
1154  */
1155  popt_flags = POPT_CONTEXT_NO_EXEC;
1156 #if defined(RPM_VENDOR_OPENPKG) /* always-strict-posix-option-parsing */
1157  popt_flags |= POPT_CONTEXT_POSIXMEHARDER;
1158 #endif
1159  if (me->opts[0] == '+') popt_flags |= POPT_CONTEXT_POSIXMEHARDER;
1160 
1161  /* Count the number of short options. */
1162  opts = me->opts;
1163  if (*opts == '+') opts++;
1164  for (c = 0; *opts != '\0'; opts++)
1165  if (*opts != ':') c++;
1166 
1167  /* Set up popt option table. */
1168  optTbl = (struct poptOption *) xcalloc(sizeof(*optTbl), (c + 1));
1169  opts = me->opts;
1170  if (*opts == '+') opts++;
1171  for (c = 0; *opts != '\0'; opts++) {
1172  if (*opts == ':') continue;
1173  optTbl[c].shortName = opts[0];
1174  optTbl[c].val = (int) opts[0];
1175  if (opts[1] == ':')
1176  optTbl[c].argInfo = POPT_ARG_STRING;
1177  c++;
1178  }
1179 
1180  /* Parse the options, defining option macros. */
1181 /*@-nullstate@*/
1182  optCon = poptGetContext(argv[0], argc, argv, optTbl, popt_flags);
1183 /*@=nullstate@*/
1184  while ((c = poptGetNextOpt(optCon)) > 0) {
1185  const char * optArg = poptGetOptArg(optCon);
1186  *be++ = '-';
1187  *be++ = (char) c;
1188  if (optArg != NULL) {
1189  *be++ = ' ';
1190  be = stpcpy(be, optArg);
1191  }
1192  *be++ = '\0';
1193  aname[0] = '-'; aname[1] = (char)c; aname[2] = '\0';
1194  addMacro(mb->mc, aname, NULL, b, mb->depth);
1195  if (optArg != NULL) {
1196  aname[0] = '-'; aname[1] = (char)c; aname[2] = '*'; aname[3] = '\0';
1197  addMacro(mb->mc, aname, NULL, optArg, mb->depth);
1198  }
1199  be = b; /* reuse the space */
1200 /*@-dependenttrans -modobserver -observertrans @*/
1201  optArg = _free(optArg);
1202 /*@=dependenttrans =modobserver =observertrans @*/
1203  }
1204  if (c < -1) {
1205  rpmlog(RPMLOG_ERR, _("Unknown option in macro %s(%s): %s: %s\n"),
1206  me->name, me->opts,
1207  poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c));
1208  goto exit;
1209  }
1210 
1211  argv = poptGetArgs(optCon);
1212  argc = 0;
1213  if (argv != NULL)
1214  for (c = 0; argv[c] != NULL; c++)
1215  argc++;
1216 
1217  /* Add arg count as macro. */
1218  sprintf(aname, "%d", argc);
1219  addMacro(mb->mc, "#", NULL, aname, mb->depth);
1220 
1221  /* Add macro for each arg. Concatenate args for %*. */
1222  if (be) {
1223  *be = '\0';
1224  if (argv != NULL)
1225  for (c = 0; c < argc; c++) {
1226  sprintf(aname, "%d", (c + 1));
1227  addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
1228  if (be != b) *be++ = ' '; /* Add space between args */
1229  be = stpcpy(be, argv[c]);
1230  }
1231  }
1232 
1233  /* Add unexpanded args as macro. */
1234  addMacro(mb->mc, "*", NULL, b, mb->depth);
1235 
1236 exit:
1237  optCon = poptFreeContext(optCon);
1238  if (optTbl) free(optTbl);
1239  optTbl = NULL;
1240  return se;
1241 }
1242 
1250 static void
1251 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
1252  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1253  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1254 {
1255  size_t bufn = _macro_BUFSIZ + msglen;
1256  char *buf = (char *) alloca(bufn);
1257 
1258  strncpy(buf, msg, msglen);
1259  buf[msglen] = '\0';
1260  (void) expandU(mb, buf, bufn);
1261  if (waserror)
1262  rpmlog(RPMLOG_ERR, "%s\n", buf);
1263  else
1264  fprintf(stderr, "%s", buf);
1265 }
1266 
1276 static void
1277 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
1278  /*@null@*/ const char * g, size_t gn)
1279  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1280  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1281 {
1282  size_t bufn = _macro_BUFSIZ + fn + gn;
1283  char * buf = (char *) alloca(bufn);
1284  char *b = NULL, *be;
1285  int c;
1286  mode_t mode;
1287 
1288  buf[0] = '\0';
1289  if (g != NULL) {
1290  strncpy(buf, g, gn);
1291  buf[gn] = '\0';
1292  (void) expandU(mb, buf, bufn);
1293  }
1294  if (fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) {
1295  /* Skip leading zeros */
1296  for (c = 5; c < (int)(fn-1) && f[c] == '0' && xisdigit((int)f[c+1]);)
1297  c++;
1298  b = buf;
1299  be = stpncpy( stpcpy(b, "%patch -P "), f+c, fn-c);
1300  *be = '\0';
1301  } else
1302  if (STREQ("basename", f, fn)) {
1303  if ((b = strrchr(buf, '/')) == NULL)
1304  b = buf;
1305  else
1306  b++;
1307  } else if (STREQ("dirname", f, fn)) {
1308  if ((b = strrchr(buf, '/')) != NULL)
1309  *b = '\0';
1310  b = buf;
1311 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */
1312  } else if (STREQ("realpath", f, fn)) {
1313  char rp[PATH_MAX];
1314  char *cp;
1315  size_t l;
1316  if ((cp = realpath(buf, rp)) != NULL) {
1317  l = strlen(cp);
1318  if ((size_t)(l+1) <= bufn) {
1319  memcpy(buf, cp, l+1);
1320  b = buf;
1321  }
1322  }
1323 #endif
1324  } else if (STREQ("getenv", f, fn)) {
1325  char *cp;
1326  if ((cp = getenv(buf)) != NULL)
1327  b = cp;
1328  } else if (STREQ("shrink", f, fn)) {
1329  /*
1330  * shrink body by removing all leading and trailing whitespaces and
1331  * reducing intermediate whitespaces to a single space character.
1332  */
1333  int i, j, k, was_space = 0;
1334  for (i = 0, j = 0, k = (int)strlen(buf); i < k; ) {
1335  if (xisspace((int)(buf[i]))) {
1336  was_space = 1;
1337  i++;
1338  continue;
1339  }
1340  else if (was_space) {
1341  was_space = 0;
1342  if (j > 0) /* remove leading blanks at all */
1343  buf[j++] = ' ';
1344  /* fallthrough */
1345  }
1346  buf[j++] = buf[i++];
1347  }
1348  buf[j] = '\0';
1349  b = buf;
1350  } else if (STREQ("suffix", f, fn)) {
1351  if ((b = strrchr(buf, '.')) != NULL)
1352  b++;
1353  } else if (STREQ("expand", f, fn)) {
1354  b = buf;
1355  } else if (STREQ("verbose", f, fn)) {
1356 #if defined(RPMLOG_MASK)
1357  if (negate)
1358  b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? NULL : buf);
1359  else
1360  b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? buf : NULL);
1361 #else
1362  /* XXX assume always verbose when running standalone */
1363  b = (negate) ? NULL : buf;
1364 #endif
1365  } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
1366  int ut = urlPath(buf, (const char **)&b);
1367  ut = ut; /* XXX quiet gcc */
1368  if (*b == '\0') b = (char *) "/";
1369  } else if (STREQ("uncompress", f, fn)) {
1370  rpmCompressedMagic compressed = COMPRESSED_OTHER;
1371 /*@-globs@*/
1372  for (b = buf; (c = (int)*b) && isblank(c);)
1373  b++;
1374  /* XXX FIXME: file paths with embedded white space needs rework. */
1375  for (be = b; (c = (int)*be) && !isblank(c);)
1376  be++;
1377 /*@=globs@*/
1378  *be++ = '\0';
1379  (void) isCompressed(b, &compressed);
1380  switch(compressed) {
1381  default:
1382  case 0: /* COMPRESSED_NOT */
1383  sprintf(be, "%%__cat %s", b);
1384  break;
1385  case 1: /* COMPRESSED_OTHER */
1386  sprintf(be, "%%__gzip -dc '%s'", b);
1387  break;
1388  case 2: /* COMPRESSED_BZIP2 */
1389  sprintf(be, "%%__bzip2 -dc '%s'", b);
1390  break;
1391  case 3: /* COMPRESSED_ZIP */
1392  sprintf(be, "%%__unzip -qq '%s'", b);
1393  break;
1394  case 4: /* COMPRESSED_LZOP */
1395  sprintf(be, "%%__lzop -dc '%s'", b);
1396  break;
1397  case 5: /* COMPRESSED_LZMA */
1398  sprintf(be, "%%__lzma -dc '%s'", b);
1399  break;
1400  case 6: /* COMPRESSED_XZ */
1401  sprintf(be, "%%__xz -dc '%s'", b);
1402  break;
1403  case 7: /* COMPRESSED_LRZIP */
1404  sprintf(be, "%%__lrzip -dqo- %s", b);
1405  break;
1406  case 8: /* COMPRESSED_LZIP */
1407  sprintf(be, "%%__lzip -dc %s", b);
1408  break;
1409  case 9: /* COMPRESSED_7ZIP */
1410  sprintf(be, "%%__7zip x %s", b);
1411  break;
1412  }
1413  b = be;
1414  } else if (STREQ("mkstemp", f, fn)) {
1415 /*@-globs@*/
1416  for (b = buf; (c = (int)*b) && isblank(c);)
1417  b++;
1418  /* XXX FIXME: file paths with embedded white space needs rework. */
1419  for (be = b; (c = (int)*be) && !isblank(c);)
1420  be++;
1421 /*@=globs@*/
1422 #if defined(HAVE_MKSTEMP)
1423  mode = umask(0077);
1424  (void) close(mkstemp(b));
1425  (void) umask(mode);
1426 #else
1427  (void) mktemp(b);
1428 #endif
1429  } else if (STREQ("mkdtemp", f, fn)) {
1430 /*@-globs@*/
1431  for (b = buf; (c = (int)*b) && isblank(c);)
1432  b++;
1433  /* XXX FIXME: file paths with embedded white space needs rework. */
1434  for (be = b; (c = (int)*be) && !isblank(c);)
1435  be++;
1436 /*@=globs@*/
1437 #if defined(HAVE_MKDTEMP) && !defined(__LCLINT__)
1438  if (mkdtemp(b) == NULL)
1439  perror("mkdtemp");
1440 #else
1441  if ((b = tmpnam(b)) != NULL)
1442  (void) mkdir(b, 0700); /* XXX S_IWRSXU is not included. */
1443 #endif
1444  } else if (STREQ("uuid", f, fn)) {
1445  int uuid_version;
1446  const char *uuid_ns;
1447  const char *uuid_data;
1448  char *cp;
1449  size_t n;
1450 
1451  uuid_version = 1;
1452  uuid_ns = NULL;
1453  uuid_data = NULL;
1454  cp = buf;
1455  if ((n = strspn(cp, " \t\n")) > 0)
1456  cp += n;
1457  if ((n = strcspn(cp, " \t\n")) > 0) {
1458  uuid_version = (int)strtol(cp, (char **)NULL, 10);
1459  cp += n;
1460  if ((n = strspn(cp, " \t\n")) > 0)
1461  cp += n;
1462  if ((n = strcspn(cp, " \t\n")) > 0) {
1463  uuid_ns = cp;
1464  cp += n;
1465  *cp++ = '\0';
1466  if ((n = strspn(cp, " \t\n")) > 0)
1467  cp += n;
1468  if ((n = strcspn(cp, " \t\n")) > 0) {
1469  uuid_data = cp;
1470  cp += n;
1471  *cp++ = '\0';
1472  }
1473  }
1474  }
1475 /*@-nullpass@*/ /* FIX: uuid_ns may be NULL */
1476  if (rpmuuidMake(uuid_version, uuid_ns, uuid_data, buf, NULL))
1477  rpmlog(RPMLOG_ERR, "failed to create UUID\n");
1478  else
1479  b = buf;
1480 /*@=nullpass@*/
1481  } else if (STREQ("S", f, fn)) {
1482  for (b = buf; (c = (int)*b) && xisdigit(c);)
1483  b++;
1484  if (!c) { /* digit index */
1485  b++;
1486  sprintf(b, "%%SOURCE%s", buf);
1487  } else
1488  b = buf;
1489  } else if (STREQ("P", f, fn)) {
1490  for (b = buf; (c = (int) *b) && xisdigit(c);)
1491  b++;
1492  if (!c) { /* digit index */
1493  b++;
1494  sprintf(b, "%%PATCH%s", buf);
1495  } else
1496  b = buf;
1497  } else if (STREQ("F", f, fn)) {
1498  b = buf + strlen(buf) + 1;
1499  sprintf(b, "file%s.file", buf);
1500  }
1501 
1502  if (b) {
1503  (void) expandT(mb, b, strlen(b));
1504  }
1505 }
1506 
1507 static int expandFIFO(MacroBuf mb, MacroEntry me, const char *g, size_t gn)
1508  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1509  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1510 {
1511  int rc = 0;
1512 
1513  if (me) {
1514  if (me->prev) {
1515  rc = expandFIFO(mb, me->prev, g, gn);
1516  rc = expandT(mb, g, gn);
1517  }
1518  rc = expandT(mb, me->body, strlen(me->body));
1519  }
1520  return rc;
1521 }
1522 
1523 #if !defined(DEBUG_MACROS)
1524 /* =============================================================== */
1525 /* XXX dupe'd to avoid change in linkage conventions. */
1526 
1527 #define POPT_ERROR_NOARG -10
1528 #define POPT_ERROR_BADQUOTE -15
1529 #define POPT_ERROR_MALLOC -21
1531 #define POPT_ARGV_ARRAY_GROW_DELTA 5
1532 
1533 static int XpoptDupArgv(int argc, char **argv,
1534  int * argcPtr, char *** argvPtr)
1535  /*@modifies *argcPtr, *argvPtr @*/
1536 {
1537  size_t nb = (argc + 1) * sizeof(*argv);
1538  char ** argv2;
1539  char * dst;
1540  int i;
1541 
1542  if (argc <= 0 || argv == NULL) /* XXX can't happen */
1543  return POPT_ERROR_NOARG;
1544  for (i = 0; i < argc; i++) {
1545  if (argv[i] == NULL)
1546  return POPT_ERROR_NOARG;
1547  nb += strlen(argv[i]) + 1;
1548  }
1549 
1550  dst = (char *) xmalloc(nb);
1551  if (dst == NULL) /* XXX can't happen */
1552  return POPT_ERROR_MALLOC;
1553  argv2 = (char **) dst;
1554  dst += (argc + 1) * sizeof(*argv);
1555 
1556  for (i = 0; i < argc; i++) {
1557  argv2[i] = dst;
1558  dst += strlen(strcpy(dst, argv[i])) + 1;
1559  }
1560  argv2[argc] = NULL;
1561 
1562  if (argvPtr) {
1563  *argvPtr = argv2;
1564  } else {
1565  free(argv2);
1566  argv2 = NULL;
1567  }
1568  if (argcPtr)
1569  *argcPtr = argc;
1570  return 0;
1571 }
1572 
1573 static int XpoptParseArgvString(const char * s, int * argcPtr, char *** argvPtr)
1574  /*@modifies *argcPtr, *argvPtr @*/
1575 {
1576  const char * src;
1577  char quote = '\0';
1578  int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
1579  char ** argv = (char **) xmalloc(sizeof(*argv) * argvAlloced);
1580  int argc = 0;
1581  size_t buflen = strlen(s) + 1;
1582  char * buf = (char *) memset(alloca(buflen), 0, buflen);
1583  int rc = POPT_ERROR_MALLOC;
1584 
1585  if (argv == NULL) return rc;
1586  argv[argc] = buf;
1587 
1588  for (src = s; *src != '\0'; src++) {
1589  if (quote == *src) {
1590  quote = '\0';
1591  } else if (quote != '\0') {
1592  if (*src == '\\') {
1593  src++;
1594  if (!*src) {
1595  rc = POPT_ERROR_BADQUOTE;
1596  goto exit;
1597  }
1598  if (*src != quote) *buf++ = '\\';
1599  }
1600  *buf++ = *src;
1601  } else if (isspace(*src)) {
1602  if (*argv[argc] != '\0') {
1603  buf++, argc++;
1604  if (argc == argvAlloced) {
1605  argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
1606  argv = (char **) realloc(argv, sizeof(*argv) * argvAlloced);
1607  if (argv == NULL) goto exit;
1608  }
1609  argv[argc] = buf;
1610  }
1611  } else switch (*src) {
1612  case '"':
1613  case '\'':
1614  quote = *src;
1615  /*@switchbreak@*/ break;
1616  case '\\':
1617  src++;
1618  if (!*src) {
1619  rc = POPT_ERROR_BADQUOTE;
1620  goto exit;
1621  }
1622  /*@fallthrough@*/
1623  default:
1624  *buf++ = *src;
1625  /*@switchbreak@*/ break;
1626  }
1627  }
1628 
1629  if (strlen(argv[argc])) {
1630  argc++, buf++;
1631  }
1632 
1633  rc = XpoptDupArgv(argc, argv, argcPtr, argvPtr);
1634 
1635 exit:
1636  if (argv) free(argv);
1637  return rc;
1638 }
1639 #endif /* !defined(DEBUG_MACROS) */
1640 
1648 #if defined(WITH_AUGEAS) || defined(WITH_FICL) || defined(WITH_GPSEE) || defined(WITH_JNIEMBED) || defined(WITH_PERLEMBED) || defined(WITH_PYTHONEMBED) || defined(WITH_RUBYEMBED) || defined(WITH_MRUBY_EMBED) || defined(WITH_SQLITE) || defined(WITH_SQUIRREL) || defined(WITH_TCL) || defined(WITH_SEMANAGE)
1649 static char _FIXME_embedded_interpreter_eval_returned_null[] =
1650  "FIXME: embedded interpreter eval returned null.";
1651 static char * parseEmbedded(const char * s, size_t nb, char *** avp)
1652  /*@*/
1653 {
1654  char * script = NULL;
1655  const char * se;
1656 
1657  /* XXX FIXME: args might have embedded : too. */
1658  for (se = s + 1; se < (s+nb); se++)
1659  switch (*se) {
1660  default: continue; /*@notreached@*/ break;
1661  case ':': goto bingo; /*@notreached@*/ break;
1662  }
1663 
1664 bingo:
1665  { size_t na = (size_t)(se-s-1);
1666  char * args = NULL;
1667  int ac;
1668  int rc;
1669 
1670  args = (char *) memcpy(xmalloc(na+1), s+1, na);
1671  args[na] = '\0';
1672 
1673  ac = 0;
1674  rc = XpoptParseArgvString(args, &ac, avp);
1675  args = _free(args);
1676  nb -= na;
1677  }
1678 
1679  nb -= (nb >= (sizeof("{:}")-1) ? (sizeof("{:}")-1) : nb);
1680  script = (char *) memcpy(xmalloc(nb+1), se+1, nb+1);
1681  script[nb] = '\0';
1682  return script;
1683 }
1684 #endif
1685 
1692 static int
1694  /*@globals rpmGlobalMacroContext,
1695  print_macro_trace, print_expand_trace, h_errno,
1696  fileSystem, internalState @*/
1697  /*@modifies mb, rpmGlobalMacroContext,
1698  print_macro_trace, print_expand_trace,
1699  fileSystem, internalState @*/
1700 {
1701  MacroEntry *mep;
1702  MacroEntry me;
1703  const char *s = mb->s, *se;
1704  const char *f, *fe;
1705  const char *g, *ge;
1706  size_t fn, gn;
1707  char *t = mb->t; /* save expansion pointer for printExpand */
1708  int c;
1709  int rc = 0;
1710  int negate;
1711  int stackarray;
1712  const char * lastc;
1713  int chkexist;
1714 
1715  if (++mb->depth > max_macro_depth) {
1717  _("Recursion depth(%d) greater than max(%d)\n"),
1718  mb->depth, max_macro_depth);
1719  mb->depth--;
1720  mb->expand_trace = 1;
1721  return 1;
1722  }
1723 
1724  while (rc == 0 && mb->nb > 0 && (c = (int)*s) != (int)'\0') {
1725  s++;
1726  /* Copy text until next macro */
1727  switch(c) {
1728  case '%':
1729  if (*s != '\0') { /* Ensure not end-of-string. */
1730  if (*s != '%')
1731  /*@switchbreak@*/ break;
1732  s++; /* skip first % in %% */
1733  }
1734  /*@fallthrough@*/
1735  default:
1736  SAVECHAR(mb, c);
1737  continue;
1738  /*@notreached@*/ /*@switchbreak@*/ break;
1739  }
1740 
1741  /* Expand next macro */
1742  f = fe = NULL;
1743  g = ge = NULL;
1744  if (mb->depth > 1) /* XXX full expansion for outermost level */
1745  t = mb->t; /* save expansion pointer for printExpand */
1746  stackarray = chkexist = negate = 0;
1747  lastc = NULL;
1748  switch ((c = (int) *s)) {
1749  default: /* %name substitution */
1750  while (*s != '\0' && strchr("!?@", *s) != NULL) {
1751  switch(*s++) {
1752  case '@':
1753  stackarray = ((stackarray + 1) % 2);
1754  /*@switchbreak@*/ break;
1755  case '!':
1756  negate = ((negate + 1) % 2);
1757  /*@switchbreak@*/ break;
1758  case '?':
1759  chkexist++;
1760  /*@switchbreak@*/ break;
1761  }
1762  }
1763  f = se = s;
1764  if (*se == '-')
1765  se++;
1766  while((c = (int) *se) && (xisalnum(c) || c == (int) '_'))
1767  se++;
1768  /* Recognize non-alnum macros too */
1769  switch (*se) {
1770  case '*':
1771  se++;
1772  if (*se == '*') se++;
1773  /*@innerbreak@*/ break;
1774  case '#':
1775  se++;
1776  /*@innerbreak@*/ break;
1777  default:
1778  /*@innerbreak@*/ break;
1779  }
1780  fe = se;
1781  /* For "%name " macros ... */
1782 /*@-globs@*/
1783  if ((c = (int) *fe) && isblank(c))
1784  if ((lastc = strchr(fe,'\n')) == NULL)
1785  lastc = strchr(fe, '\0');
1786 /*@=globs@*/
1787  /*@switchbreak@*/ break;
1788  case '(': /* %(...) shell escape */
1789  if ((se = matchchar(s, (char)c, ')')) == NULL) {
1791  _("Unterminated %c: %s\n"), (char)c, s);
1792  rc = 1;
1793  continue;
1794  }
1795  if (mb->macro_trace)
1796  printMacro(mb, s, se+1);
1797 
1798  s++; /* skip ( */
1799  rc = doShellEscape(mb, s, (se - s));
1800  se++; /* skip ) */
1801 
1802  s = se;
1803  continue;
1804  /*@notreached@*/ /*@switchbreak@*/ break;
1805  case '{': /* %{...}/%{...:...} substitution */
1806  if ((se = matchchar(s, (char)c, '}')) == NULL) {
1808  _("Unterminated %c: %s\n"), (char)c, s);
1809  rc = 1;
1810  continue;
1811  }
1812  f = s+1;/* skip { */
1813  se++; /* skip } */
1814  while (strchr("!?@", *f) != NULL) {
1815  switch(*f++) {
1816  case '@':
1817  stackarray = ((stackarray + 1) % 2);
1818  /*@switchbreak@*/ break;
1819  case '!':
1820  negate = ((negate + 1) % 2);
1821  /*@switchbreak@*/ break;
1822  case '?':
1823  chkexist++;
1824  /*@switchbreak@*/ break;
1825  }
1826  }
1827  /* Find end-of-expansion, handle %{foo:bar} expansions. */
1828  for (fe = f; (c = (int) *fe) && !strchr(" :}", c);)
1829  fe++;
1830  switch (c) {
1831  case ':':
1832  g = fe + 1;
1833  ge = se - 1;
1834  /*@innerbreak@*/ break;
1835  case ' ':
1836  lastc = se-1;
1837  /*@innerbreak@*/ break;
1838  default:
1839  /*@innerbreak@*/ break;
1840  }
1841  /*@switchbreak@*/ break;
1842  }
1843 
1844  /* XXX Everything below expects fe > f */
1845  fn = (fe - f);
1846  gn = (ge - g);
1847  if ((fe - f) <= 0) {
1848 /* XXX Process % in unknown context */
1849  c = (int) '%'; /* XXX only need to save % */
1850  SAVECHAR(mb, c);
1851 #if 0
1853  _("A %% is followed by an unparseable macro\n"));
1854 #endif
1855  s = se;
1856  continue;
1857  }
1858 
1859  if (mb->macro_trace)
1860  printMacro(mb, s, se);
1861 
1862  /* Expand builtin macros */
1863  if (STREQ("load", f, fn)) {
1864  if (g != NULL) {
1865  char * mfn = strncpy((char *) alloca(gn + 1), g, gn);
1866  int xx;
1867  mfn[gn] = '\0';
1868  xx = rpmLoadMacroFile(NULL, mfn, _max_load_depth);
1869  /* Print failure iff %{load:...} or %{!?load:...} */
1870  if (xx != 0 && chkexist == negate)
1871  rpmlog(RPMLOG_ERR, _("%s: load macros failed\n"), mfn);
1872  }
1873  s = se;
1874  continue;
1875  }
1876  if (STREQ("global", f, fn)) {
1877  s = doDefine(mb, se, RMIL_GLOBAL, 1);
1878  continue;
1879  }
1880  if (STREQ("define", f, fn)) {
1881  s = doDefine(mb, se, mb->depth, 0);
1882  continue;
1883  }
1884  if (STREQ("undefine", f, fn)) {
1885  s = doUndefine(mb->mc, se);
1886  continue;
1887  }
1888  if (STREQ("unglobal", f, fn)) {
1889  s = doUnglobal(mb->mc, se);
1890  continue;
1891  }
1892 
1893  if (STREQ("echo", f, fn) ||
1894  STREQ("warn", f, fn) ||
1895  STREQ("error", f, fn)) {
1896  int waserror = 0;
1897  if (STREQ("error", f, fn))
1898  waserror = 1, rc = 1;
1899  if (g != NULL && g < ge)
1900  doOutput(mb, waserror, g, gn);
1901  else
1902  doOutput(mb, waserror, f, fn);
1903  s = se;
1904  continue;
1905  }
1906 
1907  if (STREQ("trace", f, fn)) {
1908  /* XXX TODO restore expand_trace/macro_trace to 0 on return */
1909  mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
1910  if (mb->depth == 1) {
1913  }
1914  s = se;
1915  continue;
1916  }
1917 
1918  if (STREQ("dump", f, fn)) {
1919  rpmDumpMacroTable(mb->mc, NULL);
1920  while (iseol(*se))
1921  se++;
1922  s = se;
1923  continue;
1924  }
1925 
1926 #ifdef WITH_LUA
1927  if (STREQ("lua", f, fn)) {
1928  rpmlua lua = rpmluaGetGlobalState();
1929  rpmlua olua = (rpmlua) memcpy(alloca(sizeof(*olua)), lua, sizeof(*olua));
1930  char *scriptbuf = (char *)xmalloc(gn);
1931  const char *printbuf;
1932 
1933  /* Reset the stateful output buffer before recursing down. */
1934  lua->storeprint = 1;
1935  lua->printbuf = NULL;
1936  lua->printbufsize = 0;
1937  lua->printbufused = 0;
1938 
1939  if (g != NULL && gn > 0)
1940  memcpy(scriptbuf, g, gn);
1941  scriptbuf[gn] = '\0';
1942  if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
1943  rc = 1;
1944  printbuf = rpmluaGetPrintBuffer(lua);
1945  if (printbuf) {
1946  size_t len = strlen(printbuf);
1947  if (len > mb->nb)
1948  len = mb->nb;
1949  memcpy(mb->t, printbuf, len);
1950  mb->t += len;
1951  mb->nb -= len;
1952  }
1953 
1954  /* Restore the stateful output buffer after recursion. */
1955  lua->storeprint = olua->storeprint;
1956  lua->printbuf = olua->printbuf;
1957  lua->printbufsize = olua->printbufsize;
1958  lua->printbufused = olua->printbufused;
1959 
1960  free(scriptbuf);
1961  s = se;
1962  continue;
1963  }
1964 #endif
1965 
1966 #ifdef WITH_AUGEAS
1967  if (STREQ("augeas", f, fn)) {
1968  /* XXX change rpmaugNew() to common embedded interpreter API */
1969 #ifdef NOTYET
1970  char ** av = NULL;
1971  char * script = parseEmbedded(s, (size_t)(se-s), &av);
1972 #else
1973  char * script = strndup(g, (size_t)(se-g-1));
1974 #endif
1975  rpmaug aug = (_globalI ? NULL
1977  const char * result = NULL;
1978 
1979  if (rpmaugRun(aug, script, &result) != RPMRC_OK)
1980  rc = 1;
1981  else {
1982  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
1983  if (result != NULL && *result != '\0') {
1984  size_t len = strlen(result);
1985  if (len > mb->nb)
1986  len = mb->nb;
1987  memcpy(mb->t, result, len);
1988  mb->t += len;
1989  mb->nb -= len;
1990  }
1991  }
1992  aug = rpmaugFree(aug);
1993 #ifdef NOTYET
1994  av = _free(av);
1995 #endif
1996  script = _free(script);
1997  s = se;
1998  continue;
1999  }
2000 #endif
2001 
2002 #ifdef WITH_FICL
2003  if (STREQ("ficl", f, fn)) {
2004  char ** av = NULL;
2005  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2006  rpmficl ficl = rpmficlNew(av, _globalI);
2007  const char * result = NULL;
2008 
2009  if (rpmficlRun(ficl, script, &result) != RPMRC_OK)
2010  rc = 1;
2011  else {
2012  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2013  if (result != NULL && *result != '\0') {
2014  size_t len = strlen(result);
2015  if (len > mb->nb)
2016  len = mb->nb;
2017  memcpy(mb->t, result, len);
2018  mb->t += len;
2019  mb->nb -= len;
2020  }
2021  }
2022  ficl = rpmficlFree(ficl);
2023  av = _free(av);
2024  script = _free(script);
2025  s = se;
2026  continue;
2027  }
2028 #endif
2029 
2030 #ifdef WITH_LIBGIT2
2031  if (STREQ("git", f, fn)) {
2032  char ** av = NULL;
2033  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2034  rpmgit git = rpmgitNew(av, _globalI, NULL);
2035  const char * result = NULL;
2036 
2037  if (rpmgitRun(git, script, &result) != RPMRC_OK)
2038  rc = 1;
2039  else {
2040  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2041  if (result != NULL && *result != '\0') {
2042  size_t len = strlen(result);
2043  if (len > mb->nb)
2044  len = mb->nb;
2045  memcpy(mb->t, result, len);
2046  mb->t += len;
2047  mb->nb -= len;
2048  }
2049  }
2050  git = rpmgitFree(git);
2051  av = _free(av);
2052  script = _free(script);
2053  s = se;
2054  continue;
2055  }
2056 #endif
2057 
2058 #ifdef WITH_GPSEE
2059  if (STREQ("js", f, fn)) {
2060  char ** av = NULL;
2061  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2062  rpmjs js = rpmjsNew(av, _globalI);
2063  const char * result = NULL;
2064 
2065  if (rpmjsRun(js, script, &result) != RPMRC_OK)
2066  rc = 1;
2067  else {
2068  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2069  if (result != NULL && *result != '\0') {
2070  size_t len = strlen(result);
2071  if (len > mb->nb)
2072  len = mb->nb;
2073  memcpy(mb->t, result, len);
2074  mb->t += len;
2075  mb->nb -= len;
2076  }
2077  }
2078  js = rpmjsFree(js);
2079  av = _free(av);
2080  script = _free(script);
2081  s = se;
2082  continue;
2083  }
2084 #endif
2085 
2086 #ifdef WITH_JNIEMBED
2087  if (STREQ("jni", f, fn) || STREQ("java", f, fn)) {
2088  char ** av = NULL;
2089  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2090  rpmjni jni = rpmjniNew(av, _globalI);
2091  const char * result = NULL;
2092 
2093  if (rpmjniRun(jni, script, &result) != RPMRC_OK)
2094  rc = 1;
2095  else {
2096  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2097  if (result != NULL && *result != '\0') {
2098  size_t len = strlen(result);
2099  if (len > mb->nb)
2100  len = mb->nb;
2101  memcpy(mb->t, result, len);
2102  mb->t += len;
2103  mb->nb -= len;
2104  }
2105  }
2106  jni = rpmjniFree(jni);
2107  av = _free(av);
2108  script = _free(script);
2109  s = se;
2110  continue;
2111  }
2112 #endif
2113 
2114 #ifdef WITH_MRBEMBED
2115  if (STREQ("mrb", f, fn) || STREQ("mruby", f, fn)) {
2116  char ** av = NULL;
2117  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2118  rpmmrb mrb = rpmmrbNew(av, _globalI);
2119  const char * result = NULL;
2120 
2121  if (rpmmrbRun(mrb, script, &result) != RPMRC_OK)
2122  rc = 1;
2123  else {
2124  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2125  if (result != NULL && *result != '\0') {
2126  size_t len = strlen(result);
2127  if (len > mb->nb)
2128  len = mb->nb;
2129  memcpy(mb->t, result, len);
2130  mb->t += len;
2131  mb->nb -= len;
2132  }
2133  }
2134  mrb = rpmmrbFree(mrb);
2135  av = _free(av);
2136  script = _free(script);
2137  s = se;
2138  continue;
2139  }
2140 #endif
2141 
2142 #ifdef WITH_NIX
2143  if (STREQ("nix", f, fn)) {
2144  char ** av = NULL;
2145  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2146  int (*_vec) (rpmnix nix) = rpmnixEcho;
2147  uint32_t _flags = RPMNIX_FLAGS_NONE;
2148  rpmnix nix;
2149  const char * result = NULL;
2150  int xx;
2151 
2152  if (av == NULL || av[0] == NULL || av[1] == NULL
2153  || !strcmp(av[0], "echo"))
2154  {
2155  _vec = rpmnixEcho;
2156  } else
2157  if (!strcmp(av[1], "build")) {
2158  _vec = rpmnixBuild;
2159  _flags = RPMNIX_FLAGS_NOOUTLINK;
2160  } else
2161  if (!strcmp(av[1], "channel")) {
2162  _vec = rpmnixChannel;
2163  } else
2164  if (!strcmp(av[1], "collect-garbage")) {
2165  _vec = rpmnixCollectGarbage;
2166  } else
2167  if (!strcmp(av[1], "copy-closure")) {
2168  _vec = rpmnixCopyClosure;
2169  } else
2170  if (!strcmp(av[1], "env")) {
2171  _vec = rpmnixEnv;
2172  } else
2173  if (!strcmp(av[1], "hash")) {
2174  _vec = rpmnixHash;
2175  } else
2176  if (!strcmp(av[1], "install-package")) {
2177  _vec = rpmnixInstallPackage;
2178  _flags = RPMNIX_FLAGS_INTERACTIVE;
2179  } else
2180  if (!strcmp(av[1], "instantiate")) {
2181  _vec = rpmnixInstantiate;
2182  } else
2183  if (!strcmp(av[1], "prefetch-url")) {
2184  _vec = rpmnixPrefetchURL;
2185  } else
2186  if (!strcmp(av[1], "push")) {
2187  _vec = rpmnixPush;
2188  } else
2189  if (!strcmp(av[1], "pull")) {
2190  _vec = rpmnixPull;
2191  } else
2192  if (!strcmp(av[1], "store")) {
2193  _vec = rpmnixStore;
2194  } else
2195  if (!strcmp(av[1], "worker")) {
2196  _vec = rpmnixWorker;
2197  } else
2198 assert(0);
2199 
2200  nix = rpmnixNew(av, _flags, NULL);
2201 
2202 #ifdef NOTYET
2203  if (rpmnixRun(nix, script, &result) != RPMRC_OK)
2204  rc = 1;
2205  else {
2206  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2207  if (result != NULL && *result != '\0') {
2208  size_t len = strlen(result);
2209  if (len > mb->nb)
2210  len = mb->nb;
2211  memcpy(mb->t, result, len);
2212  mb->t += len;
2213  mb->nb -= len;
2214  }
2215  }
2216 #else
2217  xx = (*_vec) (nix);
2218  result = xstrdup("");
2219 #endif /* NOTYET */
2220 
2221  nix = rpmnixFree(nix);
2222  av = _free(av);
2223  script = _free(script);
2224  s = se;
2225  continue;
2226  }
2227 #endif
2228 
2229 #ifdef WITH_PERLEMBED
2230  if (STREQ("perl", f, fn)) {
2231  char ** av = NULL;
2232  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2233  rpmperl perl = rpmperlNew(av, _globalI);
2234  const char * result = NULL;
2235 
2236  if (rpmperlRun(perl, script, &result) != RPMRC_OK)
2237  rc = 1;
2238  else {
2239  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2240  if (result != NULL && *result != '\0') {
2241  size_t len = strlen(result);
2242  if (len > mb->nb)
2243  len = mb->nb;
2244  memcpy(mb->t, result, len);
2245  mb->t += len;
2246  mb->nb -= len;
2247  }
2248  }
2249  perl = rpmperlFree(perl);
2250  av = _free(av);
2251  script = _free(script);
2252  s = se;
2253  continue;
2254  }
2255 #endif
2256 
2257 #ifdef WITH_PYTHONEMBED
2258  if (STREQ("python", f, fn)) {
2259  char ** av = NULL;
2260  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2261  rpmpython python = rpmpythonNew(av, _globalI);
2262  const char * result = NULL;
2263 
2264  if (rpmpythonRun(python, script, &result) != RPMRC_OK)
2265  rc = 1;
2266  else {
2267  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2268  if (result != NULL && *result != '\0') {
2269  size_t len = strlen(result);
2270  if (len > mb->nb)
2271  len = mb->nb;
2272  memcpy(mb->t, result, len);
2273  mb->t += len;
2274  mb->nb -= len;
2275  }
2276  }
2277  python = rpmpythonFree(python);
2278  av = _free(av);
2279  script = _free(script);
2280  s = se;
2281  continue;
2282  }
2283 #endif
2284 
2285 #ifdef WITH_RUBYEMBED
2286  if (STREQ("ruby", f, fn)) {
2287  char ** av = NULL;
2288  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2289  rpmruby ruby = rpmrubyNew(av, _globalI);
2290  const char * result = NULL;
2291 
2292  if (rpmrubyRun(ruby, script, &result) != RPMRC_OK)
2293  rc = 1;
2294  else {
2295  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2296  if (result != NULL && *result != '\0') {
2297  size_t len = strlen(result);
2298  if (len > mb->nb)
2299  len = mb->nb;
2300  memcpy(mb->t, result, len);
2301  mb->t += len;
2302  mb->nb -= len;
2303  }
2304  }
2305  ruby = rpmrubyFree(ruby);
2306  av = _free(av);
2307  script = _free(script);
2308  s = se;
2309  continue;
2310  }
2311 #endif
2312 
2313 #ifdef WITH_SEMANAGE
2314  if (STREQ("spook", f, fn)) {
2315  /* XXX change rpmsmNew() to common embedded interpreter API */
2316 #ifdef NOTYET
2317  char ** av = NULL;
2318  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2319 #else
2320  /* XXX use xstrndup (which never returns NULL) instead. */
2321  char * script = strndup(g, (size_t)(se-g-1));
2322  char * av[2];
2323  /* XXX FIXME */
2324  static const char * _rpmsmStore = "targeted";
2325  static unsigned int _rpmsmFlags = 0;
2326 #endif
2327  rpmsm sm = (_globalI ? NULL
2328  : rpmsmNew(_rpmsmStore, _rpmsmFlags));
2329  const char * result = NULL;
2330 
2331  /* XXX HACK: use an argv for now. */
2332  av[0] = script;
2333  av[1] = NULL;
2334  if (rpmsmRun(sm, av, &result) != RPMRC_OK)
2335  rc = 1;
2336  else {
2337  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2338  if (result != NULL && *result != '\0') {
2339  size_t len = strlen(result);
2340  if (len > mb->nb)
2341  len = mb->nb;
2342  memcpy(mb->t, result, len);
2343  mb->t += len;
2344  mb->nb -= len;
2345  }
2346  }
2347  sm = rpmsmFree(sm);
2348 #ifdef NOTYET
2349  av = _free(av);
2350 #endif
2351  script = _free(script);
2352  s = se;
2353  continue;
2354  }
2355 #endif
2356 
2357 #ifdef WITH_SQLITE
2358  if (STREQ("sql", f, fn)) {
2359  char ** av = NULL;
2360  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2361  rpmsql sql = rpmsqlNew(av, _globalI);
2362  const char * result = NULL;
2363 
2364  if (rpmsqlRun(sql, script, &result) != RPMRC_OK)
2365  rc = 1;
2366  else {
2367  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2368  if (result != NULL && *result != '\0') {
2369  size_t len = strlen(result);
2370  if (len > mb->nb)
2371  len = mb->nb;
2372  memcpy(mb->t, result, len);
2373  mb->t += len;
2374  mb->nb -= len;
2375  }
2376  }
2377  sql = rpmsqlFree(sql);
2378  av = _free(av);
2379  script = _free(script);
2380  s = se;
2381  continue;
2382  }
2383 #endif
2384 
2385 #ifdef WITH_SQUIRREL
2386  if (STREQ("squirrel", f, fn)) {
2387  char ** av = NULL;
2388  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2389  rpmsquirrel squirrel = rpmsquirrelNew(av, _globalI);
2390  const char * result = NULL;
2391 
2392  if (rpmsquirrelRun(squirrel, script, &result) != RPMRC_OK)
2393  rc = 1;
2394  else {
2395  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2396  if (result != NULL && *result != '\0') {
2397  size_t len = strlen(result);
2398  if (len > mb->nb)
2399  len = mb->nb;
2400  memcpy(mb->t, result, len);
2401  mb->t += len;
2402  mb->nb -= len;
2403  }
2404  }
2405  squirrel = rpmsquirrelFree(squirrel);
2406  av = _free(av);
2407  script = _free(script);
2408  s = se;
2409  continue;
2410  }
2411 #endif
2412 
2413 #ifdef WITH_TCL
2414  if (STREQ("tcl", f, fn)) {
2415  char ** av = NULL;
2416  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2417  rpmtcl tcl = rpmtclNew(av, _globalI);
2418  const char * result = NULL;
2419 
2420  if (rpmtclRun(tcl, script, &result) != RPMRC_OK)
2421  rc = 1;
2422  else if (result != NULL && *result != '\0') {
2423  size_t len = strlen(result);
2424  if (len > mb->nb)
2425  len = mb->nb;
2426  memcpy(mb->t, result, len);
2427  mb->t += len;
2428  mb->nb -= len;
2429  }
2430  tcl = rpmtclFree(tcl);
2431  av = _free(av);
2432  script = _free(script);
2433  s = se;
2434  continue;
2435  }
2436 #endif
2437 
2438  /* Rewrite "%patchNN ..." as "%patch -P NN ..." and expand. */
2439  if (lastc && fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) {
2440  /*@-internalglobs@*/ /* FIX: verbose may be set */
2441  doFoo(mb, negate, f, (lastc - f), NULL, 0);
2442  /*@=internalglobs@*/
2443  s = lastc;
2444  continue;
2445  }
2446 
2447  /* XXX necessary but clunky */
2448  if (STREQ("basename", f, fn) ||
2449  STREQ("dirname", f, fn) ||
2450  STREQ("realpath", f, fn) ||
2451  STREQ("getenv", f, fn) ||
2452  STREQ("shrink", f, fn) ||
2453  STREQ("suffix", f, fn) ||
2454  STREQ("expand", f, fn) ||
2455  STREQ("verbose", f, fn) ||
2456  STREQ("uncompress", f, fn) ||
2457  STREQ("mkstemp", f, fn) ||
2458  STREQ("mkdtemp", f, fn) ||
2459  STREQ("uuid", f, fn) ||
2460  STREQ("url2path", f, fn) ||
2461  STREQ("u2p", f, fn) ||
2462  STREQ("S", f, fn) ||
2463  STREQ("P", f, fn) ||
2464  STREQ("F", f, fn)) {
2465  /*@-internalglobs@*/ /* FIX: verbose may be set */
2466  doFoo(mb, negate, f, fn, g, gn);
2467  /*@=internalglobs@*/
2468  s = se;
2469  continue;
2470  }
2471 
2472  /* Expand defined macros */
2473  mep = findEntry(mb->mc, f, fn);
2474  me = (mep ? *mep : NULL);
2475 
2476  /* XXX Special processing for flags */
2477  if (*f == '-') {
2478  if (me)
2479  me->used++; /* Mark macro as used */
2480  if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */
2481  (me != NULL && negate)) { /* With -f, skip %{!-f...} */
2482  s = se;
2483  continue;
2484  }
2485 
2486  if (g && g < ge) { /* Expand X in %{-f:X} */
2487  rc = expandT(mb, g, gn);
2488  } else
2489  if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
2490  rc = expandT(mb, me->body, strlen(me->body));
2491  }
2492  s = se;
2493  continue;
2494  }
2495 
2496  /* XXX Special processing for macro existence */
2497  if (chkexist) {
2498  if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */
2499  (me != NULL && negate)) { /* With -f, skip %{!?f...} */
2500  s = se;
2501  continue;
2502  }
2503  if (g && g < ge) { /* Expand X in %{?f:X} */
2504  rc = expandT(mb, g, gn);
2505  } else
2506  if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
2507  rc = expandT(mb, me->body, strlen(me->body));
2508  }
2509  s = se;
2510  continue;
2511  }
2512 
2513  if (me == NULL) { /* leave unknown %... as is */
2514 #if !defined(RPM_VENDOR_WINDRIVER_DEBUG) /* XXX usually disabled */
2515 #if DEAD
2516  /* XXX hack to skip over empty arg list */
2517  if (fn == 1 && *f == '*') {
2518  s = se;
2519  continue;
2520  }
2521 #endif
2522  /* XXX hack to permit non-overloaded %foo to be passed */
2523  c = (int) '%'; /* XXX only need to save % */
2524  SAVECHAR(mb, c);
2525 #else
2526  if (!strncmp(f, "if", fn) ||
2527  !strncmp(f, "else", fn) ||
2528  !strncmp(f, "endif", fn)) {
2529  c = '%'; /* XXX only need to save % */
2530  SAVECHAR(mb, c);
2531  } else {
2533  _("Macro %%%.*s not found, skipping\n"), fn, f);
2534  s = se;
2535  }
2536 #endif
2537  continue;
2538  }
2539 
2540  /* XXX Special processing to create a tuple from stack'd values. */
2541  if (stackarray) {
2542  if (!(g && g < ge)) {
2543  g = "\n";
2544  gn = strlen(g);
2545  }
2546  rc = expandFIFO(mb, me, g, gn);
2547  s = se;
2548  continue;
2549  }
2550 
2551  /* Setup args for "%name " macros with opts */
2552  if (me && me->opts != NULL) {
2553  if (lastc != NULL) {
2554  se = grabArgs(mb, me, fe, lastc);
2555  } else {
2556  addMacro(mb->mc, "**", NULL, "", mb->depth);
2557  addMacro(mb->mc, "*", NULL, "", mb->depth);
2558  addMacro(mb->mc, "#", NULL, "0", mb->depth);
2559  addMacro(mb->mc, "0", NULL, me->name, mb->depth);
2560  }
2561  }
2562 
2563  /* Recursively expand body of macro */
2564  if (me->body && *me->body) {
2565  mb->s = me->body;
2566  rc = expandMacro(mb);
2567  if (rc == 0)
2568  me->used++; /* Mark macro as used */
2569  }
2570 
2571  /* Free args for "%name " macros with opts */
2572  if (me->opts != NULL)
2573  freeArgs(mb);
2574 
2575  s = se;
2576  }
2577 
2578  *mb->t = '\0';
2579  mb->s = s;
2580  mb->depth--;
2581  if (rc != 0 || mb->expand_trace)
2582  printExpansion(mb, t, mb->t);
2583  return rc;
2584 }
2585 
2586 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \
2587  !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */
2588 int rpmSecuritySaneFile(const char *filename)
2589 {
2590  struct stat sb;
2591  uid_t uid;
2592 
2593  if (stat(filename, &sb) == -1)
2594  return 1;
2595  uid = getuid();
2596  if (sb.st_uid != uid)
2597  return 0;
2598  if (!S_ISREG(sb.st_mode))
2599  return 0;
2600  if (sb.st_mode & (S_IWGRP|S_IWOTH))
2601  return 0;
2602  return 1;
2603 }
2604 #endif
2605 
2606 #if !defined(DEBUG_MACROS)
2607 /* =============================================================== */
2608 /*@unchecked@*/
2609 static int _debug = 0;
2610 
2611 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
2612 {
2613  int ac = 0;
2614  char ** av = NULL;
2615  int argc = 0;
2616  const char ** argv = NULL;
2617  char * globRoot = NULL;
2618 #ifdef ENABLE_NLS
2619  const char * old_collate = NULL;
2620  const char * old_ctype = NULL;
2621  const char * t;
2622 #endif
2623  size_t maxb, nb;
2624  size_t i;
2625  int j;
2626  int rc;
2627 
2628  rc = XpoptParseArgvString(patterns, &ac, &av);
2629  if (rc)
2630  return rc;
2631 #ifdef ENABLE_NLS
2632  t = setlocale(LC_COLLATE, NULL);
2633  if (t)
2634  old_collate = xstrdup(t);
2635  t = setlocale(LC_CTYPE, NULL);
2636  if (t)
2637  old_ctype = xstrdup(t);
2638  (void) setlocale(LC_COLLATE, "C");
2639  (void) setlocale(LC_CTYPE, "C");
2640 #endif
2641 
2642  if (av != NULL)
2643  for (j = 0; j < ac; j++) {
2644  const char * globURL;
2645  const char * path;
2646  int ut = urlPath(av[j], &path);
2647  glob_t gl;
2648 
2649  if (!Glob_pattern_p(av[j], 0) && strchr(path, '~') == NULL) {
2650  argv = (const char **) xrealloc(argv, (argc+2) * sizeof(*argv));
2651  argv[argc] = xstrdup(av[j]);
2652 if (_debug)
2653 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]);
2654  argc++;
2655  continue;
2656  }
2657 
2658  gl.gl_pathc = 0;
2659  gl.gl_pathv = NULL;
2660  rc = Glob(av[j], GLOB_TILDE, Glob_error, &gl);
2661  if (rc)
2662  goto exit;
2663 
2664  /* XXX Prepend the URL leader for globs that have stripped it off */
2665  maxb = 0;
2666  for (i = 0; i < gl.gl_pathc; i++) {
2667  if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
2668  maxb = nb;
2669  }
2670 
2671  nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0);
2672  maxb += nb;
2673  maxb += 1;
2674  globURL = globRoot = (char *) xmalloc(maxb);
2675 
2676  switch (ut) {
2677  case URL_IS_PATH:
2678  case URL_IS_DASH:
2679  strncpy(globRoot, av[j], nb);
2680  /*@switchbreak@*/ break;
2681  case URL_IS_HKP:
2682  case URL_IS_FTP:
2683  case URL_IS_HTTP:
2684  case URL_IS_HTTPS:
2685  case URL_IS_MONGO: /* XXX FIXME */
2686  case URL_IS_UNKNOWN:
2687  default:
2688  /*@switchbreak@*/ break;
2689  }
2690  globRoot += nb;
2691  *globRoot = '\0';
2692 if (_debug)
2693 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
2694 
2695  argv = (const char **) xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
2696 
2697  if (argv != NULL)
2698  for (i = 0; i < gl.gl_pathc; i++) {
2699  const char * globFile = &(gl.gl_pathv[i][0]);
2700  if (globRoot > globURL && globRoot[-1] == '/')
2701  while (*globFile == '/') globFile++;
2702  strcpy(globRoot, globFile);
2703 if (_debug)
2704 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
2705  argv[argc++] = xstrdup(globURL);
2706  }
2707  /*@-immediatetrans@*/
2708  Globfree(&gl);
2709  /*@=immediatetrans@*/
2710  globURL = _free(globURL);
2711  }
2712 
2713  if (argv != NULL && argc > 0) {
2714  argv[argc] = NULL;
2715  if (argvPtr)
2716  *argvPtr = argv;
2717  if (argcPtr)
2718  *argcPtr = argc;
2719  rc = 0;
2720  } else
2721  rc = 1;
2722 
2723 
2724 exit:
2725 #ifdef ENABLE_NLS
2726  if (old_collate) {
2727  (void) setlocale(LC_COLLATE, old_collate);
2728  old_collate = _free(old_collate);
2729  }
2730  if (old_ctype) {
2731  (void) setlocale(LC_CTYPE, old_ctype);
2732  old_ctype = _free(old_ctype);
2733  }
2734 #endif
2735  av = _free(av);
2736  if (rc || argvPtr == NULL) {
2737 /*@-dependenttrans -unqualifiedtrans@*/
2738  if (argv != NULL)
2739  for (j = 0; j < argc; j++)
2740  argv[j] = _free(argv[j]);
2741  argv = _free(argv);
2742 /*@=dependenttrans =unqualifiedtrans@*/
2743  }
2744  return rc;
2745 }
2746 #endif /* !defined(DEBUG_MACROS) */
2747 
2748 /* =============================================================== */
2749 
2750 int
2751 expandMacros(void * spec, MacroContext mc, char * sbuf, size_t slen)
2752 {
2753  MacroBuf mb = (MacroBuf) alloca(sizeof(*mb));
2754  char *tbuf;
2755  int rc;
2756 
2757  if (sbuf == NULL || slen == 0)
2758  return 0;
2759  if (mc == NULL) mc = rpmGlobalMacroContext;
2760 
2761  tbuf = (char *) alloca(slen + 1);
2762  tbuf[0] = '\0';
2763 
2764  mb->s = sbuf;
2765  mb->t = tbuf;
2766  mb->nb = slen;
2767  mb->depth = 0;
2770 
2771  mb->spec = spec; /* (future) %file expansion info */
2772  mb->mc = mc;
2773 
2774  rc = expandMacro(mb);
2775 
2776  tbuf[slen] = '\0';
2777  if (mb->nb == 0)
2778  rpmlog(RPMLOG_ERR, _("Macro expansion too big for target buffer\n"));
2779  else
2780  strncpy(sbuf, tbuf, (slen - mb->nb + 1));
2781 
2782  return rc;
2783 }
2784 
2785 void
2787  const char * n, const char * o, const char * b, int level)
2788 {
2789  MacroEntry * mep;
2790  const char * name = n;
2791 
2792  if (*name == '.') /* XXX readonly macros */
2793  name++;
2794  if (*name == '.') /* XXX readonly macros */
2795  name++;
2796 
2797  if (mc == NULL) mc = rpmGlobalMacroContext;
2798 
2799  /* If new name, expand macro table */
2800  if ((mep = findEntry(mc, name, 0)) == NULL) {
2801  if (mc->firstFree == mc->macrosAllocated)
2802  expandMacroTable(mc);
2803  if (mc->macroTable != NULL)
2804  mep = mc->macroTable + mc->firstFree++;
2805  }
2806 
2807  if (mep != NULL) {
2808  /* XXX permit "..foo" to be pushed over ".foo" */
2809  if (*mep && (*mep)->flags && !(n[0] == '.' && n[1] == '.')) {
2810  /* XXX avoid error message for %buildroot */
2811  if (strcmp((*mep)->name, "buildroot"))
2812  rpmlog(RPMLOG_ERR, _("Macro '%s' is readonly and cannot be changed.\n"), n);
2813  return;
2814  }
2815  /* Push macro over previous definition */
2816  pushMacro(mep, n, o, b, level);
2817 
2818  /* If new name, sort macro table */
2819  if ((*mep)->prev == NULL)
2820  sortMacroTable(mc);
2821  }
2822 }
2823 
2824 void
2825 delMacro(MacroContext mc, const char * n)
2826 {
2827  MacroEntry * mep;
2828 
2829  if (mc == NULL) mc = rpmGlobalMacroContext;
2830  /* If name exists, pop entry */
2831  if ((mep = findEntry(mc, n, 0)) != NULL) {
2832  popMacro(mep);
2833  /* If deleted name, sort macro table */
2834  if (!(mep && *mep))
2835  sortMacroTable(mc);
2836  }
2837 }
2838 
2839 void
2840 delMacroAll(MacroContext mc, const char * n)
2841 {
2842  MacroEntry * mep;
2843 
2844  if (mc == NULL) mc = rpmGlobalMacroContext;
2845  /* If name exists, pop entry */
2846  while ((mep = findEntry(mc, n, 0)) != NULL) {
2847  delMacro(mc, n);
2848  }
2849 }
2850 
2851 /*@-mustmod@*/ /* LCL: mc is modified through mb->mc, mb is abstract */
2852 int
2853 rpmDefineMacro(MacroContext mc, const char * macro, int level)
2854 {
2855  MacroBuf mb = (MacroBuf) alloca(sizeof(*mb));
2856 
2857  memset(mb, 0, sizeof(*mb));
2858  /* XXX just enough to get by */
2859  mb->mc = (mc ? mc : rpmGlobalMacroContext);
2860  (void) doDefine(mb, macro, level, 0);
2861  return 0;
2862 }
2863 /*@=mustmod@*/
2864 
2865 /*@-mustmod@*/ /* LCL: mc is modified through mb->mc, mb is abstract */
2866 int
2867 rpmUndefineMacro(MacroContext mc, const char * macro)
2868 {
2869  (void) doUndefine(mc ? mc : rpmGlobalMacroContext, macro);
2870  return 0;
2871 }
2872 /*@=mustmod@*/
2873 
2874 void
2876 {
2877 
2878  if (mc == NULL || mc == rpmGlobalMacroContext)
2879  return;
2880 
2881  if (mc->macroTable != NULL) {
2882  int i;
2883  for (i = 0; i < mc->firstFree; i++) {
2884  MacroEntry *mep, me;
2885  mep = &mc->macroTable[i];
2886  me = *mep;
2887 
2888  if (me == NULL) /* XXX this should never happen */
2889  continue;
2890  addMacro(NULL, me->name, me->opts, me->body, (level - 1));
2891  }
2892  }
2893 }
2894 
2895 #if defined(RPM_VENDOR_OPENPKG) /* expand-macrosfile-macro */
2896 static void expand_macrosfile_macro(const char *file_name, const char *buf, size_t bufn)
2897 {
2898  char *cp;
2899  size_t l, k;
2900  static const char *macro_name = "%{macrosfile}";
2901 
2902  l = strlen(macro_name);
2903  k = strlen(file_name);
2904  while ((cp = strstr(buf, macro_name)) != NULL) {
2905  if (((strlen(buf) - l) + k) < bufn) {
2906  memmove(cp+k, cp+l, strlen(cp+l)+1);
2907  memcpy(cp, file_name, k);
2908  }
2909  }
2910  return;
2911 }
2912 #endif
2913 
2914 int
2915 rpmLoadMacroFile(MacroContext mc, const char * fn, int nesting)
2916 {
2917  size_t bufn = _macro_BUFSIZ;
2918  char *buf = (char *) alloca(bufn);
2919  int lineno = 0;
2920  int rc = -1;
2921  FD_t fd;
2922  int xx;
2923 
2924  /* XXX TODO: teach rdcl() to read through a URI, eliminate ".fpio". */
2925  fd = Fopen(fn, "r.fpio");
2926  if (fd == NULL || Ferror(fd)) {
2927  if (fd) (void) Fclose(fd);
2928  return rc;
2929  }
2930 
2931  /* XXX Assume new fangled macro expansion */
2932  /*@-mods@*/
2934  /*@=mods@*/
2935 
2936  buf[0] = '\0';
2937  while(rdcl(buf, bufn, fd) != NULL) {
2938  char * s;
2939  int c;
2940 
2941  lineno++;
2942  s = buf;
2943  SKIPBLANK(s, c);
2944 
2945  if (c != (int) '%')
2946  continue;
2947 
2948  /* Parse %{load:...} immediately recursively. */
2949  if (s[1] == '{' && !strncmp(s+2, "load:", sizeof("load:")-1)) {
2950  char * se = (char *) matchchar(s, '{', '}');
2951  const char ** argv = NULL;
2952  int argc = 0;
2953  int i;
2954  if (se == NULL) {
2956  _("%s:%u Missing '}' in \"%s\", skipping.\n"),
2957  fn, lineno, buf);
2958  continue;
2959  }
2960  s += sizeof("%{load:") - 1;
2961  SKIPBLANK(s, c);
2962  *se = '\0';
2963  if (nesting <= 0) {
2965  _("%s:%u load depth exceeded, \"%s\" ignored.\n"),
2966  fn, lineno, buf);
2967  continue;
2968  }
2969  se = rpmMCExpand(mc, s, NULL);
2970  rc = rpmGlob(se, &argc, &argv);
2971  for(i = 0; i < argc; i++) {
2972  /* Skip backups, non existing files and %config leftovers. */
2973 #define _suffix(_s, _x) \
2974  (strlen(_s) >= sizeof(_x) && !strcmp((_s)+strlen(_s)-(sizeof(_x)-1), (_x)))
2975  if (!(_suffix(argv[i], "~")
2976  || _suffix(argv[i], ".rpmnew")
2977  || _suffix(argv[i], ".rpmorig")
2978  || _suffix(argv[i], ".rpmsave"))
2979  && !Access(argv[i], R_OK)
2980  )
2981  rc |= rpmLoadMacroFile(mc, argv[i], nesting - 1);
2982 #undef _suffix
2983  argv[i] = _free(argv[i]);
2984  }
2985  argv = _free(argv);
2986  se = _free(se);
2987  if (rc != 0)
2988  goto exit;
2989  } else {
2990 #if defined(RPM_VENDOR_OPENPKG) /* expand-macro-source */
2991  expand_macrosfile_macro(fn, buf, bufn);
2992 #endif
2993  if (*s == '%') s++;
2994  rc = rpmDefineMacro(mc, s, RMIL_MACROFILES);
2995  }
2996  }
2997  rc = 0;
2998 exit:
2999  xx = Fclose(fd);
3000  return rc;
3001 }
3002 
3003 void
3004 rpmInitMacros(MacroContext mc, const char * macrofiles)
3005 {
3006  char *mfiles, *m, *me;
3007 
3008  if (macrofiles == NULL)
3009  return;
3010 #ifdef DYING
3011  if (mc == NULL) mc = rpmGlobalMacroContext;
3012 #endif
3013 
3014  mfiles = xstrdup(macrofiles);
3015  for (m = mfiles; m && *m != '\0'; m = me) {
3016  const char ** av;
3017  int ac;
3018  int i;
3019 
3020  for (me = m; (me = strchr(me, ':')) != NULL; me++) {
3021  /* Skip over URI's. */
3022  if (!(me[1] == '/' && me[2] == '/'))
3023  /*@innerbreak@*/ break;
3024  }
3025 
3026  if (me && *me == ':')
3027  *me++ = '\0';
3028  else
3029  me = m + strlen(m);
3030 
3031  /* Glob expand the macro file path element, expanding ~ to $HOME. */
3032  ac = 0;
3033  av = NULL;
3034 #if defined(DEBUG_MACROS)
3035  ac = 1;
3036  av = xmalloc((ac + 1) * sizeof(*av));
3037  av[0] = strdup(m);
3038  av[1] = NULL;
3039 #else
3040  i = rpmGlob(m, &ac, &av);
3041  if (i != 0)
3042  continue;
3043 #endif
3044 
3045  /* Read macros from each file. */
3046 
3047  for (i = 0; i < ac; i++) {
3048  size_t slen = strlen(av[i]);
3049  const char *fn = av[i];
3050 
3051  if (fn[0] == '@' /* attention */) {
3052  fn++;
3053 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \
3054  !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */
3055  if (!rpmSecuritySaneFile(fn))
3056 #else
3057  if (!poptSaneFile(fn))
3058 #endif
3059  {
3060  rpmlog(RPMLOG_WARNING, "existing RPM macros file \"%s\" considered INSECURE -- not loaded\n", fn);
3061  /*@innercontinue@*/ continue;
3062  }
3063  }
3064 
3065  /* Skip backup files and %config leftovers. */
3066 #define _suffix(_s, _x) \
3067  (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
3068  if (!(_suffix(fn, "~")
3069  || _suffix(fn, ".rpmnew")
3070  || _suffix(fn, ".rpmorig")
3071  || _suffix(fn, ".rpmsave"))
3072  )
3073  (void) rpmLoadMacroFile(mc, fn, _max_load_depth);
3074 #undef _suffix
3075 
3076  av[i] = _free(av[i]);
3077  }
3078  av = _free(av);
3079  }
3080  mfiles = _free(mfiles);
3081 
3082  /* Reload cmdline macros */
3083  /*@-mods@*/
3085  /*@=mods@*/
3086 }
3087 
3088 /*@-globstate@*/
3089 void
3091 {
3092 
3093  if (mc == NULL) mc = rpmGlobalMacroContext;
3094 
3095  if (mc->macroTable != NULL) {
3096  int i;
3097  for (i = 0; i < mc->firstFree; i++) {
3098  MacroEntry me;
3099  while ((me = mc->macroTable[i]) != NULL) {
3100  /* XXX cast to workaround const */
3101  /*@-onlytrans@*/
3102  if ((mc->macroTable[i] = me->prev) == NULL)
3103  me->name = _free(me->name);
3104  /*@=onlytrans@*/
3105  me->opts = _free(me->opts);
3106  me->body = _free(me->body);
3107  if (me) free(me);
3108  me = NULL;
3109  }
3110  }
3111  free(mc->macroTable);
3112  mc->macroTable = NULL;
3113  }
3114  memset(mc, 0, sizeof(*mc));
3115 }
3116 /*@=globstate@*/
3117 
3118 /* =============================================================== */
3119 int isCompressed(const char * file, rpmCompressedMagic * compressed)
3120 {
3121  FD_t fd;
3122  ssize_t nb;
3123  int rc = -1;
3124  unsigned char magic[13];
3125 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */
3126  size_t file_len;
3127 #endif
3128 
3129  *compressed = COMPRESSED_NOT;
3130 #if defined(RPM_VENDOR_PLD)
3131  /*
3132  * Workaround for misleading message:
3133  * error: File %PATCH666: No such file or directory
3134  * It happens when there is no "PatchXXX: " definition
3135  * and spec contains commented out %patchXXX macro
3136  * http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/5d3a3ea257d7f88e59d0ad93c20cc8448fb42f3d
3137  */
3138  if ((strlen(file) > 6) && (strncasecmp(file, "%PATCH", 6) == 0))
3139  return 0;
3140 #endif
3141 
3142 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */
3143  file_len = strlen(file);
3144  if ((file_len > 4 && strcasecmp(file+file_len-4, ".tbz") == 0)
3145  || (file_len > 4 && strcasecmp(file+file_len-4, ".bz2") == 0)) {
3146  *compressed = COMPRESSED_BZIP2;
3147  return 0;
3148  } else
3149  if (file_len > 4 && strcasecmp(file+file_len-4, ".zip") == 0) {
3150  *compressed = COMPRESSED_ZIP;
3151  return 0;
3152  } else
3153  if ((file_len > 4 && strcasecmp(file+file_len-4, ".tlz") == 0)
3154  || (file_len > 5 && strcasecmp(file+file_len-5, ".lzma") == 0)) {
3155  *compressed = COMPRESSED_LZMA;
3156  return 0;
3157  } else
3158  if (file_len > 4 && strcasecmp(file+file_len-3, ".xz") == 0) {
3159  *compressed = COMPRESSED_XZ;
3160  return 0;
3161  } else
3162  if ((file_len > 4 && strcasecmp(file+file_len-4, ".tgz") == 0)
3163  || (file_len > 3 && strcasecmp(file+file_len-3, ".gz") == 0)
3164  || (file_len > 2 && strcasecmp(file+file_len-2, ".Z") == 0)) {
3165  *compressed = COMPRESSED_OTHER;
3166  return 0;
3167  } else
3168  if (file_len > 5 && strcasecmp(file+file_len-5, ".cpio") == 0) {
3169  *compressed = COMPRESSED_NOT;
3170  return 0;
3171  } else
3172  if (file_len > 4 && strcasecmp(file+file_len-4, ".tar") == 0) {
3173  *compressed = COMPRESSED_NOT;
3174  return 0;
3175  }
3176 #endif
3177 
3178  fd = Fopen(file, "r");
3179  if (fd == NULL || Ferror(fd)) {
3180  /* XXX Fstrerror */
3181  rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd));
3182  if (fd) (void) Fclose(fd);
3183  return 1;
3184  }
3185  nb = Fread(magic, sizeof(magic[0]), sizeof(magic), fd);
3186  if (nb < (ssize_t)0) {
3187  rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd));
3188  rc = 1;
3189  } else if (nb < (ssize_t)sizeof(magic)) {
3190  rpmlog(RPMLOG_ERR, _("File %s is smaller than %u bytes\n"),
3191  file, (unsigned)sizeof(magic));
3192  rc = 0;
3193  }
3194  (void) Fclose(fd);
3195  if (rc >= 0)
3196  return rc;
3197 
3198  rc = 0;
3199 
3200  if (magic[0] == 'B' && magic[1] == 'Z')
3201  *compressed = COMPRESSED_BZIP2;
3202  else
3203  if (magic[0] == (unsigned char) 0120 && magic[1] == (unsigned char) 0113
3204  && magic[2] == (unsigned char) 0003 && magic[3] == (unsigned char) 0004) /* pkzip */
3205  *compressed = COMPRESSED_ZIP;
3206  else
3207  if (magic[0] == (unsigned char) 0x89 && magic[1] == 'L'
3208  && magic[2] == 'Z' && magic[3] == 'O') /* lzop */
3209  *compressed = COMPRESSED_LZOP;
3210  else
3211 #if !defined(RPM_VENDOR_OPENPKG) && !defined(RPM_VENDOR_FEDORA) && !defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */
3212  /* XXX Ick, LZMA has no magic. See http://lkml.org/lkml/2005/6/13/285 */
3213  if (magic[ 9] == (unsigned char) 0x00 && magic[10] == (unsigned char) 0x00 &&
3214  magic[11] == (unsigned char) 0x00 && magic[12] == (unsigned char) 0x00) /* lzmash */
3215  *compressed = COMPRESSED_LZMA;
3216  else
3217 #endif
3218 #if defined(RPM_VENDOR_OPENSUSE)
3219  if (magic[0] == 0135 && magic[1] == 0 && magic[2] == 0) /* lzma */
3220  *compressed = COMPRESSED_LZMA;
3221  else
3222 #endif
3223  if (magic[0] == (unsigned char) 0xFD && magic[1] == 0x37 && magic[2] == 0x7A
3224  && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00) /* xz */
3225  *compressed = COMPRESSED_XZ;
3226  else if ((magic[0] == 'L') && (magic[1] == 'Z') &&
3227  (magic[2] == 'I') && (magic[3] == 'P')) /* lzip */
3228  *compressed = COMPRESSED_LZIP;
3229  else if ((magic[0] == 'L') && (magic[1] == 'R') &&
3230  (magic[2] == 'Z') && (magic[3] == 'I')) /* lrzip */
3231  *compressed = COMPRESSED_LRZIP;
3232  else if ((magic[0] == '7') && (magic[1] == 'z') &&
3233  (magic[2] == 0xbc) && (magic[3] == 0xaf) &&
3234  (magic[4] == 0x27) && (magic[5] == 0x1c)) /* 7zip */
3235  *compressed = COMPRESSED_7ZIP;
3236  else
3237  if ((magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0213) /* gzip */
3238  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0236) /* old gzip */
3239  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0036) /* pack */
3240  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0240) /* SCO lzh */
3241  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0235)) /* compress */
3242  *compressed = COMPRESSED_OTHER;
3243 
3244  return rc;
3245 }
3246 
3247 /* =============================================================== */
3248 
3249 /*@-modfilesys@*/
3250 /* XXX TODO: merge rpmExpand and rpmMCExpand. gud enuf for now ... */
3251 char *
3252 rpmExpand(const char *arg, ...)
3253 {
3254  MacroContext mc = NULL;
3255  const char *s;
3256  char *t, *te;
3257  size_t sn, tn;
3258  size_t bufn = 8 * _macro_BUFSIZ;
3259 
3260  va_list ap;
3261 
3262  if (arg == NULL)
3263  return xstrdup("");
3264 
3265  t = (char *) xmalloc(bufn + strlen(arg) + 1);
3266  *t = '\0';
3267  te = stpcpy(t, arg);
3268 
3269  va_start(ap, arg);
3270  while ((s = va_arg(ap, const char *)) != NULL) {
3271  sn = strlen(s);
3272  tn = (te - t);
3273  t = (char *) xrealloc(t, tn + sn + bufn + 1);
3274  te = t + tn;
3275  te = stpcpy(te, s);
3276  }
3277  va_end(ap);
3278 
3279  *te = '\0';
3280  tn = (te - t);
3281  (void) expandMacros(NULL, mc, t, tn + bufn + 1);
3282  t[tn + bufn] = '\0';
3283  t = (char *) xrealloc(t, strlen(t) + 1);
3284 
3285  return t;
3286 }
3287 
3288 char *
3289 rpmMCExpand(MacroContext mc, const char *arg, ...)
3290 {
3291  const char *s;
3292  char *t, *te;
3293  size_t sn, tn;
3294  size_t bufn = 8 * _macro_BUFSIZ;
3295 
3296  va_list ap;
3297 
3298  if (arg == NULL)
3299  return xstrdup("");
3300 
3301  t = (char *) xmalloc(bufn + strlen(arg) + 1);
3302  *t = '\0';
3303  te = stpcpy(t, arg);
3304 
3305  va_start(ap, arg);
3306  while ((s = va_arg(ap, const char *)) != NULL) {
3307  sn = strlen(s);
3308  tn = (te - t);
3309  t = (char *) xrealloc(t, tn + sn + bufn + 1);
3310  te = t + tn;
3311  te = stpcpy(te, s);
3312  }
3313  va_end(ap);
3314 
3315  *te = '\0';
3316  tn = (te - t);
3317  (void) expandMacros(NULL, mc, t, tn + bufn + 1);
3318  t[tn + bufn] = '\0';
3319  t = (char *) xrealloc(t, strlen(t) + 1);
3320 
3321  return t;
3322 }
3323 /*@=modfilesys@*/
3324 
3325 int
3326 rpmExpandNumeric(const char *arg)
3327 {
3328  const char *val;
3329  int rc;
3330 
3331  if (arg == NULL)
3332  return 0;
3333 
3334  val = rpmExpand(arg, NULL);
3335  if (!(val && *val != '%'))
3336  rc = 0;
3337  else if (*val == 'Y' || *val == 'y')
3338  rc = 1;
3339  else if (*val == 'N' || *val == 'n')
3340  rc = 0;
3341  else {
3342  char *end;
3343  rc = strtol(val, &end, 0);
3344  if (!(end && *end == '\0'))
3345  rc = 0;
3346  }
3347  val = _free(val);
3348 
3349  return rc;
3350 }
3351 
3352 /* @todo "../sbin/./../bin/" not correct. */
3353 char *rpmCleanPath(char * path)
3354 {
3355  const char *s;
3356  char *se, *t, *te;
3357  int begin = 1;
3358 
3359  if (path == NULL)
3360  return NULL;
3361 
3362 /*fprintf(stderr, "*** RCP %s ->\n", path); */
3363  s = t = te = path;
3364  while (*s != '\0') {
3365 /*fprintf(stderr, "*** got \"%.*s\"\trest \"%s\"\n", (t-path), path, s); */
3366  switch(*s) {
3367  case ':': /* handle url's */
3368  if (s[1] == '/' && s[2] == '/') {
3369  *t++ = *s++;
3370  *t++ = *s++;
3371  /* XXX handle "file:///" */
3372  if (s[0] == '/') *t++ = *s++;
3373  te = t;
3374  /*@switchbreak@*/ break;
3375  }
3376  begin=1;
3377  /*@switchbreak@*/ break;
3378  case '/':
3379  /* Move parent dir forward */
3380  for (se = te + 1; se < t && *se != '/'; se++)
3381  {};
3382  if (se < t && *se == '/') {
3383  te = se;
3384 /*fprintf(stderr, "*** next pdir \"%.*s\"\n", (te-path), path); */
3385  }
3386  while (s[1] == '/')
3387  s++;
3388  while (t > te && t[-1] == '/')
3389  t--;
3390  /*@switchbreak@*/ break;
3391  case '.':
3392  /* Leading .. is special */
3393  /* Check that it is ../, so that we don't interpret */
3394  /* ..?(i.e. "...") or ..* (i.e. "..bogus") as "..". */
3395  /* in the case of "...", this ends up being processed*/
3396  /* as "../.", and the last '.' is stripped. This */
3397  /* would not be correct processing. */
3398  if (begin && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
3399 /*fprintf(stderr, " leading \"..\"\n"); */
3400  *t++ = *s++;
3401  /*@switchbreak@*/ break;
3402  }
3403  /* Single . is special */
3404  if (begin && s[1] == '\0') {
3405  /*@switchbreak@*/ break;
3406  }
3407  if (t > path && t[-1] == '/')
3408  switch (s[1]) {
3409  case '/': s++; /*@fallthrough@*/ /* Trim embedded ./ */
3410  case '\0': s++; continue; /* Trim trailing /. */
3411  default: /*@innerbreak@*/ break;
3412  }
3413  /* Trim embedded /../ and trailing /.. */
3414  if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
3415  t = te;
3416  /* Move parent dir forward */
3417  if (te > path)
3418  for (--te; te > path && *te != '/'; te--)
3419  {};
3420 /*fprintf(stderr, "*** prev pdir \"%.*s\"\n", (te-path), path); */
3421  s++;
3422  s++;
3423  continue;
3424  }
3425  /*@switchbreak@*/ break;
3426  default:
3427  begin = 0;
3428  /*@switchbreak@*/ break;
3429  }
3430  *t++ = *s++;
3431  }
3432 
3433  /* Trim trailing / (but leave single / alone) */
3434  if (t > &path[1] && t[-1] == '/')
3435  t--;
3436  *t = '\0';
3437 
3438 /*fprintf(stderr, "\t%s\n", path); */
3439  return path;
3440 }
3441 
3442 /* Return concatenated and expanded canonical path. */
3443 
3444 char *
3445 rpmGetPath(const char *path, ...)
3446 {
3447  size_t bufn = _macro_BUFSIZ;
3448  char *buf = (char *) alloca(bufn);
3449  const char * s;
3450  char * t, * te;
3451  int slashed = 0;
3452  va_list ap;
3453 
3454  if (path == NULL)
3455  return xstrdup("");
3456 
3457  buf[0] = '\0';
3458  t = buf;
3459  te = stpcpy(t, path);
3460  *te = '\0';
3461 
3462  va_start(ap, path);
3463  while ((s = va_arg(ap, const char *)) != NULL) {
3464  /* Specifically requested pesky trailing '/'? */
3465  slashed = (s[0] == '/' && s[1] == '\0');
3466  te = stpcpy(te, s);
3467  }
3468  va_end(ap);
3469  *te = '\0';
3470 
3471 /*@-modfilesys@*/
3472  (void) expandMacros(NULL, NULL, buf, bufn);
3473 /*@=modfilesys@*/
3474 
3475  /* Note: rpmCleanPath will strip pesky trailing '/'. */
3476  (void) rpmCleanPath(buf);
3477 
3478  /* Re-append specifically requested pesky trailing '/'. */
3479  if (slashed) {
3480  size_t nb = strlen(buf);
3481  if (buf[nb-1] != '/')
3482  buf[nb++] = '/';
3483  buf[nb] = '\0';
3484  }
3485 
3486  return DRD_xstrdup(buf); /* XXX xstrdup has side effects. */
3487 }
3488 
3489 /* Merge 3 args into path, any or all of which may be a url. */
3490 
3491 const char * rpmGenPath(const char * urlroot, const char * urlmdir,
3492  const char *urlfile)
3493 {
3494 /*@owned@*/ const char * xroot = rpmGetPath(urlroot, NULL);
3495 /*@dependent@*/ const char * root = xroot;
3496 /*@owned@*/ const char * xmdir = rpmGetPath(urlmdir, NULL);
3497 /*@dependent@*/ const char * mdir = xmdir;
3498 /*@owned@*/ const char * xfile = rpmGetPath(urlfile, NULL);
3499 /*@dependent@*/ const char * file = xfile;
3500  const char * result;
3501  const char * url = NULL;
3502  size_t nurl = 0;
3503  int ut;
3504 
3505 #if 0
3506 if (_debug) fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile);
3507 #endif
3508  ut = urlPath(xroot, &root);
3509  if (url == NULL && ut > URL_IS_DASH) {
3510  url = xroot;
3511  nurl = strlen(url);
3512  if (root >= url && root <= url+nurl)
3513  nurl -= strlen(root);
3514 #if 0
3515 if (_debug) fprintf(stderr, "*** RGP ut %d root %s nurl %u\n", ut, root, (unsigned)nurl);
3516 #endif
3517  }
3518  if (root == NULL || *root == '\0') root = "/";
3519 
3520  ut = urlPath(xmdir, &mdir);
3521  if (url == NULL && ut > URL_IS_DASH) {
3522  url = xmdir;
3523  nurl = strlen(url);
3524  if (mdir >= url && mdir <= url+nurl)
3525  nurl -= strlen(mdir);
3526 #if 0
3527 if (_debug) fprintf(stderr, "*** RGP ut %d mdir %s nurl %u\n", ut, mdir, (unsigned)nurl);
3528 #endif
3529  }
3530  if (mdir == NULL || *mdir == '\0') mdir = "/";
3531 
3532  ut = urlPath(xfile, &file);
3533  if (url == NULL && ut > URL_IS_DASH) {
3534  url = xfile;
3535  nurl = strlen(url);
3536  if (file >= url && file <= url+nurl)
3537  nurl -= strlen(file);
3538 #if 0
3539 if (_debug) fprintf(stderr, "*** RGP ut %d file %s nurl %u\n", ut, file, (unsigned)nurl);
3540 #endif
3541  }
3542 
3543  if (url && nurl > 0) {
3544  char *t = strncpy((char *)alloca(nurl+1), url, nurl);
3545  t[nurl] = '\0';
3546  url = t;
3547  } else
3548  url = "";
3549 
3550  result = rpmGetPath(url, root, "/", mdir, "/", file, NULL);
3551 
3552  xroot = _free(xroot);
3553  xmdir = _free(xmdir);
3554  xfile = _free(xfile);
3555 #if 0
3556 if (_debug) fprintf(stderr, "*** RGP result %s\n", result);
3557 #endif
3558  return result;
3559 }
3560 
3561 /* =============================================================== */
3562 
3563 #if defined(DEBUG_MACROS)
3564 
3565 #if defined(EVAL_MACROS)
3566 
3567 const char *rpmMacrofiles = MACROFILES;
3568 
3569 int
3570 main(int argc, char *argv[])
3571 {
3572  int c;
3573  int errflg = 0;
3574  extern char *optarg;
3575  extern int optind;
3576 
3577  while ((c = getopt(argc, argv, "f:")) != EOF ) {
3578  switch (c) {
3579  case 'f':
3580  rpmMacrofiles = optarg;
3581  break;
3582  case '?':
3583  default:
3584  errflg++;
3585  break;
3586  }
3587  }
3588  if (errflg || optind >= argc) {
3589  fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
3590  exit(1);
3591  }
3592 
3593  rpmInitMacros(NULL, rpmMacrofiles);
3594  /* XXX getopt(3) also used for parametrized macros, expect scwewiness. */
3595  for ( ; optind < argc; optind++) {
3596  const char *val;
3597 
3598  val = rpmExpand(argv[optind], NULL);
3599  if (val) {
3600  fprintf(stdout, "%s:\t%s\n", argv[optind], val);
3601  val = _free(val);
3602  }
3603  }
3604  rpmFreeMacros(NULL);
3605  return 0;
3606 }
3607 
3608 #else /* !EVAL_MACROS */
3609 
3610 const char *rpmMacrofiles = "../macros:./testmacros";
3611 const char *testfile = "./test";
3612 
3613 int
3614 main(int argc, char *argv[])
3615 {
3616  size_t bufn = _macro_BUFSIZ;
3617  char *buf = (char *) alloca(bufn);
3618  FILE *fp;
3619  int x;
3620 
3621  rpmInitMacros(NULL, rpmMacrofiles);
3622 
3623  if ((fp = fopen(testfile, "r")) != NULL) {
3624  while(rdcl(buf, bufn, fp)) {
3625  x = expandMacros(NULL, NULL, buf, bufn);
3626  fprintf(stderr, "%d->%s\n", x, buf);
3627  memset(buf, 0, bufn);
3628  }
3629  fclose(fp);
3630  }
3631 
3632  while(rdcl(buf, bufn, stdin)) {
3633  x = expandMacros(NULL, NULL, buf, bufn);
3634  fprintf(stderr, "%d->%s\n <-\n", x, buf);
3635  memset(buf, 0, bufn);
3636  }
3637  rpmFreeMacros(NULL);
3638 
3639  return 0;
3640 }
3641 #endif /* EVAL_MACROS */
3642 #endif /* DEBUG_MACROS */
const bson * b
Definition: bson.h:280
void rpmInitMacros(MacroContext mc, const char *macrofiles)
Initialize macro context from set of macrofile(s).
Definition: macro.c:3004
void rpmFreeMacros(MacroContext mc)
Destroy macro context.
Definition: macro.c:3090
static void printMacro(MacroBuf mb, const char *s, const char *se)
Pre-print macro expression to be expanded.
Definition: macro.c:496
int rpmuuidMake(int version, const char *ns, const char *data, char *buf_str, unsigned char *buf_bin)
Generate a Universally Unique Identifier (UUID).
Definition: rpmuuid.c:23
rpmsm rpmsmFree(rpmsm sm)
Destroy a semanage wrapper.
const char * s
Definition: macro.c:137
#define RMIL_GLOBAL
Definition: rpmmacro.h:70
const char * _rpmaugLoadpath
Definition: rpmaug.c:79
static void doFoo(MacroBuf mb, int negate, const char *f, size_t fn, const char *g, size_t gn)
Execute macro primitives.
Definition: macro.c:1277
const char const char size_t len
Definition: bson.h:823
int isCompressed(const char *file, rpmCompressedMagic *compressed)
Return type of compression used in file.
Definition: macro.c:3119
char * getenv(const char *name)
static const char * doUnglobal(MacroContext mc, const char *se)
Parse (and execute) macro undefinition.
Definition: macro.c:913
const char * _rpmaugRoot
Definition: rpmaug.c:76
const char const char * cmd
Definition: mongo.h:777
struct rpmgit_s * rpmgit
Definition: rpmgit.h:10
#define _MAX_MACRO_DEPTH
Definition: macro.c:154
rpmsquirrel rpmsquirrelFree(rpmsquirrel squirrel)
Destroy a squirrel interpreter.
static int xisalnum(int c)
Definition: rpmiotypes.h:549
char * xstrdup(const char *str)
Definition: rpmmalloc.c:321
char * rpmCleanPath(char *path)
Canonicalize file path.
Definition: macro.c:3353
int Glob_error(const char *epath, int eerrno)
glob_error(3) clone.
Definition: rpmrpc.c:2271
__size_t gl_pathc
Definition: glob.h:119
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2840
struct rpmsql_s * rpmsql
Definition: rpmsql.h:20
rpmjs rpmjsFree(rpmjs js)
Destroy a js interpreter.
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3445
void rpmLoadMacros(MacroContext mc, int level)
Load macros from specific context into global context.
Definition: macro.c:2875
int Access(const char *path, int amode)
access(2) clone.
Definition: rpmrpc.c:2196
MacroContext rpmCLIMacroContext
Definition: macro.c:129
#define RPMLOG_MASK(pri)
Definition: rpmlog.h:136
int _max_load_depth
Definition: macro.c:168
static ARGV_t patterns
Definition: rpmgrep.c:87
int main(int argc, const char **argv, char **envp)
Definition: rpmqv.c:453
static const char uuid_ns[]
Definition: hdrfmt.c:1808
rpmlua rpmluaGetGlobalState(void)
#define R_OK
Definition: system.h:234
static const char * matchchar(const char *p, char pl, char pr)
Return text between pl and matching pr characters.
Definition: macro.c:470
rpmficl rpmficlNew(char **av, uint32_t flags)
Create and load a ficl interpreter.
Definition: rpmficl.c:74
void Globfree(void *_pglob)
globfree(3) clone.
Definition: rpmrpc.c:2322
void delMacroAll(MacroContext mc, const char *n)
Definition: macro.c:2840
static void pushMacro(MacroEntry *mep, const char *n, const char *o, const char *b, int level)
Push new macro definition onto macro entry stack.
Definition: macro.c:966
static const char * doUndefine(MacroContext mc, const char *se)
Parse (and execute) macro undefinition.
Definition: macro.c:878
#define POPT_ARGV_ARRAY_GROW_DELTA
Definition: macro.c:1531
struct rpmsm_s * rpmsm
Definition: rpmsm.h:11
struct rpmjs_s * rpmjs
Definition: rpmjs.h:11
void addMacro(MacroContext mc, const char *n, const char *o, const char *b, int level)
Add macro to context.
Definition: macro.c:2786
static void printExpansion(MacroBuf mb, const char *t, const char *te)
Post-print expanded macro expression.
Definition: macro.c:540
char ** gl_pathv
Definition: glob.h:120
static int xisalpha(int c)
Definition: rpmiotypes.h:543
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
Definition: glob.h:117
static size_t _macro_BUFSIZ
Definition: macro.c:175
static int expandFIFO(MacroBuf mb, MacroEntry me, const char *g, size_t gn)
Definition: macro.c:1507
rpmRC rpmaugRun(rpmaug aug, const char *str, const char **resultp)
Run augeas commands from a buffer.
Definition: rpmaug.c:763
struct MacroBuf_s * MacroBuf
static void popMacro(MacroEntry *mep)
Pop macro definition from macro entry stack.
Definition: macro.c:1001
unsigned int _rpmaugFlags
Definition: rpmaug.c:80
static int XpoptDupArgv(int argc, char **argv, int *argcPtr, char ***argvPtr)
Definition: macro.c:1533
rpmsql rpmsqlNew(char **av, uint32_t flags)
Create and load a sql interpreter.
Definition: rpmsql.c:5450
rpmpython rpmpythonFree(rpmpython python)
Destroy a python interpreter.
char * alloca()
static void sortMacroTable(MacroContext mc)
Sort entries in macro table.
Definition: macro.c:237
Yet Another syslog(3) API clone.
#define DRD_xstrdup(_str)
Definition: debug.h:176
static char * dupMacroEntry(MacroEntry me)
Definition: macro.c:259
int rpmGlob(const char *patterns, int *argcPtr, const char ***argvPtr)
Return URL path(s) from a (URL prefixed) pattern glob.
Definition: macro.c:2611
static int expandT(MacroBuf mb, const char *f, size_t flen)
Save source and expand field into target.
Definition: macro.c:610
void delMacro(MacroContext mc, const char *n)
Delete macro from context.
Definition: macro.c:2825
#define fdGetFILE(_fd)
Definition: rpmio.c:159
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
#define isblank(_c)
Definition: macro.c:9
#define _MAX_LOAD_DEPTH
Definition: macro.c:166
struct _FD_s * FD_t
Definition: rpmio.h:43
static void expandMacroTable(MacroContext mc)
Enlarge macro table.
Definition: macro.c:215
MacroContext rpmGlobalMacroContext
Definition: macro.c:124
rpmgit rpmgitFree(rpmgit git)
Destroy a git wrapper.
int Glob(const char *pattern, int flags, int errfunc(const char *epath, int eerrno), void *_pglob)
glob(3) clone.
Definition: rpmrpc.c:2277
rpmruby rpmrubyNew(char **av, uint32_t flags)
Creates and initializes a Ruby interpreter.
Definition: rpmruby.c:99
const char * mode
Definition: mongo.h:440
rpmRC rpmpythonRun(rpmpython python, const char *str, const char **resultp)
Execute python string.
Definition: rpmpython.c:159
char * realpath(const char *path, char resolved_path[])
int rpmGetMacroEntries(MacroContext mc, void *_mire, int used, const char ***avp)
Return macro entries as string array.
Definition: macro.c:321
RPM pattern matching.
char * stpncpy(char *dest, const char *src, size_t n)
#define SKIPBLANK(_s, _c)
Definition: macro.c:577
struct rpmaug_s * rpmaug
Definition: rpmaug.h:14
static int xisspace(int c)
Definition: rpmiotypes.h:555
struct rpmperl_s * rpmperl
Definition: rpmperl.h:11
struct miRE_s * miRE
Definition: mire.h:60
#define setlocale(Category, Locale)
Definition: system.h:513
int print_expand_trace
Definition: macro.c:164
rpmRC rpmficlRun(rpmficl ficl, const char *str, const char **resultp)
Execute ficl string.
Definition: rpmficl.c:140
const char * rpmluaGetPrintBuffer(rpmlua _lua)
rpmperl rpmperlNew(char **av, uint32_t flags)
Create and load a perl interpreter.
Definition: rpmperl.c:93
rpmjs rpmjsNew(char **av, uint32_t flags)
Create and load a js interpreter.
Definition: rpmjs.c:171
int rpmDefineMacro(MacroContext mc, const char *macro, int level)
Define macro in context.
Definition: macro.c:2853
struct rpmpython_s * rpmpython
Definition: rpmpython.h:11
rpmRC rpmsmRun(rpmsm sm, char **av, const char **resultp)
Run semanage commands.
Definition: rpmsm.c:400
static const char * file
Definition: parseFiles.c:20
#define SAVECHAR(_mb, _c)
Definition: macro.c:150
#define POPT_ERROR_BADQUOTE
Definition: macro.c:1528
int Glob_pattern_p(const char *pattern, int quote)
glob_pattern_p(3) clone.
Definition: rpmrpc.c:2231
struct rpmtcl_s * rpmtcl
Definition: rpmtcl.h:11
#define _PRINT_MACRO_TRACE
Definition: macro.c:158
rpmpython rpmpythonNew(char **av, uint32_t flags)
Create and load a python interpreter.
Definition: rpmpython.c:72
#define STREQ(_t, _f, _fn)
Definition: macro.c:13
The FD_t File Handle data structure.
const char * rpmMacrofiles
List of macro files to read when configuring rpm.
Definition: macro.c:62
const char * rpmGenPath(const char *urlroot, const char *urlmdir, const char *urlfile)
Merge 3 args into path, any or all of which may be a url.
Definition: macro.c:3491
void rpmDumpMacroTable(MacroContext mc, FILE *fp)
Print macros to file stream.
Definition: macro.c:287
int mireRegexec(miRE mire, const char *val, size_t vallen)
Execute pattern match.
Definition: mire.c:396
#define MACRO_CHUNK_SIZE
Definition: macro.c:171
void * spec
Definition: macro.c:145
static char * rdcl(char *buf, size_t size, FD_t fd)
fgets(3) analogue that reads \ continuations.
Definition: macro.c:406
rpmRC rpmsquirrelRun(rpmsquirrel squirrel, const char *str, const char **resultp)
Execute squirrel string.
Definition: rpmsquirrel.c:211
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3252
int expand_trace
Definition: macro.c:143
rpmaug rpmaugFree(rpmaug aug)
Destroy a augeas wrapper.
int depth
Definition: macro.c:141
Embedded Ruby interpreter.
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
const char const char int arg
Definition: mongo.h:777
static int XpoptParseArgvString(const char *s, int *argcPtr, char ***argvPtr)
Definition: macro.c:1573
static const char * grabArgs(MacroBuf mb, const MacroEntry me, const char *se, const char *lastc)
Parse arguments (to next new line) for parameterized macro.
Definition: macro.c:1075
static int expandMacro(MacroBuf mb)
Parse args and string for PHP like %{foo : } syntax.
Definition: macro.c:1693
static int expandU(MacroBuf mb, char *u, size_t ulen)
Save source/target and expand macro in u.
Definition: macro.c:663
int macro_trace
Definition: macro.c:142
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
struct rpmruby_s * rpmruby
Definition: rpmruby.h:32
#define _PRINT_EXPAND_TRACE
Definition: macro.c:162
#define POPT_ERROR_MALLOC
Definition: macro.c:1529
#define COPYOPTS(_oe, _s, _c)
Definition: macro.c:596
#define GLOB_TILDE
Definition: glob.h:88
rpmruby rpmrubyFree(rpmruby ruby)
Destroys a Ruby interpreter instance.
struct rpmsquirrel_s * rpmsquirrel
Definition: rpmsquirrel.h:11
rpmsm rpmsmNew(const char *fn, unsigned int flags)
Create and load a semanage wrapper.
Definition: rpmsm.c:343
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2951
rpmsql rpmsqlFree(rpmsql sql)
Destroy a sql interpreter.
#define POPT_ERROR_NOARG
Definition: macro.c:1527
const char const char const char * opts
Definition: bson.h:971
const char const int i
Definition: bson.h:778
#define _suffix(_s, _x)
enum rpmCompressedMagic_e rpmCompressedMagic
static int xisdigit(int c)
Definition: rpmiotypes.h:546
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
const char const bson * key
Definition: mongo.h:717
static const char * doDefine(MacroBuf mb, const char *se, int level, int expandbody)
Parse (and execute) new macro definition.
Definition: macro.c:741
char * stpcpy(char *dest, const char *src)
const char const char size_t size
Definition: bson.h:895
struct MacroContext_s * MacroContext
Definition: rpmmacro.h:13
static int compareMacroName(const void *ap, const void *bp)
Compare macro entries by name (qsort/bsearch).
Definition: macro.c:195
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
static void doOutput(MacroBuf mb, int waserror, const char *msg, size_t msglen)
Perform macro message output.
Definition: macro.c:1251
MacroContext mc
Definition: macro.c:147
#define MACROFILES
Definition: config.h:1106
static void freeArgs(MacroBuf mb)
Free parsed arguments for parameterized macro.
Definition: macro.c:1024
int print_macro_trace
Definition: macro.c:160
rpmRC rpmgitRun(rpmgit git, const char *str, const char **resultp)
Execute git string.
Definition: rpmgit.c:2825
int rpmSecuritySaneFile(const char *filename)
Check whether configuration file is moderately secure to load.
Definition: macro.c:2588
static struct MacroContext_s rpmCLIMacroContext_s
Definition: macro.c:127
rpmRC rpmsqlRun(rpmsql sql, const char *str, const char **resultp)
Execute sql from STRING | FILE | STDIN | INTERACTIVE.
Definition: rpmsql.c:5554
static struct MacroContext_s rpmGlobalMacroContext_s
Definition: macro.c:122
#define RMIL_MACROFILES
Definition: rpmmacro.h:63
#define COPYNAME(_ne, _s, _c)
Definition: macro.c:589
static MacroEntry * findEntry(MacroContext mc, const char *name, size_t namelen)
Find entry in macro table.
Definition: macro.c:368
static int _debug
Definition: macro.c:2609
rpmtcl rpmtclFree(rpmtcl tcl)
Destroy a tcl interpreter.
int expandMacros(void *spec, MacroContext mc, char *sbuf, size_t slen)
Expand macro into buffer.
Definition: macro.c:2751
struct rpmlua_s * rpmlua
Definition: rpmlua.h:53
char * t
Definition: macro.c:139
struct rpmficl_s * rpmficl
Definition: rpmficl.h:11
static const char * name
rpmRC rpmrubyRun(rpmruby ruby, const char *str, const char **resultp)
Evaluates Ruby code stored in a string.
Definition: rpmruby.c:126
int max_macro_depth
Definition: macro.c:156
rpmaug rpmaugNew(const char *root, const char *loadpath, unsigned int flags)
Create and load a augeas wrapper.
Definition: rpmaug.c:132
#define _(Text)
Definition: system.h:29
rpmficl rpmficlFree(rpmficl ficl)
Destroy a ficl interpreter.
static int doShellEscape(MacroBuf mb, const char *cmd, size_t clen)
Expand output of shell command into target buffer.
Definition: macro.c:700
#define xmalloc
Definition: system.h:32
int rpmLoadMacroFile(MacroContext mc, const char *fn, int nesting)
Load macro context from a macro file.
Definition: macro.c:2915
#define RMIL_CMDLINE
Definition: rpmmacro.h:66
struct MacroEntry_s * MacroEntry
Definition: rpmmacro.h:12
size_t nb
Definition: macro.c:140
Macro expansion state.
Definition: macro.c:135
rpmRC rpmjsRun(rpmjs js, const char *str, const char **resultp)
Execute js string.
Definition: rpmjs.c:410
int rpmlogSetMask(int mask)
Set the log mask level.
Definition: rpmlog.c:98
rpmgit rpmgitNew(char **av, uint32_t flags, void *_opts)
Create and load a git wrapper.
Definition: rpmgit.c:2750
static rpmuint32_t uuid_version
Definition: hdrfmt.c:1814
#define PATH_MAX
Definition: query.c:10
rpmsquirrel rpmsquirrelNew(char **av, uint32_t flags)
Definition: rpmsquirrel.c:106
rpmperl rpmperlFree(rpmperl perl)
Destroy a perl interpreter.
rpmtcl rpmtclNew(char **av, uint32_t flags)
Create and load a tcl interpreter.
Definition: rpmtcl.c:125
rpmRC rpmperlRun(rpmperl perl, const char *str, const char **resultp)
Execute perl string.
Definition: rpmperl.c:144
int rpmExpandNumeric(const char *arg)
Return macro expansion as a numeric value.
Definition: macro.c:3326
#define xrealloc
Definition: system.h:35
int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
int rpmUndefineMacro(MacroContext mc, const char *macro)
Undefine macro in context.
Definition: macro.c:2867
rpmRC rpmtclRun(rpmtcl tcl, const char *str, const char **resultp)
Execute tcl string.
Definition: rpmtcl.c:179
int j
Definition: mongo.h:438
#define iseol(_c)
Definition: macro.c:11
char * rpmMCExpand(MacroContext mc, const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s) in a context.
Definition: macro.c:3289