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