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