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