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)
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 
710  strncpy(buf, cmd, clen);
711  buf[clen] = '\0';
712  rc = expandU(mb, buf, bufn);
713  if (rc)
714  return rc;
715 
716  if ((shf = popen(buf, "r")) == NULL)
717  return 1;
718  while(mb->nb > 0 && (c = fgetc(shf)) != EOF)
719  SAVECHAR(mb, c);
720  (void) pclose(shf);
721 
722  /* XXX delete trailing \r \n */
723  while (iseol(mb->t[-1])) {
724  *(mb->t--) = '\0';
725  mb->nb++;
726  }
727  return 0;
728 }
729 
738 /*@dependent@*/ static const char *
739 doDefine(MacroBuf mb, /*@returned@*/ const char * se, int level, int expandbody)
740  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
741  /*@modifies mb, rpmGlobalMacroContext, internalState @*/
742 {
743  const char *s = se;
744  size_t bufn = _macro_BUFSIZ;
745  char *buf = (char *) alloca(bufn);
746  char *n = buf, *ne;
747  char *o = NULL, *oe;
748  char *b, *be;
749  int c;
750  int oc = (int) ')';
751 
752  SKIPBLANK(s, c);
753  if (c == (int) '.') /* XXX readonly macros */
754 /*@i@*/ *n++ = c = *s++;
755  if (c == (int) '.') /* XXX readonly macros */
756 /*@i@*/ *n++ = c = *s++;
757  ne = n;
758 
759  /* Copy name */
760  COPYNAME(ne, s, c);
761 
762  /* Copy opts (if present) */
763  oe = ne + 1;
764  if (*s == '(') {
765  s++; /* skip ( */
766  o = oe;
767  COPYOPTS(oe, s, oc);
768  /* Options must be terminated with ')' */
769  if (oc != ')') {
770  rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
771  se = s; /* XXX W2DO? */
772  return se;
773  }
774  s++; /* skip ) */
775  }
776 
777  /* Copy body, skipping over escaped newlines */
778  b = be = oe + 1;
779  SKIPBLANK(s, c);
780  if (c == (int) '{') { /* XXX permit silent {...} grouping */
781  if ((se = matchchar(s, (char) c, '}')) == NULL) {
783  _("Macro %%%s has unterminated body\n"), n);
784  se = s; /* XXX W2DO? */
785  return se;
786  }
787  s++; /* XXX skip { */
788  strncpy(b, s, (se - s));
789  b[se - s] = '\0';
790  be += strlen(b);
791  se++; /* XXX skip } */
792  s = se; /* move scan forward */
793  } else { /* otherwise free-field */
794  int bc = 0, pc = 0;
795  while (*s && (bc || pc || !iseol(*s))) {
796  switch (*s) {
797  case '\\':
798  switch (*(s+1)) {
799  case '\0': /*@switchbreak@*/ break;
800  default: s++; /*@switchbreak@*/ break;
801  }
802  /*@switchbreak@*/ break;
803  case '%':
804  switch (*(s+1)) {
805  case '{': *be++ = *s++; bc++; /*@switchbreak@*/ break;
806  case '(': *be++ = *s++; pc++; /*@switchbreak@*/ break;
807  case '%': *be++ = *s++; /*@switchbreak@*/ break;
808  }
809  /*@switchbreak@*/ break;
810  case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
811  case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
812  case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
813  case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
814  }
815  *be++ = *s++;
816  }
817  *be = '\0';
818 
819  if (bc || pc) {
821  _("Macro %%%s has unterminated body\n"), n);
822  se = s; /* XXX W2DO? */
823  return se;
824  }
825 
826  /* Trim trailing blanks/newlines */
827 /*@-globs@*/
828  while (--be >= b && (c = (int) *be) && (isblank(c) || iseol(c)))
829  {};
830 /*@=globs@*/
831  *(++be) = '\0'; /* one too far */
832  }
833 
834  /* Move scan over body */
835  while (iseol(*s))
836  s++;
837  se = s;
838 
839  /* Names must start with alphabetic or _ and be at least 3 chars */
840  if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) {
842  _("Macro %%%s has illegal name (%%define)\n"), n);
843  return se;
844  }
845 
846  if ((be - b) < 1) {
847  rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
848  return se;
849  }
850 
851 /*@-modfilesys@*/
852  if (expandbody && expandU(mb, b, (&buf[bufn] - b))) {
853  rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
854  return se;
855  }
856 /*@=modfilesys@*/
857 
858  if (n != buf) /* XXX readonly macros */
859  n--;
860  if (n != buf) /* XXX readonly macros */
861  n--;
862  addMacro(mb->mc, n, o, b, (level - 1));
863 
864  return se;
865 }
866 
873 /*@dependent@*/ static const char *
874 doUndefine(MacroContext mc, /*@returned@*/ const char * se)
875  /*@globals rpmGlobalMacroContext @*/
876  /*@modifies mc, rpmGlobalMacroContext @*/
877 {
878  const char *s = se;
879  char *buf = (char *) alloca(_macro_BUFSIZ);
880  char *n = buf, *ne = n;
881  int c;
882 
883  COPYNAME(ne, s, c);
884 
885  /* Move scan over body */
886  while (iseol(*s))
887  s++;
888  se = s;
889 
890  /* Names must start with alphabetic or _ and be at least 3 chars */
891  if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) {
893  _("Macro %%%s has illegal name (%%undefine)\n"), n);
894  return se;
895  }
896 
897  delMacro(mc, n);
898 
899  return se;
900 }
901 
908 /*@dependent@*/ static const char *
909 doUnglobal(MacroContext mc, /*@returned@*/ const char * se)
910  /*@globals rpmGlobalMacroContext @*/
911  /*@modifies mc, rpmGlobalMacroContext @*/
912 {
913  const char *s = se;
914  char *buf = alloca(_macro_BUFSIZ);
915  char *n = buf, *ne = n;
916  int c;
917 
918  COPYNAME(ne, s, c);
919 
920  /* Move scan over body */
921  while (iseol(*s))
922  s++;
923  se = s;
924 
925  /* Names must start with alphabetic or _ and be at least 3 chars */
926  if (!((c = *n) && (xisalpha(c) || c == '_') && (ne - n) > 2)) {
928  _("Macro %%%s has illegal name (%%unglobal)\n"), n);
929  return se;
930  }
931 
932  delMacroAll(mc, n);
933 
934  return se;
935 }
936 
937 #ifdef DYING
938 static void
939 dumpME(const char * msg, MacroEntry me)
940  /*@globals fileSystem @*/
941  /*@modifies fileSystem @*/
942 {
943  if (msg)
944  fprintf(stderr, "%s", msg);
945  fprintf(stderr, "\tme %p", me);
946  if (me)
947  fprintf(stderr,"\tname %p(%s) prev %p",
948  me->name, me->name, me->prev);
949  fprintf(stderr, "\n");
950 }
951 #endif
952 
961 static void
962 pushMacro(/*@out@*/ MacroEntry * mep, const char * n, /*@null@*/ const char * o,
963  /*@null@*/ const char * b, int level)
964  /*@modifies *mep @*/
965 {
966  MacroEntry prev = (mep && *mep ? *mep : NULL);
967  MacroEntry me = (MacroEntry) xmalloc(sizeof(*me));
968  const char *name = n;
969 
970  if (*name == '.') /* XXX readonly macros */
971  name++;
972  if (*name == '.') /* XXX readonly macros */
973  name++;
974 
975  /*@-assignexpose@*/
976  me->prev = prev;
977  /*@=assignexpose@*/
978  me->name = (prev ? prev->name : xstrdup(name));
979  me->opts = (o ? xstrdup(o) : NULL);
980  me->body = xstrdup(b ? b : "");
981  me->used = 0;
982  me->level = level;
983  me->flags = (name != n);
984  if (mep)
985  *mep = me;
986  else {
987  if (me) free(me);
988  me = NULL;
989  }
990 }
991 
996 static void
998  /*@modifies *mep @*/
999 {
1000  MacroEntry me = (*mep ? *mep : NULL);
1001 
1002  if (me) {
1003  /* XXX cast to workaround const */
1004  /*@-onlytrans@*/
1005  if ((*mep = me->prev) == NULL)
1006  me->name = _free(me->name);
1007  me->opts = _free(me->opts);
1008  me->body = _free(me->body);
1009  if (me) free(me);
1010  me = NULL;
1011  /*@=onlytrans@*/
1012  }
1013 }
1014 
1019 static void
1021  /*@modifies mb @*/
1022 {
1023  MacroContext mc = mb->mc;
1024  int ndeleted = 0;
1025  int i;
1026 
1027  if (mc == NULL || mc->macroTable == NULL)
1028  return;
1029 
1030  /* Delete dynamic macro definitions */
1031  for (i = 0; i < mc->firstFree; i++) {
1032  MacroEntry *mep, me;
1033  int skiptest = 0;
1034  mep = &mc->macroTable[i];
1035  me = *mep;
1036 
1037  if (me == NULL) /* XXX this should never happen */
1038  continue;
1039  if (me->level < mb->depth)
1040  continue;
1041  if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
1042  if (*me->name == '*' && me->used > 0)
1043  skiptest = 1; /* XXX skip test for %# %* %0 */
1044  } else if (!skiptest && me->used <= 0) {
1045 #if NOTYET
1047  _("Macro %%%s (%s) was not used below level %d\n"),
1048  me->name, me->body, me->level);
1049 #endif
1050  }
1051  popMacro(mep);
1052  if (!(mep && *mep))
1053  ndeleted++;
1054  }
1055 
1056  /* If any deleted macros, sort macro table */
1057  if (ndeleted)
1058  sortMacroTable(mc);
1059 }
1060 
1070 /*@dependent@*/ static const char *
1071 grabArgs(MacroBuf mb, const MacroEntry me, /*@returned@*/ const char * se,
1072  const char * lastc)
1073  /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
1074  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1075 {
1076  poptContext optCon;
1077  struct poptOption *optTbl;
1078  size_t bufn = _macro_BUFSIZ;
1079  char *buf = (char *) alloca(bufn);
1080  char *b, *be;
1081  char aname[16];
1082  const char *opts;
1083  int argc = 0;
1084  const char **argv;
1085  int c;
1086  unsigned int popt_flags;
1087 
1088  /* Copy macro name as argv[0], save beginning of args. */
1089  buf[0] = '\0';
1090  b = be = stpcpy(buf, me->name);
1091 
1092  addMacro(mb->mc, "0", NULL, buf, mb->depth);
1093 
1094  argc = 1; /* XXX count argv[0] */
1095 
1096  /* Copy args into buf until lastc */
1097  *be++ = ' ';
1098  while ((c = (int) *se++) != (int) '\0' && (se-1) != lastc) {
1099 /*@-globs@*/
1100  if (!isblank(c)) {
1101  *be++ = (char) c;
1102  continue;
1103  }
1104 /*@=globs@*/
1105  /* c is blank */
1106  if (be[-1] == ' ')
1107  continue;
1108  /* a word has ended */
1109  *be++ = ' ';
1110  argc++;
1111  }
1112  if (c == (int) '\0') se--; /* one too far */
1113  if (be[-1] != ' ')
1114  argc++, be++; /* last word has not trailing ' ' */
1115  be[-1] = '\0';
1116  if (*b == ' ') b++; /* skip the leading ' ' */
1117 
1118 /*
1119  * The macro %* analoguous to the shell's $* means "Pass all non-macro
1120  * parameters." Consequently, there needs to be a macro that means "Pass all
1121  * (including macro parameters) options". This is useful for verifying
1122  * parameters during expansion and yet transparently passing all parameters
1123  * through for higher level processing (e.g. %description and/or %setup).
1124  * This is the (potential) justification for %{**} ...
1125  */
1126  /* Add unexpanded args as macro */
1127  addMacro(mb->mc, "**", NULL, b, mb->depth);
1128 
1129 #ifdef NOTYET
1130  /* XXX if macros can be passed as args ... */
1131  expandU(mb, buf, bufn);
1132 #endif
1133 
1134  /* Build argv array */
1135  argv = (const char **) alloca((argc + 1) * sizeof(*argv));
1136  be[-1] = ' '; /* assert((be - 1) == (b + strlen(b) == buf + strlen(buf))) */
1137  be[0] = '\0';
1138 
1139  b = buf;
1140  for (c = 0; c < argc; c++) {
1141  argv[c] = b;
1142  b = strchr(b, ' ');
1143  *b++ = '\0';
1144  }
1145  /* assert(b == be); */
1146  argv[argc] = NULL;
1147 
1148  /* '+' as the first character means that options are recognized
1149  * only before positional arguments, as POSIX requires.
1150  */
1151  popt_flags = POPT_CONTEXT_NO_EXEC;
1152 #if defined(RPM_VENDOR_OPENPKG) /* always-strict-posix-option-parsing */
1153  popt_flags |= POPT_CONTEXT_POSIXMEHARDER;
1154 #endif
1155  if (me->opts[0] == '+') popt_flags |= POPT_CONTEXT_POSIXMEHARDER;
1156 
1157  /* Count the number of short options. */
1158  opts = me->opts;
1159  if (*opts == '+') opts++;
1160  for (c = 0; *opts != '\0'; opts++)
1161  if (*opts != ':') c++;
1162 
1163  /* Set up popt option table. */
1164  optTbl = (struct poptOption *) xcalloc(sizeof(*optTbl), (c + 1));
1165  opts = me->opts;
1166  if (*opts == '+') opts++;
1167  for (c = 0; *opts != '\0'; opts++) {
1168  if (*opts == ':') continue;
1169  optTbl[c].shortName = opts[0];
1170  optTbl[c].val = (int) opts[0];
1171  if (opts[1] == ':')
1172  optTbl[c].argInfo = POPT_ARG_STRING;
1173  c++;
1174  }
1175 
1176  /* Parse the options, defining option macros. */
1177 /*@-nullstate@*/
1178  optCon = poptGetContext(argv[0], argc, argv, optTbl, popt_flags);
1179 /*@=nullstate@*/
1180  while ((c = poptGetNextOpt(optCon)) > 0) {
1181  const char * optArg = poptGetOptArg(optCon);
1182  *be++ = '-';
1183  *be++ = (char) c;
1184  if (optArg != NULL) {
1185  *be++ = ' ';
1186  be = stpcpy(be, optArg);
1187  }
1188  *be++ = '\0';
1189  aname[0] = '-'; aname[1] = (char)c; aname[2] = '\0';
1190  addMacro(mb->mc, aname, NULL, b, mb->depth);
1191  if (optArg != NULL) {
1192  aname[0] = '-'; aname[1] = (char)c; aname[2] = '*'; aname[3] = '\0';
1193  addMacro(mb->mc, aname, NULL, optArg, mb->depth);
1194  }
1195  be = b; /* reuse the space */
1196 /*@-dependenttrans -modobserver -observertrans @*/
1197  optArg = _free(optArg);
1198 /*@=dependenttrans =modobserver =observertrans @*/
1199  }
1200  if (c < -1) {
1201  rpmlog(RPMLOG_ERR, _("Unknown option in macro %s(%s): %s: %s\n"),
1202  me->name, me->opts,
1203  poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c));
1204  goto exit;
1205  }
1206 
1207  argv = poptGetArgs(optCon);
1208  argc = 0;
1209  if (argv != NULL)
1210  for (c = 0; argv[c] != NULL; c++)
1211  argc++;
1212 
1213  /* Add arg count as macro. */
1214  sprintf(aname, "%d", argc);
1215  addMacro(mb->mc, "#", NULL, aname, mb->depth);
1216 
1217  /* Add macro for each arg. Concatenate args for %*. */
1218  if (be) {
1219  *be = '\0';
1220  if (argv != NULL)
1221  for (c = 0; c < argc; c++) {
1222  sprintf(aname, "%d", (c + 1));
1223  addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
1224  if (be != b) *be++ = ' '; /* Add space between args */
1225  be = stpcpy(be, argv[c]);
1226  }
1227  }
1228 
1229  /* Add unexpanded args as macro. */
1230  addMacro(mb->mc, "*", NULL, b, mb->depth);
1231 
1232 exit:
1233  optCon = poptFreeContext(optCon);
1234  if (optTbl) free(optTbl);
1235  optTbl = NULL;
1236  return se;
1237 }
1238 
1246 static void
1247 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
1248  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1249  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1250 {
1251  size_t bufn = _macro_BUFSIZ + msglen;
1252  char *buf = (char *) alloca(bufn);
1253 
1254  strncpy(buf, msg, msglen);
1255  buf[msglen] = '\0';
1256  (void) expandU(mb, buf, bufn);
1257  if (waserror)
1258  rpmlog(RPMLOG_ERR, "%s\n", buf);
1259  else
1260  fprintf(stderr, "%s", buf);
1261 }
1262 
1272 static void
1273 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
1274  /*@null@*/ const char * g, size_t gn)
1275  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1276  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1277 {
1278  size_t bufn = _macro_BUFSIZ + fn + gn;
1279  char * buf = (char *) alloca(bufn);
1280  char *b = NULL, *be;
1281  int c;
1282  mode_t mode;
1283 
1284  buf[0] = '\0';
1285  if (g != NULL) {
1286  strncpy(buf, g, gn);
1287  buf[gn] = '\0';
1288  (void) expandU(mb, buf, bufn);
1289  }
1290  if (fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) {
1291  /* Skip leading zeros */
1292  for (c = 5; c < (int)(fn-1) && f[c] == '0' && xisdigit((int)f[c+1]);)
1293  c++;
1294  b = buf;
1295  be = stpncpy( stpcpy(b, "%patch -P "), f+c, fn-c);
1296  *be = '\0';
1297  } else
1298  if (STREQ("basename", f, fn)) {
1299  if ((b = strrchr(buf, '/')) == NULL)
1300  b = buf;
1301  else
1302  b++;
1303  } else if (STREQ("dirname", f, fn)) {
1304  if ((b = strrchr(buf, '/')) != NULL)
1305  *b = '\0';
1306  b = buf;
1307 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */
1308  } else if (STREQ("realpath", f, fn)) {
1309  char rp[PATH_MAX];
1310  char *cp;
1311  size_t l;
1312  if ((cp = realpath(buf, rp)) != NULL) {
1313  l = strlen(cp);
1314  if ((size_t)(l+1) <= bufn) {
1315  memcpy(buf, cp, l+1);
1316  b = buf;
1317  }
1318  }
1319 #endif
1320  } else if (STREQ("getenv", f, fn)) {
1321  char *cp;
1322  if ((cp = getenv(buf)) != NULL)
1323  b = cp;
1324  } else if (STREQ("shrink", f, fn)) {
1325  /*
1326  * shrink body by removing all leading and trailing whitespaces and
1327  * reducing intermediate whitespaces to a single space character.
1328  */
1329  int i, j, k, was_space = 0;
1330  for (i = 0, j = 0, k = (int)strlen(buf); i < k; ) {
1331  if (xisspace((int)(buf[i]))) {
1332  was_space = 1;
1333  i++;
1334  continue;
1335  }
1336  else if (was_space) {
1337  was_space = 0;
1338  if (j > 0) /* remove leading blanks at all */
1339  buf[j++] = ' ';
1340  /* fallthrough */
1341  }
1342  buf[j++] = buf[i++];
1343  }
1344  buf[j] = '\0';
1345  b = buf;
1346  } else if (STREQ("suffix", f, fn)) {
1347  if ((b = strrchr(buf, '.')) != NULL)
1348  b++;
1349  } else if (STREQ("expand", f, fn)) {
1350  b = buf;
1351  } else if (STREQ("verbose", f, fn)) {
1352 #if defined(RPMLOG_MASK)
1353  if (negate)
1354  b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? NULL : buf);
1355  else
1356  b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? buf : NULL);
1357 #else
1358  /* XXX assume always verbose when running standalone */
1359  b = (negate) ? NULL : buf;
1360 #endif
1361  } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
1362  int ut = urlPath(buf, (const char **)&b);
1363  ut = ut; /* XXX quiet gcc */
1364  if (*b == '\0') b = (char *) "/";
1365  } else if (STREQ("uncompress", f, fn)) {
1366  rpmCompressedMagic compressed = COMPRESSED_OTHER;
1367 /*@-globs@*/
1368  for (b = buf; (c = (int)*b) && isblank(c);)
1369  b++;
1370  /* XXX FIXME: file paths with embedded white space needs rework. */
1371  for (be = b; (c = (int)*be) && !isblank(c);)
1372  be++;
1373 /*@=globs@*/
1374  *be++ = '\0';
1375  (void) isCompressed(b, &compressed);
1376  switch(compressed) {
1377  default:
1378  case 0: /* COMPRESSED_NOT */
1379  sprintf(be, "%%__cat %s", b);
1380  break;
1381  case 1: /* COMPRESSED_OTHER */
1382  sprintf(be, "%%__gzip -dc '%s'", b);
1383  break;
1384  case 2: /* COMPRESSED_BZIP2 */
1385  sprintf(be, "%%__bzip2 -dc '%s'", b);
1386  break;
1387  case 3: /* COMPRESSED_ZIP */
1388  sprintf(be, "%%__unzip -qq '%s'", b);
1389  break;
1390  case 4: /* COMPRESSED_LZOP */
1391  sprintf(be, "%%__lzop -dc '%s'", b);
1392  break;
1393  case 5: /* COMPRESSED_LZMA */
1394  sprintf(be, "%%__lzma -dc '%s'", b);
1395  break;
1396  case 6: /* COMPRESSED_XZ */
1397  sprintf(be, "%%__xz -dc '%s'", b);
1398  break;
1399  case 7: /* COMPRESSED_LRZIP */
1400  sprintf(be, "%%__lrzip -dqo- %s", b);
1401  break;
1402  case 8: /* COMPRESSED_LZIP */
1403  sprintf(be, "%%__lzip -dc %s", b);
1404  break;
1405  case 9: /* COMPRESSED_7ZIP */
1406  sprintf(be, "%%__7zip x %s", b);
1407  break;
1408  }
1409  b = be;
1410  } else if (STREQ("mkstemp", f, fn)) {
1411 /*@-globs@*/
1412  for (b = buf; (c = (int)*b) && isblank(c);)
1413  b++;
1414  /* XXX FIXME: file paths with embedded white space needs rework. */
1415  for (be = b; (c = (int)*be) && !isblank(c);)
1416  be++;
1417 /*@=globs@*/
1418 #if defined(HAVE_MKSTEMP)
1419  mode = umask(0077);
1420  (void) close(mkstemp(b));
1421  (void) umask(mode);
1422 #else
1423  (void) mktemp(b);
1424 #endif
1425  } else if (STREQ("mkdtemp", f, fn)) {
1426 /*@-globs@*/
1427  for (b = buf; (c = (int)*b) && isblank(c);)
1428  b++;
1429  /* XXX FIXME: file paths with embedded white space needs rework. */
1430  for (be = b; (c = (int)*be) && !isblank(c);)
1431  be++;
1432 /*@=globs@*/
1433 #if defined(HAVE_MKDTEMP) && !defined(__LCLINT__)
1434  if (mkdtemp(b) == NULL)
1435  perror("mkdtemp");
1436 #else
1437  if ((b = tmpnam(b)) != NULL)
1438  (void) mkdir(b, 0700); /* XXX S_IWRSXU is not included. */
1439 #endif
1440  } else if (STREQ("uuid", f, fn)) {
1441  int uuid_version;
1442  const char *uuid_ns;
1443  const char *uuid_data;
1444  char *cp;
1445  size_t n;
1446 
1447  uuid_version = 1;
1448  uuid_ns = NULL;
1449  uuid_data = NULL;
1450  cp = buf;
1451  if ((n = strspn(cp, " \t\n")) > 0)
1452  cp += n;
1453  if ((n = strcspn(cp, " \t\n")) > 0) {
1454  uuid_version = (int)strtol(cp, (char **)NULL, 10);
1455  cp += n;
1456  if ((n = strspn(cp, " \t\n")) > 0)
1457  cp += n;
1458  if ((n = strcspn(cp, " \t\n")) > 0) {
1459  uuid_ns = cp;
1460  cp += n;
1461  *cp++ = '\0';
1462  if ((n = strspn(cp, " \t\n")) > 0)
1463  cp += n;
1464  if ((n = strcspn(cp, " \t\n")) > 0) {
1465  uuid_data = cp;
1466  cp += n;
1467  *cp++ = '\0';
1468  }
1469  }
1470  }
1471 /*@-nullpass@*/ /* FIX: uuid_ns may be NULL */
1472  if (rpmuuidMake(uuid_version, uuid_ns, uuid_data, buf, NULL))
1473  rpmlog(RPMLOG_ERR, "failed to create UUID\n");
1474  else
1475  b = buf;
1476 /*@=nullpass@*/
1477  } else if (STREQ("S", f, fn)) {
1478  for (b = buf; (c = (int)*b) && xisdigit(c);)
1479  b++;
1480  if (!c) { /* digit index */
1481  b++;
1482  sprintf(b, "%%SOURCE%s", buf);
1483  } else
1484  b = buf;
1485  } else if (STREQ("P", f, fn)) {
1486  for (b = buf; (c = (int) *b) && xisdigit(c);)
1487  b++;
1488  if (!c) { /* digit index */
1489  b++;
1490  sprintf(b, "%%PATCH%s", buf);
1491  } else
1492  b = buf;
1493  } else if (STREQ("F", f, fn)) {
1494  b = buf + strlen(buf) + 1;
1495  sprintf(b, "file%s.file", buf);
1496  }
1497 
1498  if (b) {
1499  (void) expandT(mb, b, strlen(b));
1500  }
1501 }
1502 
1503 static int expandFIFO(MacroBuf mb, MacroEntry me, const char *g, size_t gn)
1504  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1505  /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/
1506 {
1507  int rc = 0;
1508 
1509  if (me) {
1510  if (me->prev) {
1511  rc = expandFIFO(mb, me->prev, g, gn);
1512  rc = expandT(mb, g, gn);
1513  }
1514  rc = expandT(mb, me->body, strlen(me->body));
1515  }
1516  return rc;
1517 }
1518 
1519 #if !defined(DEBUG_MACROS)
1520 /* =============================================================== */
1521 /* XXX dupe'd to avoid change in linkage conventions. */
1522 
1523 #define POPT_ERROR_NOARG -10
1524 #define POPT_ERROR_BADQUOTE -15
1525 #define POPT_ERROR_MALLOC -21
1527 #define POPT_ARGV_ARRAY_GROW_DELTA 5
1528 
1529 static int XpoptDupArgv(int argc, char **argv,
1530  int * argcPtr, char *** argvPtr)
1531  /*@modifies *argcPtr, *argvPtr @*/
1532 {
1533  size_t nb = (argc + 1) * sizeof(*argv);
1534  char ** argv2;
1535  char * dst;
1536  int i;
1537 
1538  if (argc <= 0 || argv == NULL) /* XXX can't happen */
1539  return POPT_ERROR_NOARG;
1540  for (i = 0; i < argc; i++) {
1541  if (argv[i] == NULL)
1542  return POPT_ERROR_NOARG;
1543  nb += strlen(argv[i]) + 1;
1544  }
1545 
1546  dst = (char *) xmalloc(nb);
1547  if (dst == NULL) /* XXX can't happen */
1548  return POPT_ERROR_MALLOC;
1549  argv2 = (char **) dst;
1550  dst += (argc + 1) * sizeof(*argv);
1551 
1552  for (i = 0; i < argc; i++) {
1553  argv2[i] = dst;
1554  dst += strlen(strcpy(dst, argv[i])) + 1;
1555  }
1556  argv2[argc] = NULL;
1557 
1558  if (argvPtr) {
1559  *argvPtr = argv2;
1560  } else {
1561  free(argv2);
1562  argv2 = NULL;
1563  }
1564  if (argcPtr)
1565  *argcPtr = argc;
1566  return 0;
1567 }
1568 
1569 static int XpoptParseArgvString(const char * s, int * argcPtr, char *** argvPtr)
1570  /*@modifies *argcPtr, *argvPtr @*/
1571 {
1572  const char * src;
1573  char quote = '\0';
1574  int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
1575  char ** argv = (char **) xmalloc(sizeof(*argv) * argvAlloced);
1576  int argc = 0;
1577  size_t buflen = strlen(s) + 1;
1578  char * buf = (char *) memset(alloca(buflen), 0, buflen);
1579  int rc = POPT_ERROR_MALLOC;
1580 
1581  if (argv == NULL) return rc;
1582  argv[argc] = buf;
1583 
1584  for (src = s; *src != '\0'; src++) {
1585  if (quote == *src) {
1586  quote = '\0';
1587  } else if (quote != '\0') {
1588  if (*src == '\\') {
1589  src++;
1590  if (!*src) {
1591  rc = POPT_ERROR_BADQUOTE;
1592  goto exit;
1593  }
1594  if (*src != quote) *buf++ = '\\';
1595  }
1596  *buf++ = *src;
1597  } else if (isspace(*src)) {
1598  if (*argv[argc] != '\0') {
1599  buf++, argc++;
1600  if (argc == argvAlloced) {
1601  argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
1602  argv = (char **) realloc(argv, sizeof(*argv) * argvAlloced);
1603  if (argv == NULL) goto exit;
1604  }
1605  argv[argc] = buf;
1606  }
1607  } else switch (*src) {
1608  case '"':
1609  case '\'':
1610  quote = *src;
1611  /*@switchbreak@*/ break;
1612  case '\\':
1613  src++;
1614  if (!*src) {
1615  rc = POPT_ERROR_BADQUOTE;
1616  goto exit;
1617  }
1618  /*@fallthrough@*/
1619  default:
1620  *buf++ = *src;
1621  /*@switchbreak@*/ break;
1622  }
1623  }
1624 
1625  if (strlen(argv[argc])) {
1626  argc++, buf++;
1627  }
1628 
1629  rc = XpoptDupArgv(argc, argv, argcPtr, argvPtr);
1630 
1631 exit:
1632  if (argv) free(argv);
1633  return rc;
1634 }
1635 #endif /* !defined(DEBUG_MACROS) */
1636 
1644 #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)
1645 static char _FIXME_embedded_interpreter_eval_returned_null[] =
1646  "FIXME: embedded interpreter eval returned null.";
1647 static char * parseEmbedded(const char * s, size_t nb, char *** avp)
1648  /*@*/
1649 {
1650  char * script = NULL;
1651  const char * se;
1652 
1653  /* XXX FIXME: args might have embedded : too. */
1654  for (se = s + 1; se < (s+nb); se++)
1655  switch (*se) {
1656  default: continue; /*@notreached@*/ break;
1657  case ':': goto bingo; /*@notreached@*/ break;
1658  }
1659 
1660 bingo:
1661  { size_t na = (size_t)(se-s-1);
1662  char * args = NULL;
1663  int ac;
1664  int rc;
1665 
1666  args = (char *) memcpy(xmalloc(na+1), s+1, na);
1667  args[na] = '\0';
1668 
1669  ac = 0;
1670  rc = XpoptParseArgvString(args, &ac, avp);
1671  args = _free(args);
1672  nb -= na;
1673  }
1674 
1675  nb -= (nb >= (sizeof("{:}")-1) ? (sizeof("{:}")-1) : nb);
1676  script = (char *) memcpy(xmalloc(nb+1), se+1, nb+1);
1677  script[nb] = '\0';
1678  return script;
1679 }
1680 #endif
1681 
1688 static int
1690  /*@globals rpmGlobalMacroContext,
1691  print_macro_trace, print_expand_trace, h_errno,
1692  fileSystem, internalState @*/
1693  /*@modifies mb, rpmGlobalMacroContext,
1694  print_macro_trace, print_expand_trace,
1695  fileSystem, internalState @*/
1696 {
1697  MacroEntry *mep;
1698  MacroEntry me;
1699  const char *s = mb->s, *se;
1700  const char *f, *fe;
1701  const char *g, *ge;
1702  size_t fn, gn;
1703  char *t = mb->t; /* save expansion pointer for printExpand */
1704  int c;
1705  int rc = 0;
1706  int negate;
1707  int stackarray;
1708  const char * lastc;
1709  int chkexist;
1710 
1711  if (++mb->depth > max_macro_depth) {
1713  _("Recursion depth(%d) greater than max(%d)\n"),
1714  mb->depth, max_macro_depth);
1715  mb->depth--;
1716  mb->expand_trace = 1;
1717  return 1;
1718  }
1719 
1720  while (rc == 0 && mb->nb > 0 && (c = (int)*s) != (int)'\0') {
1721  s++;
1722  /* Copy text until next macro */
1723  switch(c) {
1724  case '%':
1725  if (*s != '\0') { /* Ensure not end-of-string. */
1726  if (*s != '%')
1727  /*@switchbreak@*/ break;
1728  s++; /* skip first % in %% */
1729  }
1730  /*@fallthrough@*/
1731  default:
1732  SAVECHAR(mb, c);
1733  continue;
1734  /*@notreached@*/ /*@switchbreak@*/ break;
1735  }
1736 
1737  /* Expand next macro */
1738  f = fe = NULL;
1739  g = ge = NULL;
1740  if (mb->depth > 1) /* XXX full expansion for outermost level */
1741  t = mb->t; /* save expansion pointer for printExpand */
1742  stackarray = chkexist = negate = 0;
1743  lastc = NULL;
1744  switch ((c = (int) *s)) {
1745  default: /* %name substitution */
1746  while (*s != '\0' && strchr("!?@", *s) != NULL) {
1747  switch(*s++) {
1748  case '@':
1749  stackarray = ((stackarray + 1) % 2);
1750  /*@switchbreak@*/ break;
1751  case '!':
1752  negate = ((negate + 1) % 2);
1753  /*@switchbreak@*/ break;
1754  case '?':
1755  chkexist++;
1756  /*@switchbreak@*/ break;
1757  }
1758  }
1759  f = se = s;
1760  if (*se == '-')
1761  se++;
1762  while((c = (int) *se) && (xisalnum(c) || c == (int) '_'))
1763  se++;
1764  /* Recognize non-alnum macros too */
1765  switch (*se) {
1766  case '*':
1767  se++;
1768  if (*se == '*') se++;
1769  /*@innerbreak@*/ break;
1770  case '#':
1771  se++;
1772  /*@innerbreak@*/ break;
1773  default:
1774  /*@innerbreak@*/ break;
1775  }
1776  fe = se;
1777  /* For "%name " macros ... */
1778 /*@-globs@*/
1779  if ((c = (int) *fe) && isblank(c))
1780  if ((lastc = strchr(fe,'\n')) == NULL)
1781  lastc = strchr(fe, '\0');
1782 /*@=globs@*/
1783  /*@switchbreak@*/ break;
1784  case '(': /* %(...) shell escape */
1785  if ((se = matchchar(s, (char)c, ')')) == NULL) {
1787  _("Unterminated %c: %s\n"), (char)c, s);
1788  rc = 1;
1789  continue;
1790  }
1791  if (mb->macro_trace)
1792  printMacro(mb, s, se+1);
1793 
1794  s++; /* skip ( */
1795  rc = doShellEscape(mb, s, (se - s));
1796  se++; /* skip ) */
1797 
1798  s = se;
1799  continue;
1800  /*@notreached@*/ /*@switchbreak@*/ break;
1801  case '{': /* %{...}/%{...:...} substitution */
1802  if ((se = matchchar(s, (char)c, '}')) == NULL) {
1804  _("Unterminated %c: %s\n"), (char)c, s);
1805  rc = 1;
1806  continue;
1807  }
1808  f = s+1;/* skip { */
1809  se++; /* skip } */
1810  while (strchr("!?@", *f) != NULL) {
1811  switch(*f++) {
1812  case '@':
1813  stackarray = ((stackarray + 1) % 2);
1814  /*@switchbreak@*/ break;
1815  case '!':
1816  negate = ((negate + 1) % 2);
1817  /*@switchbreak@*/ break;
1818  case '?':
1819  chkexist++;
1820  /*@switchbreak@*/ break;
1821  }
1822  }
1823  /* Find end-of-expansion, handle %{foo:bar} expansions. */
1824  for (fe = f; (c = (int) *fe) && !strchr(" :}", c);)
1825  fe++;
1826  switch (c) {
1827  case ':':
1828  g = fe + 1;
1829  ge = se - 1;
1830  /*@innerbreak@*/ break;
1831  case ' ':
1832  lastc = se-1;
1833  /*@innerbreak@*/ break;
1834  default:
1835  /*@innerbreak@*/ break;
1836  }
1837  /*@switchbreak@*/ break;
1838  }
1839 
1840  /* XXX Everything below expects fe > f */
1841  fn = (fe - f);
1842  gn = (ge - g);
1843  if ((fe - f) <= 0) {
1844 /* XXX Process % in unknown context */
1845  c = (int) '%'; /* XXX only need to save % */
1846  SAVECHAR(mb, c);
1847 #if 0
1849  _("A %% is followed by an unparseable macro\n"));
1850 #endif
1851  s = se;
1852  continue;
1853  }
1854 
1855  if (mb->macro_trace)
1856  printMacro(mb, s, se);
1857 
1858  /* Expand builtin macros */
1859  if (STREQ("load", f, fn)) {
1860  if (g != NULL) {
1861  char * mfn = strncpy((char *) alloca(gn + 1), g, gn);
1862  int xx;
1863  mfn[gn] = '\0';
1864  xx = rpmLoadMacroFile(NULL, mfn, _max_load_depth);
1865  /* Print failure iff %{load:...} or %{!?load:...} */
1866  if (xx != 0 && chkexist == negate)
1867  rpmlog(RPMLOG_ERR, _("%s: load macros failed\n"), mfn);
1868  }
1869  s = se;
1870  continue;
1871  }
1872  if (STREQ("global", f, fn)) {
1873  s = doDefine(mb, se, RMIL_GLOBAL, 1);
1874  continue;
1875  }
1876  if (STREQ("define", f, fn)) {
1877  s = doDefine(mb, se, mb->depth, 0);
1878  continue;
1879  }
1880  if (STREQ("undefine", f, fn)) {
1881  s = doUndefine(mb->mc, se);
1882  continue;
1883  }
1884  if (STREQ("unglobal", f, fn)) {
1885  s = doUnglobal(mb->mc, se);
1886  continue;
1887  }
1888 
1889  if (STREQ("echo", f, fn) ||
1890  STREQ("warn", f, fn) ||
1891  STREQ("error", f, fn)) {
1892  int waserror = 0;
1893  if (STREQ("error", f, fn))
1894  waserror = 1, rc = 1;
1895  if (g != NULL && g < ge)
1896  doOutput(mb, waserror, g, gn);
1897  else
1898  doOutput(mb, waserror, f, fn);
1899  s = se;
1900  continue;
1901  }
1902 
1903  if (STREQ("trace", f, fn)) {
1904  /* XXX TODO restore expand_trace/macro_trace to 0 on return */
1905  mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
1906  if (mb->depth == 1) {
1909  }
1910  s = se;
1911  continue;
1912  }
1913 
1914  if (STREQ("dump", f, fn)) {
1915  rpmDumpMacroTable(mb->mc, NULL);
1916  while (iseol(*se))
1917  se++;
1918  s = se;
1919  continue;
1920  }
1921 
1922 #ifdef WITH_LUA
1923  if (STREQ("lua", f, fn)) {
1924  rpmlua lua = rpmluaGetGlobalState();
1925  rpmlua olua = (rpmlua) memcpy(alloca(sizeof(*olua)), lua, sizeof(*olua));
1926  char *scriptbuf = (char *)xmalloc(gn);
1927  const char *printbuf;
1928 
1929  /* Reset the stateful output buffer before recursing down. */
1930  lua->storeprint = 1;
1931  lua->printbuf = NULL;
1932  lua->printbufsize = 0;
1933  lua->printbufused = 0;
1934 
1935  if (g != NULL && gn > 0)
1936  memcpy(scriptbuf, g, gn);
1937  scriptbuf[gn] = '\0';
1938  if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
1939  rc = 1;
1940  printbuf = rpmluaGetPrintBuffer(lua);
1941  if (printbuf) {
1942  size_t len = strlen(printbuf);
1943  if (len > mb->nb)
1944  len = mb->nb;
1945  memcpy(mb->t, printbuf, len);
1946  mb->t += len;
1947  mb->nb -= len;
1948  }
1949 
1950  /* Restore the stateful output buffer after recursion. */
1951  lua->storeprint = olua->storeprint;
1952  lua->printbuf = olua->printbuf;
1953  lua->printbufsize = olua->printbufsize;
1954  lua->printbufused = olua->printbufused;
1955 
1956  free(scriptbuf);
1957  s = se;
1958  continue;
1959  }
1960 #endif
1961 
1962 #ifdef WITH_AUGEAS
1963  if (STREQ("augeas", f, fn)) {
1964  /* XXX change rpmaugNew() to common embedded interpreter API */
1965 #ifdef NOTYET
1966  char ** av = NULL;
1967  char * script = parseEmbedded(s, (size_t)(se-s), &av);
1968 #else
1969  char * script = strndup(g, (size_t)(se-g-1));
1970 #endif
1971  rpmaug aug = (_globalI ? NULL
1973  const char * result = NULL;
1974 
1975  if (rpmaugRun(aug, script, &result) != RPMRC_OK)
1976  rc = 1;
1977  else {
1978  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
1979  if (result != NULL && *result != '\0') {
1980  size_t len = strlen(result);
1981  if (len > mb->nb)
1982  len = mb->nb;
1983  memcpy(mb->t, result, len);
1984  mb->t += len;
1985  mb->nb -= len;
1986  }
1987  }
1988  aug = rpmaugFree(aug);
1989 #ifdef NOTYET
1990  av = _free(av);
1991 #endif
1992  script = _free(script);
1993  s = se;
1994  continue;
1995  }
1996 #endif
1997 
1998 #ifdef WITH_FICL
1999  if (STREQ("ficl", f, fn)) {
2000  char ** av = NULL;
2001  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2002  rpmficl ficl = rpmficlNew(av, _globalI);
2003  const char * result = NULL;
2004 
2005  if (rpmficlRun(ficl, script, &result) != RPMRC_OK)
2006  rc = 1;
2007  else {
2008  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2009  if (result != NULL && *result != '\0') {
2010  size_t len = strlen(result);
2011  if (len > mb->nb)
2012  len = mb->nb;
2013  memcpy(mb->t, result, len);
2014  mb->t += len;
2015  mb->nb -= len;
2016  }
2017  }
2018  ficl = rpmficlFree(ficl);
2019  av = _free(av);
2020  script = _free(script);
2021  s = se;
2022  continue;
2023  }
2024 #endif
2025 
2026 #ifdef WITH_LIBGIT2
2027  if (STREQ("git", f, fn)) {
2028  char ** av = NULL;
2029  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2030  rpmgit git = rpmgitNew(av, _globalI, NULL);
2031  const char * result = NULL;
2032 
2033  if (rpmgitRun(git, script, &result) != RPMRC_OK)
2034  rc = 1;
2035  else {
2036  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2037  if (result != NULL && *result != '\0') {
2038  size_t len = strlen(result);
2039  if (len > mb->nb)
2040  len = mb->nb;
2041  memcpy(mb->t, result, len);
2042  mb->t += len;
2043  mb->nb -= len;
2044  }
2045  }
2046  git = rpmgitFree(git);
2047  av = _free(av);
2048  script = _free(script);
2049  s = se;
2050  continue;
2051  }
2052 #endif
2053 
2054 #ifdef WITH_GPSEE
2055  if (STREQ("js", f, fn)) {
2056  char ** av = NULL;
2057  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2058  rpmjs js = rpmjsNew(av, _globalI);
2059  const char * result = NULL;
2060 
2061  if (rpmjsRun(js, script, &result) != RPMRC_OK)
2062  rc = 1;
2063  else {
2064  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2065  if (result != NULL && *result != '\0') {
2066  size_t len = strlen(result);
2067  if (len > mb->nb)
2068  len = mb->nb;
2069  memcpy(mb->t, result, len);
2070  mb->t += len;
2071  mb->nb -= len;
2072  }
2073  }
2074  js = rpmjsFree(js);
2075  av = _free(av);
2076  script = _free(script);
2077  s = se;
2078  continue;
2079  }
2080 #endif
2081 
2082 #ifdef WITH_JNIEMBED
2083  if (STREQ("jni", f, fn) || STREQ("java", f, fn)) {
2084  char ** av = NULL;
2085  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2086  rpmjni jni = rpmjniNew(av, _globalI);
2087  const char * result = NULL;
2088 
2089  if (rpmjniRun(jni, script, &result) != RPMRC_OK)
2090  rc = 1;
2091  else {
2092  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2093  if (result != NULL && *result != '\0') {
2094  size_t len = strlen(result);
2095  if (len > mb->nb)
2096  len = mb->nb;
2097  memcpy(mb->t, result, len);
2098  mb->t += len;
2099  mb->nb -= len;
2100  }
2101  }
2102  jni = rpmjniFree(jni);
2103  av = _free(av);
2104  script = _free(script);
2105  s = se;
2106  continue;
2107  }
2108 #endif
2109 
2110 #ifdef WITH_MRBEMBED
2111  if (STREQ("mrb", f, fn) || STREQ("mruby", f, fn)) {
2112  char ** av = NULL;
2113  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2114  rpmmrb mrb = rpmmrbNew(av, _globalI);
2115  const char * result = NULL;
2116 
2117  if (rpmmrbRun(mrb, script, &result) != RPMRC_OK)
2118  rc = 1;
2119  else {
2120  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2121  if (result != NULL && *result != '\0') {
2122  size_t len = strlen(result);
2123  if (len > mb->nb)
2124  len = mb->nb;
2125  memcpy(mb->t, result, len);
2126  mb->t += len;
2127  mb->nb -= len;
2128  }
2129  }
2130  mrb = rpmmrbFree(mrb);
2131  av = _free(av);
2132  script = _free(script);
2133  s = se;
2134  continue;
2135  }
2136 #endif
2137 
2138 #ifdef WITH_NIX
2139  if (STREQ("nix", f, fn)) {
2140  char ** av = NULL;
2141  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2142  int (*_vec) (rpmnix nix) = rpmnixEcho;
2143  uint32_t _flags = RPMNIX_FLAGS_NONE;
2144  rpmnix nix;
2145  const char * result = NULL;
2146  int xx;
2147 
2148  if (av == NULL || av[0] == NULL || av[1] == NULL
2149  || !strcmp(av[0], "echo"))
2150  {
2151  _vec = rpmnixEcho;
2152  } else
2153  if (!strcmp(av[1], "build")) {
2154  _vec = rpmnixBuild;
2155  _flags = RPMNIX_FLAGS_NOOUTLINK;
2156  } else
2157  if (!strcmp(av[1], "channel")) {
2158  _vec = rpmnixChannel;
2159  } else
2160  if (!strcmp(av[1], "collect-garbage")) {
2161  _vec = rpmnixCollectGarbage;
2162  } else
2163  if (!strcmp(av[1], "copy-closure")) {
2164  _vec = rpmnixCopyClosure;
2165  } else
2166  if (!strcmp(av[1], "env")) {
2167  _vec = rpmnixEnv;
2168  } else
2169  if (!strcmp(av[1], "hash")) {
2170  _vec = rpmnixHash;
2171  } else
2172  if (!strcmp(av[1], "install-package")) {
2173  _vec = rpmnixInstallPackage;
2174  _flags = RPMNIX_FLAGS_INTERACTIVE;
2175  } else
2176  if (!strcmp(av[1], "instantiate")) {
2177  _vec = rpmnixInstantiate;
2178  } else
2179  if (!strcmp(av[1], "prefetch-url")) {
2180  _vec = rpmnixPrefetchURL;
2181  } else
2182  if (!strcmp(av[1], "push")) {
2183  _vec = rpmnixPush;
2184  } else
2185  if (!strcmp(av[1], "pull")) {
2186  _vec = rpmnixPull;
2187  } else
2188  if (!strcmp(av[1], "store")) {
2189  _vec = rpmnixStore;
2190  } else
2191  if (!strcmp(av[1], "worker")) {
2192  _vec = rpmnixWorker;
2193  } else
2194 assert(0);
2195 
2196  nix = rpmnixNew(av, _flags, NULL);
2197 
2198 #ifdef NOTYET
2199  if (rpmnixRun(nix, script, &result) != RPMRC_OK)
2200  rc = 1;
2201  else {
2202  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2203  if (result != NULL && *result != '\0') {
2204  size_t len = strlen(result);
2205  if (len > mb->nb)
2206  len = mb->nb;
2207  memcpy(mb->t, result, len);
2208  mb->t += len;
2209  mb->nb -= len;
2210  }
2211  }
2212 #else
2213  xx = (*_vec) (nix);
2214  result = xstrdup("");
2215 #endif /* NOTYET */
2216 
2217  nix = rpmnixFree(nix);
2218  av = _free(av);
2219  script = _free(script);
2220  s = se;
2221  continue;
2222  }
2223 #endif
2224 
2225 #ifdef WITH_PERLEMBED
2226  if (STREQ("perl", f, fn)) {
2227  char ** av = NULL;
2228  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2229  rpmperl perl = rpmperlNew(av, _globalI);
2230  const char * result = NULL;
2231 
2232  if (rpmperlRun(perl, script, &result) != RPMRC_OK)
2233  rc = 1;
2234  else {
2235  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2236  if (result != NULL && *result != '\0') {
2237  size_t len = strlen(result);
2238  if (len > mb->nb)
2239  len = mb->nb;
2240  memcpy(mb->t, result, len);
2241  mb->t += len;
2242  mb->nb -= len;
2243  }
2244  }
2245  perl = rpmperlFree(perl);
2246  av = _free(av);
2247  script = _free(script);
2248  s = se;
2249  continue;
2250  }
2251 #endif
2252 
2253 #ifdef WITH_PYTHONEMBED
2254  if (STREQ("python", f, fn)) {
2255  char ** av = NULL;
2256  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2257  rpmpython python = rpmpythonNew(av, _globalI);
2258  const char * result = NULL;
2259 
2260  if (rpmpythonRun(python, script, &result) != RPMRC_OK)
2261  rc = 1;
2262  else {
2263  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2264  if (result != NULL && *result != '\0') {
2265  size_t len = strlen(result);
2266  if (len > mb->nb)
2267  len = mb->nb;
2268  memcpy(mb->t, result, len);
2269  mb->t += len;
2270  mb->nb -= len;
2271  }
2272  }
2273  python = rpmpythonFree(python);
2274  av = _free(av);
2275  script = _free(script);
2276  s = se;
2277  continue;
2278  }
2279 #endif
2280 
2281 #ifdef WITH_RUBYEMBED
2282  if (STREQ("ruby", f, fn)) {
2283  char ** av = NULL;
2284  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2285  rpmruby ruby = rpmrubyNew(av, _globalI);
2286  const char * result = NULL;
2287 
2288  if (rpmrubyRun(ruby, script, &result) != RPMRC_OK)
2289  rc = 1;
2290  else {
2291  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2292  if (result != NULL && *result != '\0') {
2293  size_t len = strlen(result);
2294  if (len > mb->nb)
2295  len = mb->nb;
2296  memcpy(mb->t, result, len);
2297  mb->t += len;
2298  mb->nb -= len;
2299  }
2300  }
2301  ruby = rpmrubyFree(ruby);
2302  av = _free(av);
2303  script = _free(script);
2304  s = se;
2305  continue;
2306  }
2307 #endif
2308 
2309 #ifdef WITH_SEMANAGE
2310  if (STREQ("spook", f, fn)) {
2311  /* XXX change rpmsmNew() to common embedded interpreter API */
2312 #ifdef NOTYET
2313  char ** av = NULL;
2314  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2315 #else
2316  /* XXX use xstrndup (which never returns NULL) instead. */
2317  char * script = strndup(g, (size_t)(se-g-1));
2318  char * av[2];
2319  /* XXX FIXME */
2320  static const char * _rpmsmStore = "targeted";
2321  static unsigned int _rpmsmFlags = 0;
2322 #endif
2323  rpmsm sm = (_globalI ? NULL
2324  : rpmsmNew(_rpmsmStore, _rpmsmFlags));
2325  const char * result = NULL;
2326 
2327  /* XXX HACK: use an argv for now. */
2328  av[0] = script;
2329  av[1] = NULL;
2330  if (rpmsmRun(sm, av, &result) != RPMRC_OK)
2331  rc = 1;
2332  else {
2333  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2334  if (result != NULL && *result != '\0') {
2335  size_t len = strlen(result);
2336  if (len > mb->nb)
2337  len = mb->nb;
2338  memcpy(mb->t, result, len);
2339  mb->t += len;
2340  mb->nb -= len;
2341  }
2342  }
2343  sm = rpmsmFree(sm);
2344 #ifdef NOTYET
2345  av = _free(av);
2346 #endif
2347  script = _free(script);
2348  s = se;
2349  continue;
2350  }
2351 #endif
2352 
2353 #ifdef WITH_SQLITE
2354  if (STREQ("sql", f, fn)) {
2355  char ** av = NULL;
2356  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2357  rpmsql sql = rpmsqlNew(av, _globalI);
2358  const char * result = NULL;
2359 
2360  if (rpmsqlRun(sql, script, &result) != RPMRC_OK)
2361  rc = 1;
2362  else {
2363  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2364  if (result != NULL && *result != '\0') {
2365  size_t len = strlen(result);
2366  if (len > mb->nb)
2367  len = mb->nb;
2368  memcpy(mb->t, result, len);
2369  mb->t += len;
2370  mb->nb -= len;
2371  }
2372  }
2373  sql = rpmsqlFree(sql);
2374  av = _free(av);
2375  script = _free(script);
2376  s = se;
2377  continue;
2378  }
2379 #endif
2380 
2381 #ifdef WITH_SQUIRREL
2382  if (STREQ("squirrel", f, fn)) {
2383  char ** av = NULL;
2384  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2385  rpmsquirrel squirrel = rpmsquirrelNew(av, _globalI);
2386  const char * result = NULL;
2387 
2388  if (rpmsquirrelRun(squirrel, script, &result) != RPMRC_OK)
2389  rc = 1;
2390  else {
2391  if (result == NULL) result = _FIXME_embedded_interpreter_eval_returned_null;
2392  if (result != NULL && *result != '\0') {
2393  size_t len = strlen(result);
2394  if (len > mb->nb)
2395  len = mb->nb;
2396  memcpy(mb->t, result, len);
2397  mb->t += len;
2398  mb->nb -= len;
2399  }
2400  }
2401  squirrel = rpmsquirrelFree(squirrel);
2402  av = _free(av);
2403  script = _free(script);
2404  s = se;
2405  continue;
2406  }
2407 #endif
2408 
2409 #ifdef WITH_TCL
2410  if (STREQ("tcl", f, fn)) {
2411  char ** av = NULL;
2412  char * script = parseEmbedded(s, (size_t)(se-s), &av);
2413  rpmtcl tcl = rpmtclNew(av, _globalI);
2414  const char * result = NULL;
2415 
2416  if (rpmtclRun(tcl, script, &result) != RPMRC_OK)
2417  rc = 1;
2418  else if (result != NULL && *result != '\0') {
2419  size_t len = strlen(result);
2420  if (len > mb->nb)
2421  len = mb->nb;
2422  memcpy(mb->t, result, len);
2423  mb->t += len;
2424  mb->nb -= len;
2425  }
2426  tcl = rpmtclFree(tcl);
2427  av = _free(av);
2428  script = _free(script);
2429  s = se;
2430  continue;
2431  }
2432 #endif
2433 
2434  /* Rewrite "%patchNN ..." as "%patch -P NN ..." and expand. */
2435  if (lastc && fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) {
2436  /*@-internalglobs@*/ /* FIX: verbose may be set */
2437  doFoo(mb, negate, f, (lastc - f), NULL, 0);
2438  /*@=internalglobs@*/
2439  s = lastc;
2440  continue;
2441  }
2442 
2443  /* XXX necessary but clunky */
2444  if (STREQ("basename", f, fn) ||
2445  STREQ("dirname", f, fn) ||
2446  STREQ("realpath", f, fn) ||
2447  STREQ("getenv", f, fn) ||
2448  STREQ("shrink", f, fn) ||
2449  STREQ("suffix", f, fn) ||
2450  STREQ("expand", f, fn) ||
2451  STREQ("verbose", f, fn) ||
2452  STREQ("uncompress", f, fn) ||
2453  STREQ("mkstemp", f, fn) ||
2454  STREQ("mkdtemp", f, fn) ||
2455  STREQ("uuid", f, fn) ||
2456  STREQ("url2path", f, fn) ||
2457  STREQ("u2p", f, fn) ||
2458  STREQ("S", f, fn) ||
2459  STREQ("P", f, fn) ||
2460  STREQ("F", f, fn)) {
2461  /*@-internalglobs@*/ /* FIX: verbose may be set */
2462  doFoo(mb, negate, f, fn, g, gn);
2463  /*@=internalglobs@*/
2464  s = se;
2465  continue;
2466  }
2467 
2468  /* Expand defined macros */
2469  mep = findEntry(mb->mc, f, fn);
2470  me = (mep ? *mep : NULL);
2471 
2472  /* XXX Special processing for flags */
2473  if (*f == '-') {
2474  if (me)
2475  me->used++; /* Mark macro as used */
2476  if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */
2477  (me != NULL && negate)) { /* With -f, skip %{!-f...} */
2478  s = se;
2479  continue;
2480  }
2481 
2482  if (g && g < ge) { /* Expand X in %{-f:X} */
2483  rc = expandT(mb, g, gn);
2484  } else
2485  if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
2486  rc = expandT(mb, me->body, strlen(me->body));
2487  }
2488  s = se;
2489  continue;
2490  }
2491 
2492  /* XXX Special processing for macro existence */
2493  if (chkexist) {
2494  if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */
2495  (me != NULL && negate)) { /* With -f, skip %{!?f...} */
2496  s = se;
2497  continue;
2498  }
2499  if (g && g < ge) { /* Expand X in %{?f:X} */
2500  rc = expandT(mb, g, gn);
2501  } else
2502  if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
2503  rc = expandT(mb, me->body, strlen(me->body));
2504  }
2505  s = se;
2506  continue;
2507  }
2508 
2509  if (me == NULL) { /* leave unknown %... as is */
2510 #if !defined(RPM_VENDOR_WINDRIVER_DEBUG) /* XXX usually disabled */
2511 #if DEAD
2512  /* XXX hack to skip over empty arg list */
2513  if (fn == 1 && *f == '*') {
2514  s = se;
2515  continue;
2516  }
2517 #endif
2518  /* XXX hack to permit non-overloaded %foo to be passed */
2519  c = (int) '%'; /* XXX only need to save % */
2520  SAVECHAR(mb, c);
2521 #else
2522  if (!strncmp(f, "if", fn) ||
2523  !strncmp(f, "else", fn) ||
2524  !strncmp(f, "endif", fn)) {
2525  c = '%'; /* XXX only need to save % */
2526  SAVECHAR(mb, c);
2527  } else {
2529  _("Macro %%%.*s not found, skipping\n"), fn, f);
2530  s = se;
2531  }
2532 #endif
2533  continue;
2534  }
2535 
2536  /* XXX Special processing to create a tuple from stack'd values. */
2537  if (stackarray) {
2538  if (!(g && g < ge)) {
2539  g = "\n";
2540  gn = strlen(g);
2541  }
2542  rc = expandFIFO(mb, me, g, gn);
2543  s = se;
2544  continue;
2545  }
2546 
2547  /* Setup args for "%name " macros with opts */
2548  if (me && me->opts != NULL) {
2549  if (lastc != NULL) {
2550  se = grabArgs(mb, me, fe, lastc);
2551  } else {
2552  addMacro(mb->mc, "**", NULL, "", mb->depth);
2553  addMacro(mb->mc, "*", NULL, "", mb->depth);
2554  addMacro(mb->mc, "#", NULL, "0", mb->depth);
2555  addMacro(mb->mc, "0", NULL, me->name, mb->depth);
2556  }
2557  }
2558 
2559  /* Recursively expand body of macro */
2560  if (me->body && *me->body) {
2561  mb->s = me->body;
2562  rc = expandMacro(mb);
2563  if (rc == 0)
2564  me->used++; /* Mark macro as used */
2565  }
2566 
2567  /* Free args for "%name " macros with opts */
2568  if (me->opts != NULL)
2569  freeArgs(mb);
2570 
2571  s = se;
2572  }
2573 
2574  *mb->t = '\0';
2575  mb->s = s;
2576  mb->depth--;
2577  if (rc != 0 || mb->expand_trace)
2578  printExpansion(mb, t, mb->t);
2579  return rc;
2580 }
2581 
2582 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \
2583  !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */
2584 int rpmSecuritySaneFile(const char *filename)
2585 {
2586  struct stat sb;
2587  uid_t uid;
2588 
2589  if (stat(filename, &sb) == -1)
2590  return 1;
2591  uid = getuid();
2592  if (sb.st_uid != uid)
2593  return 0;
2594  if (!S_ISREG(sb.st_mode))
2595  return 0;
2596  if (sb.st_mode & (S_IWGRP|S_IWOTH))
2597  return 0;
2598  return 1;
2599 }
2600 #endif
2601 
2602 #if !defined(DEBUG_MACROS)
2603 /* =============================================================== */
2604 /*@unchecked@*/
2605 static int _debug = 0;
2606 
2607 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
2608 {
2609  int ac = 0;
2610  char ** av = NULL;
2611  int argc = 0;
2612  const char ** argv = NULL;
2613  char * globRoot = NULL;
2614 #ifdef ENABLE_NLS
2615  const char * old_collate = NULL;
2616  const char * old_ctype = NULL;
2617  const char * t;
2618 #endif
2619  size_t maxb, nb;
2620  size_t i;
2621  int j;
2622  int rc;
2623 
2624  rc = XpoptParseArgvString(patterns, &ac, &av);
2625  if (rc)
2626  return rc;
2627 #ifdef ENABLE_NLS
2628  t = setlocale(LC_COLLATE, NULL);
2629  if (t)
2630  old_collate = xstrdup(t);
2631  t = setlocale(LC_CTYPE, NULL);
2632  if (t)
2633  old_ctype = xstrdup(t);
2634  (void) setlocale(LC_COLLATE, "C");
2635  (void) setlocale(LC_CTYPE, "C");
2636 #endif
2637 
2638  if (av != NULL)
2639  for (j = 0; j < ac; j++) {
2640  const char * globURL;
2641  const char * path;
2642  int ut = urlPath(av[j], &path);
2643  glob_t gl;
2644 
2645  if (!Glob_pattern_p(av[j], 0) && strchr(path, '~') == NULL) {
2646  argv = (const char **) xrealloc(argv, (argc+2) * sizeof(*argv));
2647  argv[argc] = xstrdup(av[j]);
2648 if (_debug)
2649 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]);
2650  argc++;
2651  continue;
2652  }
2653 
2654  gl.gl_pathc = 0;
2655  gl.gl_pathv = NULL;
2656  rc = Glob(av[j], GLOB_TILDE, Glob_error, &gl);
2657  if (rc)
2658  goto exit;
2659 
2660  /* XXX Prepend the URL leader for globs that have stripped it off */
2661  maxb = 0;
2662  for (i = 0; i < gl.gl_pathc; i++) {
2663  if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
2664  maxb = nb;
2665  }
2666 
2667  nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0);
2668  maxb += nb;
2669  maxb += 1;
2670  globURL = globRoot = (char *) xmalloc(maxb);
2671 
2672  switch (ut) {
2673  case URL_IS_PATH:
2674  case URL_IS_DASH:
2675  strncpy(globRoot, av[j], nb);
2676  /*@switchbreak@*/ break;
2677  case URL_IS_HKP:
2678  case URL_IS_FTP:
2679  case URL_IS_HTTP:
2680  case URL_IS_HTTPS:
2681  case URL_IS_MONGO: /* XXX FIXME */
2682  case URL_IS_UNKNOWN:
2683  default:
2684  /*@switchbreak@*/ break;
2685  }
2686  globRoot += nb;
2687  *globRoot = '\0';
2688 if (_debug)
2689 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
2690 
2691  argv = (const char **) xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
2692 
2693  if (argv != NULL)
2694  for (i = 0; i < gl.gl_pathc; i++) {
2695  const char * globFile = &(gl.gl_pathv[i][0]);
2696  if (globRoot > globURL && globRoot[-1] == '/')
2697  while (*globFile == '/') globFile++;
2698  strcpy(globRoot, globFile);
2699 if (_debug)
2700 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
2701  argv[argc++] = xstrdup(globURL);
2702  }
2703  /*@-immediatetrans@*/
2704  Globfree(&gl);
2705  /*@=immediatetrans@*/
2706  globURL = _free(globURL);
2707  }
2708 
2709  if (argv != NULL && argc > 0) {
2710  argv[argc] = NULL;
2711  if (argvPtr)
2712  *argvPtr = argv;
2713  if (argcPtr)
2714  *argcPtr = argc;
2715  rc = 0;
2716  } else
2717  rc = 1;
2718 
2719 
2720 exit:
2721 #ifdef ENABLE_NLS
2722  if (old_collate) {
2723  (void) setlocale(LC_COLLATE, old_collate);
2724  old_collate = _free(old_collate);
2725  }
2726  if (old_ctype) {
2727  (void) setlocale(LC_CTYPE, old_ctype);
2728  old_ctype = _free(old_ctype);
2729  }
2730 #endif
2731  av = _free(av);
2732  if (rc || argvPtr == NULL) {
2733 /*@-dependenttrans -unqualifiedtrans@*/
2734  if (argv != NULL)
2735  for (j = 0; j < argc; j++)
2736  argv[j] = _free(argv[j]);
2737  argv = _free(argv);
2738 /*@=dependenttrans =unqualifiedtrans@*/
2739  }
2740  return rc;
2741 }
2742 #endif /* !defined(DEBUG_MACROS) */
2743 
2744 /* =============================================================== */
2745 
2746 int
2747 expandMacros(void * spec, MacroContext mc, char * sbuf, size_t slen)
2748 {
2749  MacroBuf mb = (MacroBuf) alloca(sizeof(*mb));
2750  char *tbuf;
2751  int rc;
2752 
2753  if (sbuf == NULL || slen == 0)
2754  return 0;
2755  if (mc == NULL) mc = rpmGlobalMacroContext;
2756 
2757  tbuf = (char *) alloca(slen + 1);
2758  tbuf[0] = '\0';
2759 
2760  mb->s = sbuf;
2761  mb->t = tbuf;
2762  mb->nb = slen;
2763  mb->depth = 0;
2766 
2767  mb->spec = spec; /* (future) %file expansion info */
2768  mb->mc = mc;
2769 
2770  rc = expandMacro(mb);
2771 
2772  tbuf[slen] = '\0';
2773  if (mb->nb == 0)
2774  rpmlog(RPMLOG_ERR, _("Macro expansion too big for target buffer\n"));
2775  else
2776  strncpy(sbuf, tbuf, (slen - mb->nb + 1));
2777 
2778  return rc;
2779 }
2780 
2781 void
2783  const char * n, const char * o, const char * b, int level)
2784 {
2785  MacroEntry * mep;
2786  const char * name = n;
2787 
2788  if (*name == '.') /* XXX readonly macros */
2789  name++;
2790  if (*name == '.') /* XXX readonly macros */
2791  name++;
2792 
2793  if (mc == NULL) mc = rpmGlobalMacroContext;
2794 
2795  /* If new name, expand macro table */
2796  if ((mep = findEntry(mc, name, 0)) == NULL) {
2797  if (mc->firstFree == mc->macrosAllocated)
2798  expandMacroTable(mc);
2799  if (mc->macroTable != NULL)
2800  mep = mc->macroTable + mc->firstFree++;
2801  }
2802 
2803  if (mep != NULL) {
2804  /* XXX permit "..foo" to be pushed over ".foo" */
2805  if (*mep && (*mep)->flags && !(n[0] == '.' && n[1] == '.')) {
2806  /* XXX avoid error message for %buildroot */
2807  if (strcmp((*mep)->name, "buildroot"))
2808  rpmlog(RPMLOG_ERR, _("Macro '%s' is readonly and cannot be changed.\n"), n);
2809  return;
2810  }
2811  /* Push macro over previous definition */
2812  pushMacro(mep, n, o, b, level);
2813 
2814  /* If new name, sort macro table */
2815  if ((*mep)->prev == NULL)
2816  sortMacroTable(mc);
2817  }
2818 }
2819 
2820 void
2821 delMacro(MacroContext mc, const char * n)
2822 {
2823  MacroEntry * mep;
2824 
2825  if (mc == NULL) mc = rpmGlobalMacroContext;
2826  /* If name exists, pop entry */
2827  if ((mep = findEntry(mc, n, 0)) != NULL) {
2828  popMacro(mep);
2829  /* If deleted name, sort macro table */
2830  if (!(mep && *mep))
2831  sortMacroTable(mc);
2832  }
2833 }
2834 
2835 void
2836 delMacroAll(MacroContext mc, const char * n)
2837 {
2838  MacroEntry * mep;
2839 
2840  if (mc == NULL) mc = rpmGlobalMacroContext;
2841  /* If name exists, pop entry */
2842  while ((mep = findEntry(mc, n, 0)) != NULL) {
2843  delMacro(mc, n);
2844  }
2845 }
2846 
2847 /*@-mustmod@*/ /* LCL: mc is modified through mb->mc, mb is abstract */
2848 int
2849 rpmDefineMacro(MacroContext mc, const char * macro, int level)
2850 {
2851  MacroBuf mb = (MacroBuf) alloca(sizeof(*mb));
2852 
2853  memset(mb, 0, sizeof(*mb));
2854  /* XXX just enough to get by */
2855  mb->mc = (mc ? mc : rpmGlobalMacroContext);
2856  (void) doDefine(mb, macro, level, 0);
2857  return 0;
2858 }
2859 /*@=mustmod@*/
2860 
2861 /*@-mustmod@*/ /* LCL: mc is modified through mb->mc, mb is abstract */
2862 int
2863 rpmUndefineMacro(MacroContext mc, const char * macro)
2864 {
2865  (void) doUndefine(mc ? mc : rpmGlobalMacroContext, macro);
2866  return 0;
2867 }
2868 /*@=mustmod@*/
2869 
2870 void
2872 {
2873 
2874  if (mc == NULL || mc == rpmGlobalMacroContext)
2875  return;
2876 
2877  if (mc->macroTable != NULL) {
2878  int i;
2879  for (i = 0; i < mc->firstFree; i++) {
2880  MacroEntry *mep, me;
2881  mep = &mc->macroTable[i];
2882  me = *mep;
2883 
2884  if (me == NULL) /* XXX this should never happen */
2885  continue;
2886  addMacro(NULL, me->name, me->opts, me->body, (level - 1));
2887  }
2888  }
2889 }
2890 
2891 #if defined(RPM_VENDOR_OPENPKG) /* expand-macrosfile-macro */
2892 static void expand_macrosfile_macro(const char *file_name, const char *buf, size_t bufn)
2893 {
2894  char *cp;
2895  size_t l, k;
2896  static const char *macro_name = "%{macrosfile}";
2897 
2898  l = strlen(macro_name);
2899  k = strlen(file_name);
2900  while ((cp = strstr(buf, macro_name)) != NULL) {
2901  if (((strlen(buf) - l) + k) < bufn) {
2902  memmove(cp+k, cp+l, strlen(cp+l)+1);
2903  memcpy(cp, file_name, k);
2904  }
2905  }
2906  return;
2907 }
2908 #endif
2909 
2910 int
2911 rpmLoadMacroFile(MacroContext mc, const char * fn, int nesting)
2912 {
2913  size_t bufn = _macro_BUFSIZ;
2914  char *buf = (char *) alloca(bufn);
2915  int lineno = 0;
2916  int rc = -1;
2917  FD_t fd;
2918  int xx;
2919 
2920  /* XXX TODO: teach rdcl() to read through a URI, eliminate ".fpio". */
2921  fd = Fopen(fn, "r.fpio");
2922  if (fd == NULL || Ferror(fd)) {
2923  if (fd) (void) Fclose(fd);
2924  return rc;
2925  }
2926 
2927  /* XXX Assume new fangled macro expansion */
2928  /*@-mods@*/
2930  /*@=mods@*/
2931 
2932  buf[0] = '\0';
2933  while(rdcl(buf, bufn, fd) != NULL) {
2934  char * s;
2935  int c;
2936 
2937  lineno++;
2938  s = buf;
2939  SKIPBLANK(s, c);
2940 
2941  if (c != (int) '%')
2942  continue;
2943 
2944  /* Parse %{load:...} immediately recursively. */
2945  if (s[1] == '{' && !strncmp(s+2, "load:", sizeof("load:")-1)) {
2946  char * se = (char *) matchchar(s, '{', '}');
2947  const char ** argv = NULL;
2948  int argc = 0;
2949  int i;
2950  if (se == NULL) {
2952  _("%s:%u Missing '}' in \"%s\", skipping.\n"),
2953  fn, lineno, buf);
2954  continue;
2955  }
2956  s += sizeof("%{load:") - 1;
2957  SKIPBLANK(s, c);
2958  *se = '\0';
2959  if (nesting <= 0) {
2961  _("%s:%u load depth exceeded, \"%s\" ignored.\n"),
2962  fn, lineno, buf);
2963  continue;
2964  }
2965  se = rpmMCExpand(mc, s, NULL);
2966  rc = rpmGlob(se, &argc, &argv);
2967  for(i = 0; i < argc; i++) {
2968  rc |= rpmLoadMacroFile(mc, argv[i], nesting - 1);
2969  argv[i] = _free(argv[i]);
2970  }
2971  argv = _free(argv);
2972  se = _free(se);
2973  if (rc != 0)
2974  goto exit;
2975  } else {
2976 #if defined(RPM_VENDOR_OPENPKG) /* expand-macro-source */
2977  expand_macrosfile_macro(fn, buf, bufn);
2978 #endif
2979  if (*s == '%') s++;
2980  rc = rpmDefineMacro(mc, s, RMIL_MACROFILES);
2981  }
2982  }
2983  rc = 0;
2984 exit:
2985  xx = Fclose(fd);
2986  return rc;
2987 }
2988 
2989 void
2990 rpmInitMacros(MacroContext mc, const char * macrofiles)
2991 {
2992  char *mfiles, *m, *me;
2993 
2994  if (macrofiles == NULL)
2995  return;
2996 #ifdef DYING
2997  if (mc == NULL) mc = rpmGlobalMacroContext;
2998 #endif
2999 
3000  mfiles = xstrdup(macrofiles);
3001  for (m = mfiles; m && *m != '\0'; m = me) {
3002  const char ** av;
3003  int ac;
3004  int i;
3005 
3006  for (me = m; (me = strchr(me, ':')) != NULL; me++) {
3007  /* Skip over URI's. */
3008  if (!(me[1] == '/' && me[2] == '/'))
3009  /*@innerbreak@*/ break;
3010  }
3011 
3012  if (me && *me == ':')
3013  *me++ = '\0';
3014  else
3015  me = m + strlen(m);
3016 
3017  /* Glob expand the macro file path element, expanding ~ to $HOME. */
3018  ac = 0;
3019  av = NULL;
3020 #if defined(DEBUG_MACROS)
3021  ac = 1;
3022  av = xmalloc((ac + 1) * sizeof(*av));
3023  av[0] = strdup(m);
3024  av[1] = NULL;
3025 #else
3026  i = rpmGlob(m, &ac, &av);
3027  if (i != 0)
3028  continue;
3029 #endif
3030 
3031  /* Read macros from each file. */
3032 
3033  for (i = 0; i < ac; i++) {
3034  size_t slen = strlen(av[i]);
3035  const char *fn = av[i];
3036 
3037  if (fn[0] == '@' /* attention */) {
3038  fn++;
3039 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \
3040  !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */
3041  if (!rpmSecuritySaneFile(fn))
3042 #else
3043  if (!poptSaneFile(fn))
3044 #endif
3045  {
3046  rpmlog(RPMLOG_WARNING, "existing RPM macros file \"%s\" considered INSECURE -- not loaded\n", fn);
3047  /*@innercontinue@*/ continue;
3048  }
3049  }
3050 
3051  /* Skip backup files and %config leftovers. */
3052 #define _suffix(_s, _x) \
3053  (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
3054  if (!(_suffix(fn, "~")
3055  || _suffix(fn, ".rpmnew")
3056  || _suffix(fn, ".rpmorig")
3057  || _suffix(fn, ".rpmsave"))
3058  )
3059  (void) rpmLoadMacroFile(mc, fn, _max_load_depth);
3060 #undef _suffix
3061 
3062  av[i] = _free(av[i]);
3063  }
3064  av = _free(av);
3065  }
3066  mfiles = _free(mfiles);
3067 
3068  /* Reload cmdline macros */
3069  /*@-mods@*/
3071  /*@=mods@*/
3072 }
3073 
3074 /*@-globstate@*/
3075 void
3077 {
3078 
3079  if (mc == NULL) mc = rpmGlobalMacroContext;
3080 
3081  if (mc->macroTable != NULL) {
3082  int i;
3083  for (i = 0; i < mc->firstFree; i++) {
3084  MacroEntry me;
3085  while ((me = mc->macroTable[i]) != NULL) {
3086  /* XXX cast to workaround const */
3087  /*@-onlytrans@*/
3088  if ((mc->macroTable[i] = me->prev) == NULL)
3089  me->name = _free(me->name);
3090  /*@=onlytrans@*/
3091  me->opts = _free(me->opts);
3092  me->body = _free(me->body);
3093  if (me) free(me);
3094  me = NULL;
3095  }
3096  }
3097  free(mc->macroTable);
3098  mc->macroTable = NULL;
3099  }
3100  memset(mc, 0, sizeof(*mc));
3101 }
3102 /*@=globstate@*/
3103 
3104 /* =============================================================== */
3105 int isCompressed(const char * file, rpmCompressedMagic * compressed)
3106 {
3107  FD_t fd;
3108  ssize_t nb;
3109  int rc = -1;
3110  unsigned char magic[13];
3111 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */
3112  size_t file_len;
3113 #endif
3114 
3115  *compressed = COMPRESSED_NOT;
3116 #if defined(RPM_VENDOR_PLD)
3117  /*
3118  * Workaround for misleading message:
3119  * error: File %PATCH666: No such file or directory
3120  * It happens when there is no "PatchXXX: " definition
3121  * and spec contains commented out %patchXXX macro
3122  * http://git.pld-linux.org/gitweb.cgi/packages/kernel.git/commitdiff/5d3a3ea257d7f88e59d0ad93c20cc8448fb42f3d
3123  */
3124  if ((strlen(file) > 6) && (strncasecmp(file, "%PATCH", 6) == 0))
3125  return 0;
3126 #endif
3127 
3128 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */
3129  file_len = strlen(file);
3130  if ((file_len > 4 && strcasecmp(file+file_len-4, ".tbz") == 0)
3131  || (file_len > 4 && strcasecmp(file+file_len-4, ".bz2") == 0)) {
3132  *compressed = COMPRESSED_BZIP2;
3133  return 0;
3134  } else
3135  if (file_len > 4 && strcasecmp(file+file_len-4, ".zip") == 0) {
3136  *compressed = COMPRESSED_ZIP;
3137  return 0;
3138  } else
3139  if ((file_len > 4 && strcasecmp(file+file_len-4, ".tlz") == 0)
3140  || (file_len > 5 && strcasecmp(file+file_len-5, ".lzma") == 0)) {
3141  *compressed = COMPRESSED_LZMA;
3142  return 0;
3143  } else
3144  if (file_len > 4 && strcasecmp(file+file_len-3, ".xz") == 0) {
3145  *compressed = COMPRESSED_XZ;
3146  return 0;
3147  } else
3148  if ((file_len > 4 && strcasecmp(file+file_len-4, ".tgz") == 0)
3149  || (file_len > 3 && strcasecmp(file+file_len-3, ".gz") == 0)
3150  || (file_len > 2 && strcasecmp(file+file_len-2, ".Z") == 0)) {
3151  *compressed = COMPRESSED_OTHER;
3152  return 0;
3153  } else
3154  if (file_len > 5 && strcasecmp(file+file_len-5, ".cpio") == 0) {
3155  *compressed = COMPRESSED_NOT;
3156  return 0;
3157  } else
3158  if (file_len > 4 && strcasecmp(file+file_len-4, ".tar") == 0) {
3159  *compressed = COMPRESSED_NOT;
3160  return 0;
3161  }
3162 #endif
3163 
3164  fd = Fopen(file, "r");
3165  if (fd == NULL || Ferror(fd)) {
3166  /* XXX Fstrerror */
3167  rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd));
3168  if (fd) (void) Fclose(fd);
3169  return 1;
3170  }
3171  nb = Fread(magic, sizeof(magic[0]), sizeof(magic), fd);
3172  if (nb < (ssize_t)0) {
3173  rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd));
3174  rc = 1;
3175  } else if (nb < (ssize_t)sizeof(magic)) {
3176  rpmlog(RPMLOG_ERR, _("File %s is smaller than %u bytes\n"),
3177  file, (unsigned)sizeof(magic));
3178  rc = 0;
3179  }
3180  (void) Fclose(fd);
3181  if (rc >= 0)
3182  return rc;
3183 
3184  rc = 0;
3185 
3186  if (magic[0] == 'B' && magic[1] == 'Z')
3187  *compressed = COMPRESSED_BZIP2;
3188  else
3189  if (magic[0] == (unsigned char) 0120 && magic[1] == (unsigned char) 0113
3190  && magic[2] == (unsigned char) 0003 && magic[3] == (unsigned char) 0004) /* pkzip */
3191  *compressed = COMPRESSED_ZIP;
3192  else
3193  if (magic[0] == (unsigned char) 0x89 && magic[1] == 'L'
3194  && magic[2] == 'Z' && magic[3] == 'O') /* lzop */
3195  *compressed = COMPRESSED_LZOP;
3196  else
3197 #if !defined(RPM_VENDOR_OPENPKG) && !defined(RPM_VENDOR_FEDORA) && !defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */
3198  /* XXX Ick, LZMA has no magic. See http://lkml.org/lkml/2005/6/13/285 */
3199  if (magic[ 9] == (unsigned char) 0x00 && magic[10] == (unsigned char) 0x00 &&
3200  magic[11] == (unsigned char) 0x00 && magic[12] == (unsigned char) 0x00) /* lzmash */
3201  *compressed = COMPRESSED_LZMA;
3202  else
3203 #endif
3204 #if defined(RPM_VENDOR_OPENSUSE)
3205  if (magic[0] == 0135 && magic[1] == 0 && magic[2] == 0) /* lzma */
3206  *compressed = COMPRESSED_LZMA;
3207  else
3208 #endif
3209  if (magic[0] == (unsigned char) 0xFD && magic[1] == 0x37 && magic[2] == 0x7A
3210  && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00) /* xz */
3211  *compressed = COMPRESSED_XZ;
3212  else if ((magic[0] == 'L') && (magic[1] == 'Z') &&
3213  (magic[2] == 'I') && (magic[3] == 'P')) /* lzip */
3214  *compressed = COMPRESSED_LZIP;
3215  else if ((magic[0] == 'L') && (magic[1] == 'R') &&
3216  (magic[2] == 'Z') && (magic[3] == 'I')) /* lrzip */
3217  *compressed = COMPRESSED_LRZIP;
3218  else if ((magic[0] == '7') && (magic[1] == 'z') &&
3219  (magic[2] == 0xbc) && (magic[3] == 0xaf) &&
3220  (magic[4] == 0x27) && (magic[5] == 0x1c)) /* 7zip */
3221  *compressed = COMPRESSED_7ZIP;
3222  else
3223  if ((magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0213) /* gzip */
3224  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0236) /* old gzip */
3225  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0036) /* pack */
3226  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0240) /* SCO lzh */
3227  || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0235)) /* compress */
3228  *compressed = COMPRESSED_OTHER;
3229 
3230  return rc;
3231 }
3232 
3233 /* =============================================================== */
3234 
3235 /*@-modfilesys@*/
3236 /* XXX TODO: merge rpmExpand and rpmMCExpand. gud enuf for now ... */
3237 char *
3238 rpmExpand(const char *arg, ...)
3239 {
3240  MacroContext mc = NULL;
3241  const char *s;
3242  char *t, *te;
3243  size_t sn, tn;
3244  size_t bufn = 8 * _macro_BUFSIZ;
3245 
3246  va_list ap;
3247 
3248  if (arg == NULL)
3249  return xstrdup("");
3250 
3251  t = (char *) xmalloc(bufn + strlen(arg) + 1);
3252  *t = '\0';
3253  te = stpcpy(t, arg);
3254 
3255  va_start(ap, arg);
3256  while ((s = va_arg(ap, const char *)) != NULL) {
3257  sn = strlen(s);
3258  tn = (te - t);
3259  t = (char *) xrealloc(t, tn + sn + bufn + 1);
3260  te = t + tn;
3261  te = stpcpy(te, s);
3262  }
3263  va_end(ap);
3264 
3265  *te = '\0';
3266  tn = (te - t);
3267  (void) expandMacros(NULL, mc, t, tn + bufn + 1);
3268  t[tn + bufn] = '\0';
3269  t = (char *) xrealloc(t, strlen(t) + 1);
3270 
3271  return t;
3272 }
3273 
3274 char *
3275 rpmMCExpand(MacroContext mc, const char *arg, ...)
3276 {
3277  const char *s;
3278  char *t, *te;
3279  size_t sn, tn;
3280  size_t bufn = 8 * _macro_BUFSIZ;
3281 
3282  va_list ap;
3283 
3284  if (arg == NULL)
3285  return xstrdup("");
3286 
3287  t = (char *) xmalloc(bufn + strlen(arg) + 1);
3288  *t = '\0';
3289  te = stpcpy(t, arg);
3290 
3291  va_start(ap, arg);
3292  while ((s = va_arg(ap, const char *)) != NULL) {
3293  sn = strlen(s);
3294  tn = (te - t);
3295  t = (char *) xrealloc(t, tn + sn + bufn + 1);
3296  te = t + tn;
3297  te = stpcpy(te, s);
3298  }
3299  va_end(ap);
3300 
3301  *te = '\0';
3302  tn = (te - t);
3303  (void) expandMacros(NULL, mc, t, tn + bufn + 1);
3304  t[tn + bufn] = '\0';
3305  t = (char *) xrealloc(t, strlen(t) + 1);
3306 
3307  return t;
3308 }
3309 /*@=modfilesys@*/
3310 
3311 int
3312 rpmExpandNumeric(const char *arg)
3313 {
3314  const char *val;
3315  int rc;
3316 
3317  if (arg == NULL)
3318  return 0;
3319 
3320  val = rpmExpand(arg, NULL);
3321  if (!(val && *val != '%'))
3322  rc = 0;
3323  else if (*val == 'Y' || *val == 'y')
3324  rc = 1;
3325  else if (*val == 'N' || *val == 'n')
3326  rc = 0;
3327  else {
3328  char *end;
3329  rc = strtol(val, &end, 0);
3330  if (!(end && *end == '\0'))
3331  rc = 0;
3332  }
3333  val = _free(val);
3334 
3335  return rc;
3336 }
3337 
3338 /* @todo "../sbin/./../bin/" not correct. */
3339 char *rpmCleanPath(char * path)
3340 {
3341  const char *s;
3342  char *se, *t, *te;
3343  int begin = 1;
3344 
3345  if (path == NULL)
3346  return NULL;
3347 
3348 /*fprintf(stderr, "*** RCP %s ->\n", path); */
3349  s = t = te = path;
3350  while (*s != '\0') {
3351 /*fprintf(stderr, "*** got \"%.*s\"\trest \"%s\"\n", (t-path), path, s); */
3352  switch(*s) {
3353  case ':': /* handle url's */
3354  if (s[1] == '/' && s[2] == '/') {
3355  *t++ = *s++;
3356  *t++ = *s++;
3357  /* XXX handle "file:///" */
3358  if (s[0] == '/') *t++ = *s++;
3359  te = t;
3360  /*@switchbreak@*/ break;
3361  }
3362  begin=1;
3363  /*@switchbreak@*/ break;
3364  case '/':
3365  /* Move parent dir forward */
3366  for (se = te + 1; se < t && *se != '/'; se++)
3367  {};
3368  if (se < t && *se == '/') {
3369  te = se;
3370 /*fprintf(stderr, "*** next pdir \"%.*s\"\n", (te-path), path); */
3371  }
3372  while (s[1] == '/')
3373  s++;
3374  while (t > te && t[-1] == '/')
3375  t--;
3376  /*@switchbreak@*/ break;
3377  case '.':
3378  /* Leading .. is special */
3379  /* Check that it is ../, so that we don't interpret */
3380  /* ..?(i.e. "...") or ..* (i.e. "..bogus") as "..". */
3381  /* in the case of "...", this ends up being processed*/
3382  /* as "../.", and the last '.' is stripped. This */
3383  /* would not be correct processing. */
3384  if (begin && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
3385 /*fprintf(stderr, " leading \"..\"\n"); */
3386  *t++ = *s++;
3387  /*@switchbreak@*/ break;
3388  }
3389  /* Single . is special */
3390  if (begin && s[1] == '\0') {
3391  /*@switchbreak@*/ break;
3392  }
3393  if (t > path && t[-1] == '/')
3394  switch (s[1]) {
3395  case '/': s++; /*@fallthrough@*/ /* Trim embedded ./ */
3396  case '\0': s++; continue; /* Trim trailing /. */
3397  default: /*@innerbreak@*/ break;
3398  }
3399  /* Trim embedded /../ and trailing /.. */
3400  if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
3401  t = te;
3402  /* Move parent dir forward */
3403  if (te > path)
3404  for (--te; te > path && *te != '/'; te--)
3405  {};
3406 /*fprintf(stderr, "*** prev pdir \"%.*s\"\n", (te-path), path); */
3407  s++;
3408  s++;
3409  continue;
3410  }
3411  /*@switchbreak@*/ break;
3412  default:
3413  begin = 0;
3414  /*@switchbreak@*/ break;
3415  }
3416  *t++ = *s++;
3417  }
3418 
3419  /* Trim trailing / (but leave single / alone) */
3420  if (t > &path[1] && t[-1] == '/')
3421  t--;
3422  *t = '\0';
3423 
3424 /*fprintf(stderr, "\t%s\n", path); */
3425  return path;
3426 }
3427 
3428 /* Return concatenated and expanded canonical path. */
3429 
3430 char *
3431 rpmGetPath(const char *path, ...)
3432 {
3433  size_t bufn = _macro_BUFSIZ;
3434  char *buf = (char *) alloca(bufn);
3435  const char * s;
3436  char * t, * te;
3437  int slashed = 0;
3438  va_list ap;
3439 
3440  if (path == NULL)
3441  return xstrdup("");
3442 
3443  buf[0] = '\0';
3444  t = buf;
3445  te = stpcpy(t, path);
3446  *te = '\0';
3447 
3448  va_start(ap, path);
3449  while ((s = va_arg(ap, const char *)) != NULL) {
3450  /* Specifically requested pesky trailing '/'? */
3451  slashed = (s[0] == '/' && s[1] == '\0');
3452  te = stpcpy(te, s);
3453  }
3454  va_end(ap);
3455  *te = '\0';
3456 
3457 /*@-modfilesys@*/
3458  (void) expandMacros(NULL, NULL, buf, bufn);
3459 /*@=modfilesys@*/
3460 
3461  /* Note: rpmCleanPath will strip pesky trailing '/'. */
3462  (void) rpmCleanPath(buf);
3463 
3464  /* Re-append specifically requested pesky trailing '/'. */
3465  if (slashed) {
3466  size_t nb = strlen(buf);
3467  if (buf[nb-1] != '/')
3468  buf[nb++] = '/';
3469  buf[nb] = '\0';
3470  }
3471 
3472  return DRD_xstrdup(buf); /* XXX xstrdup has side effects. */
3473 }
3474 
3475 /* Merge 3 args into path, any or all of which may be a url. */
3476 
3477 const char * rpmGenPath(const char * urlroot, const char * urlmdir,
3478  const char *urlfile)
3479 {
3480 /*@owned@*/ const char * xroot = rpmGetPath(urlroot, NULL);
3481 /*@dependent@*/ const char * root = xroot;
3482 /*@owned@*/ const char * xmdir = rpmGetPath(urlmdir, NULL);
3483 /*@dependent@*/ const char * mdir = xmdir;
3484 /*@owned@*/ const char * xfile = rpmGetPath(urlfile, NULL);
3485 /*@dependent@*/ const char * file = xfile;
3486  const char * result;
3487  const char * url = NULL;
3488  size_t nurl = 0;
3489  int ut;
3490 
3491 #if 0
3492 if (_debug) fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile);
3493 #endif
3494  ut = urlPath(xroot, &root);
3495  if (url == NULL && ut > URL_IS_DASH) {
3496  url = xroot;
3497  nurl = strlen(url);
3498  if (root >= url && root <= url+nurl)
3499  nurl -= strlen(root);
3500 #if 0
3501 if (_debug) fprintf(stderr, "*** RGP ut %d root %s nurl %u\n", ut, root, (unsigned)nurl);
3502 #endif
3503  }
3504  if (root == NULL || *root == '\0') root = "/";
3505 
3506  ut = urlPath(xmdir, &mdir);
3507  if (url == NULL && ut > URL_IS_DASH) {
3508  url = xmdir;
3509  nurl = strlen(url);
3510  if (mdir >= url && mdir <= url+nurl)
3511  nurl -= strlen(mdir);
3512 #if 0
3513 if (_debug) fprintf(stderr, "*** RGP ut %d mdir %s nurl %u\n", ut, mdir, (unsigned)nurl);
3514 #endif
3515  }
3516  if (mdir == NULL || *mdir == '\0') mdir = "/";
3517 
3518  ut = urlPath(xfile, &file);
3519  if (url == NULL && ut > URL_IS_DASH) {
3520  url = xfile;
3521  nurl = strlen(url);
3522  if (file >= url && file <= url+nurl)
3523  nurl -= strlen(file);
3524 #if 0
3525 if (_debug) fprintf(stderr, "*** RGP ut %d file %s nurl %u\n", ut, file, (unsigned)nurl);
3526 #endif
3527  }
3528 
3529  if (url && nurl > 0) {
3530  char *t = strncpy((char *)alloca(nurl+1), url, nurl);
3531  t[nurl] = '\0';
3532  url = t;
3533  } else
3534  url = "";
3535 
3536  result = rpmGetPath(url, root, "/", mdir, "/", file, NULL);
3537 
3538  xroot = _free(xroot);
3539  xmdir = _free(xmdir);
3540  xfile = _free(xfile);
3541 #if 0
3542 if (_debug) fprintf(stderr, "*** RGP result %s\n", result);
3543 #endif
3544  return result;
3545 }
3546 
3547 /* =============================================================== */
3548 
3549 #if defined(DEBUG_MACROS)
3550 
3551 #if defined(EVAL_MACROS)
3552 
3553 const char *rpmMacrofiles = MACROFILES;
3554 
3555 int
3556 main(int argc, char *argv[])
3557 {
3558  int c;
3559  int errflg = 0;
3560  extern char *optarg;
3561  extern int optind;
3562 
3563  while ((c = getopt(argc, argv, "f:")) != EOF ) {
3564  switch (c) {
3565  case 'f':
3566  rpmMacrofiles = optarg;
3567  break;
3568  case '?':
3569  default:
3570  errflg++;
3571  break;
3572  }
3573  }
3574  if (errflg || optind >= argc) {
3575  fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
3576  exit(1);
3577  }
3578 
3579  rpmInitMacros(NULL, rpmMacrofiles);
3580  /* XXX getopt(3) also used for parametrized macros, expect scwewiness. */
3581  for ( ; optind < argc; optind++) {
3582  const char *val;
3583 
3584  val = rpmExpand(argv[optind], NULL);
3585  if (val) {
3586  fprintf(stdout, "%s:\t%s\n", argv[optind], val);
3587  val = _free(val);
3588  }
3589  }
3590  rpmFreeMacros(NULL);
3591  return 0;
3592 }
3593 
3594 #else /* !EVAL_MACROS */
3595 
3596 const char *rpmMacrofiles = "../macros:./testmacros";
3597 const char *testfile = "./test";
3598 
3599 int
3600 main(int argc, char *argv[])
3601 {
3602  size_t bufn = _macro_BUFSIZ;
3603  char *buf = (char *) alloca(bufn);
3604  FILE *fp;
3605  int x;
3606 
3607  rpmInitMacros(NULL, rpmMacrofiles);
3608 
3609  if ((fp = fopen(testfile, "r")) != NULL) {
3610  while(rdcl(buf, bufn, fp)) {
3611  x = expandMacros(NULL, NULL, buf, bufn);
3612  fprintf(stderr, "%d->%s\n", x, buf);
3613  memset(buf, 0, bufn);
3614  }
3615  fclose(fp);
3616  }
3617 
3618  while(rdcl(buf, bufn, stdin)) {
3619  x = expandMacros(NULL, NULL, buf, bufn);
3620  fprintf(stderr, "%d->%s\n <-\n", x, buf);
3621  memset(buf, 0, bufn);
3622  }
3623  rpmFreeMacros(NULL);
3624 
3625  return 0;
3626 }
3627 #endif /* EVAL_MACROS */
3628 #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:2990
void rpmFreeMacros(MacroContext mc)
Destroy macro context.
Definition: macro.c:3076
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:1273
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:3105
char * getenv(const char *name)
static const char * doUnglobal(MacroContext mc, const char *se)
Parse (and execute) macro undefinition.
Definition: macro.c:909
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:3339
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:2833
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:3431
void rpmLoadMacros(MacroContext mc, int level)
Load macros from specific context into global context.
Definition: macro.c:2871
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)
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:2836
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:962
static const char * doUndefine(MacroContext mc, const char *se)
Parse (and execute) macro undefinition.
Definition: macro.c:874
#define POPT_ARGV_ARRAY_GROW_DELTA
Definition: macro.c:1527
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:2782
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:1503
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:997
unsigned int _rpmaugFlags
Definition: rpmaug.c:80
static int XpoptDupArgv(int argc, char **argv, int *argcPtr, char ***argvPtr)
Definition: macro.c:1529
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:2607
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:2821
#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:2849
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:1524
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:3477
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:3238
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:1569
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:1071
static int expandMacro(MacroBuf mb)
Parse args and string for PHP like %{foo : } syntax.
Definition: macro.c:1689
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:1525
#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:2944
rpmsql rpmsqlFree(rpmsql sql)
Destroy a sql interpreter.
#define POPT_ERROR_NOARG
Definition: macro.c:1523
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:739
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:1247
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:1020
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:2584
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:2605
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:2747
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:2911
#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:3312
#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:2863
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:3275