00001
00005 #include "system.h"
00006 #include <stdarg.h>
00007
00008 #if !defined(isblank)
00009 #define isblank(_c) ((char)(_c) == ' ' || (char)(_c) == '\t')
00010 #endif
00011 #define iseol(_c) ((char)(_c) == '\n' || (char)(_c) == '\r')
00012
00013 #define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && !strncmp((_t), (_f), (_fn)))
00014
00015 #ifdef DEBUG_MACROS
00016 #undef WITH_LUA
00017 #include <sys/types.h>
00018 #include <errno.h>
00019 #include <fcntl.h>
00020 #include <getopt.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <popt.h>
00026
00027 #define rpmlog fprintf
00028 #define RPMLOG_ERR stderr
00029 #define RPMLOG_WARNING stderr
00030 #undef _
00031 #define _(x) x
00032
00033 #define vmefail(_nb) (exit(1), NULL)
00034 #define URL_IS_DASH 1
00035 #define URL_IS_PATH 2
00036 #define urlPath(_xr, _r) (*(_r) = (_xr), URL_IS_PATH)
00037 #define xisalnum(_c) isalnum(_c)
00038 #define xisalpha(_c) isalpha(_c)
00039 #define xisdigit(_c) isdigit(_c)
00040 #define xisspace(_c) isspace(_c)
00041
00042 typedef FILE * FD_t;
00043 #define Fopen(_path, _fmode) fopen(_path, "r");
00044 #define Ferror ferror
00045 #define Fstrerror(_fd) strerror(errno)
00046 #define Fread fread
00047 #define Fclose fclose
00048
00049 #define fdGetFILE(_fd) (_fd)
00050
00051 static inline void *
00052 _free( const void * p)
00053
00054 {
00055 if (p != NULL) free((void *)p);
00056 return NULL;
00057 }
00058
00059 #else
00060
00061
00062 const char * rpmMacrofiles = MACROFILES;
00063
00064 #include <rpmio_internal.h>
00065 #include <rpmlog.h>
00066 #include <mire.h>
00067
00068 #ifdef WITH_LUA
00069 #define _RPMLUA_INTERNAL
00070 #include <rpmlua.h>
00071 #endif
00072
00073 #include <rpmficl.h>
00074 #include <rpmjs.h>
00075 #include <rpmperl.h>
00076 #include <rpmpython.h>
00077 #include <rpmruby.h>
00078 #include <rpmtcl.h>
00079
00080 #endif
00081
00082 #include <rpmuuid.h>
00083
00084 #define _MACRO_INTERNAL
00085 #include <rpmmacro.h>
00086
00087 #include "debug.h"
00088
00089
00090 #if defined(WITH_FICL) || defined(WITH_JS) || defined(WITH_PERLEMBED) || defined(WITH_PYTHONEMBED) || defined(WITH_RUBYEMBED) || defined(WITH_TCL)
00091 static int _globalI = 1;
00092 #endif
00093
00094 #if defined(__LCLINT__)
00095
00096 extern const unsigned short int **__ctype_b_loc (void) ;
00097
00098 #endif
00099
00100
00101
00102
00103
00104
00105
00106
00107 static struct MacroContext_s rpmGlobalMacroContext_s;
00108
00109 MacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
00110
00111
00112 static struct MacroContext_s rpmCLIMacroContext_s;
00113
00114 MacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
00115
00116
00120 typedef struct MacroBuf_s {
00121
00122 const char * s;
00123
00124 char * t;
00125 size_t nb;
00126 int depth;
00127 int macro_trace;
00128 int expand_trace;
00129
00130 void * spec;
00131
00132 MacroContext mc;
00133 } * MacroBuf;
00134
00135 #define SAVECHAR(_mb, _c) { *(_mb)->t = (char) (_c), (_mb)->t++, (_mb)->nb--; }
00136
00137
00138
00139 #define _MAX_MACRO_DEPTH 16
00140
00141 int max_macro_depth = _MAX_MACRO_DEPTH;
00142
00143 #define _PRINT_MACRO_TRACE 0
00144
00145 int print_macro_trace = _PRINT_MACRO_TRACE;
00146
00147 #define _PRINT_EXPAND_TRACE 0
00148
00149 int print_expand_trace = _PRINT_EXPAND_TRACE;
00150
00151
00152 #define MACRO_CHUNK_SIZE 16
00153
00154
00155
00156 static size_t _macro_BUFSIZ = 16 * 1024;
00157
00158
00159 static int expandMacro(MacroBuf mb)
00160
00161
00162
00163
00164
00165 ;
00166
00167
00168
00175 static int
00176 compareMacroName(const void * ap, const void * bp)
00177
00178 {
00179 MacroEntry ame = *((MacroEntry *)ap);
00180 MacroEntry bme = *((MacroEntry *)bp);
00181
00182 if (ame == NULL && bme == NULL)
00183 return 0;
00184 if (ame == NULL)
00185 return 1;
00186 if (bme == NULL)
00187 return -1;
00188 return strcmp(ame->name, bme->name);
00189 }
00190
00195 static void
00196 expandMacroTable(MacroContext mc)
00197
00198 {
00199 if (mc->macroTable == NULL) {
00200 mc->macrosAllocated = MACRO_CHUNK_SIZE;
00201 mc->macroTable = (MacroEntry *)
00202 xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
00203 mc->firstFree = 0;
00204 } else {
00205 mc->macrosAllocated += MACRO_CHUNK_SIZE;
00206 mc->macroTable = (MacroEntry *)
00207 xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
00208 mc->macrosAllocated);
00209 }
00210 memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
00211 }
00212
00217 static void
00218 sortMacroTable(MacroContext mc)
00219
00220 {
00221 int i;
00222
00223 if (mc == NULL || mc->macroTable == NULL)
00224 return;
00225
00226 qsort(mc->macroTable, mc->firstFree, sizeof(mc->macroTable[0]),
00227 compareMacroName);
00228
00229
00230 for (i = 0; i < mc->firstFree; i++) {
00231 if (mc->macroTable[i] != NULL)
00232 continue;
00233 mc->firstFree = i;
00234 break;
00235 }
00236 }
00237
00238 #if !defined(DEBUG_MACROS)
00239
00240 static char * dupMacroEntry(MacroEntry me)
00241
00242 {
00243 char * t, * te;
00244 size_t nb;
00245
00246 assert(me != NULL);
00247 nb = strlen(me->name) + sizeof("%") - 1;
00248 if (me->opts)
00249 nb += strlen(me->opts) + sizeof("()") - 1;
00250 if (me->body)
00251 nb += strlen(me->body) + sizeof("\t") - 1;
00252 nb++;
00253
00254 t = te = xmalloc(nb);
00255 *te = '\0';
00256 te = stpcpy( stpcpy(te, "%"), me->name);
00257 if (me->opts)
00258 te = stpcpy( stpcpy( stpcpy(te, "("), me->opts), ")");
00259 if (me->body)
00260 te = stpcpy( stpcpy(te, "\t"), me->body);
00261 *te = '\0';
00262
00263 return t;
00264 }
00265 #endif
00266
00267 void
00268 rpmDumpMacroTable(MacroContext mc, FILE * fp)
00269 {
00270 int nempty = 0;
00271 int nactive = 0;
00272
00273 if (mc == NULL) mc = rpmGlobalMacroContext;
00274 if (fp == NULL) fp = stderr;
00275
00276 fprintf(fp, "========================\n");
00277 if (mc->macroTable != NULL) {
00278 int i;
00279 for (i = 0; i < mc->firstFree; i++) {
00280 MacroEntry me;
00281 if ((me = mc->macroTable[i]) == NULL) {
00282
00283 nempty++;
00284 continue;
00285 }
00286 fprintf(fp, "%3d%c %s", me->level,
00287 (me->used > 0 ? '=' : ':'), me->name);
00288 if (me->opts && *me->opts)
00289 fprintf(fp, "(%s)", me->opts);
00290 if (me->body && *me->body)
00291 fprintf(fp, "\t%s", me->body);
00292 fprintf(fp, "\n");
00293 nactive++;
00294 }
00295 }
00296 fprintf(fp, _("======================== active %d empty %d\n"),
00297 nactive, nempty);
00298 }
00299
00300 #if !defined(DEBUG_MACROS)
00301 int
00302 rpmGetMacroEntries(MacroContext mc, void * _mire, int used,
00303 const char *** avp)
00304 {
00305
00306 miRE mire = (miRE) _mire;
00307
00308 const char ** av;
00309 int ac = 0;
00310 int i;
00311
00312 if (mc == NULL)
00313 mc = rpmGlobalMacroContext;
00314
00315 if (avp == NULL)
00316 return mc->firstFree;
00317
00318 av = xcalloc( (mc->firstFree+1), sizeof(mc->macroTable[0]));
00319 if (mc->macroTable != NULL)
00320 for (i = 0; i < mc->firstFree; i++) {
00321 MacroEntry me;
00322 me = mc->macroTable[i];
00323 if (used > 0 && me->used < used)
00324 continue;
00325 if (used == 0 && me->used != 0)
00326 continue;
00327 #if !defined(DEBUG_MACROS)
00328 if (mire != NULL && mireRegexec(mire, me->name, 0) < 0)
00329 continue;
00330 #endif
00331 av[ac++] = dupMacroEntry(me);
00332 }
00333 av[ac] = NULL;
00334 *avp = av = xrealloc(av, (ac+1) * sizeof(*av));
00335
00336 return ac;
00337 }
00338 #endif
00339
00347
00348 static MacroEntry *
00349 findEntry(MacroContext mc, const char * name, size_t namelen)
00350
00351 {
00352 MacroEntry key, *ret;
00353
00354
00355 if (mc == NULL) mc = rpmGlobalMacroContext;
00356
00357 if (mc->macroTable == NULL || mc->firstFree == 0)
00358 return NULL;
00359
00360 if (namelen > 0) {
00361 char * t = strncpy(alloca(namelen + 1), name, namelen);
00362 t[namelen] = '\0';
00363 name = t;
00364 }
00365
00366 key = memset(alloca(sizeof(*key)), 0, sizeof(*key));
00367
00368 key->name = (char *)name;
00369
00370 ret = (MacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
00371 sizeof(*(mc->macroTable)), compareMacroName);
00372
00373 return ret;
00374 }
00375
00376
00377
00385
00386 static char *
00387 rdcl( char * buf, size_t size, FD_t fd)
00388
00389
00390 {
00391 char *q = buf - 1;
00392 size_t nb = 0;
00393 size_t nread = 0;
00394 FILE * f = fdGetFILE(fd);
00395 int pc = 0, bc = 0;
00396 char *p = buf;
00397
00398 if (f != NULL)
00399 do {
00400 *(++q) = '\0';
00401 if (fgets(q, (int)size, f) == NULL)
00402 break;
00403 nb = strlen(q);
00404 nread += nb;
00405 for (q += nb - 1; nb > 0 && iseol(*q); q--)
00406 nb--;
00407 for (; p <= q; p++) {
00408 switch (*p) {
00409 case '\\':
00410 switch (*(p+1)) {
00411 case '\r': break;
00412 case '\n': break;
00413 case '\0': break;
00414 default: p++; break;
00415 }
00416 break;
00417 case '%':
00418 switch (*(p+1)) {
00419 case '{': p++, bc++; break;
00420 case '(': p++, pc++; break;
00421 case '%': p++; break;
00422 }
00423 break;
00424 case '{': if (bc > 0) bc++; break;
00425 case '}': if (bc > 0) bc--; break;
00426 case '(': if (pc > 0) pc++; break;
00427 case ')': if (pc > 0) pc--; break;
00428 }
00429 }
00430 if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
00431 *(++q) = '\0';
00432 break;
00433 }
00434 q++; p++; nb++;
00435 size -= nb;
00436 if (*q == '\r')
00437 *q = '\n';
00438 } while (size > 0);
00439 return (nread > 0 ? buf : NULL);
00440 }
00441
00449
00450 static const char *
00451 matchchar(const char * p, char pl, char pr)
00452
00453 {
00454 int lvl = 0;
00455 char c;
00456
00457 while ((c = *p++) != '\0') {
00458 if (c == '\\') {
00459 p++;
00460 continue;
00461 }
00462 if (c == pr) {
00463 if (--lvl <= 0) return --p;
00464 } else if (c == pl)
00465 lvl++;
00466 }
00467 return (const char *)NULL;
00468 }
00469
00476 static void
00477 printMacro(MacroBuf mb, const char * s, const char * se)
00478
00479
00480 {
00481 const char *senl;
00482 const char *ellipsis;
00483 int choplen;
00484
00485 if (s >= se) {
00486 fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
00487 (2 * mb->depth + 1), "");
00488 return;
00489 }
00490
00491 if (s[-1] == '{')
00492 s--;
00493
00494
00495 for (senl = se; *senl && !iseol(*senl); senl++)
00496 {};
00497
00498
00499 choplen = 61 - (2 * mb->depth);
00500 if ((senl - s) > choplen) {
00501 senl = s + choplen;
00502 ellipsis = "...";
00503 } else
00504 ellipsis = "";
00505
00506
00507 fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
00508 (2 * mb->depth + 1), "", (int)(se - s), s);
00509 if (se[1] != '\0' && (senl - (se+1)) > 0)
00510 fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
00511 fprintf(stderr, "\n");
00512 }
00513
00520 static void
00521 printExpansion(MacroBuf mb, const char * t, const char * te)
00522
00523
00524 {
00525 const char *ellipsis;
00526 int choplen;
00527
00528 if (!(te > t)) {
00529 fprintf(stderr, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
00530 return;
00531 }
00532
00533
00534 while (te > t && iseol(te[-1]))
00535 te--;
00536 ellipsis = "";
00537 if (mb->depth > 0) {
00538 const char *tenl;
00539
00540
00541 while ((tenl = strchr(t, '\n')) && tenl < te)
00542 t = ++tenl;
00543
00544
00545 choplen = 61 - (2 * mb->depth);
00546 if ((te - t) > choplen) {
00547 te = t + choplen;
00548 ellipsis = "...";
00549 }
00550 }
00551
00552 fprintf(stderr, "%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
00553 if (te > t)
00554 fprintf(stderr, "%.*s%s", (int)(te - t), t, ellipsis);
00555 fprintf(stderr, "\n");
00556 }
00557
00558 #define SKIPBLANK(_s, _c) \
00559 \
00560 while (((_c) = (int) *(_s)) && isblank(_c)) \
00561 (_s)++; \
00562
00563
00564 #define SKIPNONBLANK(_s, _c) \
00565 \
00566 while (((_c) = (int) *(_s)) && !(isblank(_c) || iseol(_c))) \
00567 (_s)++; \
00568
00569
00570 #define COPYNAME(_ne, _s, _c) \
00571 { SKIPBLANK(_s,_c); \
00572 while(((_c) = (int) *(_s)) && (xisalnum(_c) || (_c) == (int) '_')) \
00573 *(_ne)++ = *(_s)++; \
00574 *(_ne) = '\0'; \
00575 }
00576
00577 #define COPYOPTS(_oe, _s, _c) \
00578 { while(((_c) = (int) *(_s)) && (_c) != (int) ')') \
00579 *(_oe)++ = *(_s)++; \
00580 *(_oe) = '\0'; \
00581 }
00582
00590 static int
00591 expandT(MacroBuf mb, const char * f, size_t flen)
00592
00593
00594 {
00595 char *sbuf;
00596 const char *s = mb->s;
00597 int rc;
00598
00599 sbuf = alloca(flen + 1);
00600 memset(sbuf, 0, (flen + 1));
00601
00602 strncpy(sbuf, f, flen);
00603 sbuf[flen] = '\0';
00604 mb->s = sbuf;
00605 rc = expandMacro(mb);
00606 mb->s = s;
00607 return rc;
00608 }
00609
00610 #if 0
00611
00618 static int
00619 expandS(MacroBuf mb, char * tbuf, size_t tbuflen)
00620
00621
00622 {
00623 const char *t = mb->t;
00624 size_t nb = mb->nb;
00625 int rc;
00626
00627 mb->t = tbuf;
00628 mb->nb = tbuflen;
00629 rc = expandMacro(mb);
00630 mb->t = t;
00631 mb->nb = nb;
00632 return rc;
00633 }
00634 #endif
00635
00643 static int
00644 expandU(MacroBuf mb, char * u, size_t ulen)
00645
00646
00647 {
00648 const char *s = mb->s;
00649 char *t = mb->t;
00650 size_t nb = mb->nb;
00651 char *tbuf;
00652 int rc;
00653
00654 tbuf = alloca(ulen + 1);
00655 memset(tbuf, 0, (ulen + 1));
00656
00657 mb->s = u;
00658 mb->t = tbuf;
00659 mb->nb = ulen;
00660 rc = expandMacro(mb);
00661
00662 tbuf[ulen] = '\0';
00663 if (ulen > mb->nb)
00664 strncpy(u, tbuf, (ulen - mb->nb + 1));
00665
00666 mb->s = s;
00667 mb->t = t;
00668 mb->nb = nb;
00669
00670 return rc;
00671 }
00672
00680 static int
00681 doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
00682
00683
00684 {
00685 size_t bufn = _macro_BUFSIZ + clen;
00686 char * buf = alloca(bufn);
00687 FILE *shf;
00688 int rc;
00689 int c;
00690
00691 strncpy(buf, cmd, clen);
00692 buf[clen] = '\0';
00693 rc = expandU(mb, buf, bufn);
00694 if (rc)
00695 return rc;
00696
00697 if ((shf = popen(buf, "r")) == NULL)
00698 return 1;
00699 while(mb->nb > 0 && (c = fgetc(shf)) != EOF)
00700 SAVECHAR(mb, c);
00701 (void) pclose(shf);
00702
00703
00704 while (iseol(mb->t[-1])) {
00705 *(mb->t--) = '\0';
00706 mb->nb++;
00707 }
00708 return 0;
00709 }
00710
00719 static const char *
00720 doDefine(MacroBuf mb, const char * se, int level, int expandbody)
00721
00722
00723 {
00724 const char *s = se;
00725 size_t bufn = _macro_BUFSIZ;
00726 char *buf = alloca(bufn);
00727 char *n = buf, *ne;
00728 char *o = NULL, *oe;
00729 char *b, *be;
00730 int c;
00731 int oc = (int) ')';
00732
00733 SKIPBLANK(s, c);
00734 if (c == (int) '.')
00735 *n++ = c = *s++;
00736 if (c == (int) '.')
00737 *n++ = c = *s++;
00738 ne = n;
00739
00740
00741 COPYNAME(ne, s, c);
00742
00743
00744 oe = ne + 1;
00745 if (*s == '(') {
00746 s++;
00747 o = oe;
00748 COPYOPTS(oe, s, oc);
00749 s++;
00750 }
00751
00752
00753 b = be = oe + 1;
00754 SKIPBLANK(s, c);
00755 if (c == (int) '{') {
00756 if ((se = matchchar(s, (char) c, '}')) == NULL) {
00757 rpmlog(RPMLOG_ERR,
00758 _("Macro %%%s has unterminated body\n"), n);
00759 se = s;
00760 return se;
00761 }
00762 s++;
00763 strncpy(b, s, (se - s));
00764 b[se - s] = '\0';
00765 be += strlen(b);
00766 se++;
00767 s = se;
00768 } else {
00769 int bc = 0, pc = 0;
00770 while (*s && (bc || pc || !iseol(*s))) {
00771 switch (*s) {
00772 case '\\':
00773 switch (*(s+1)) {
00774 case '\0': break;
00775 default: s++; break;
00776 }
00777 break;
00778 case '%':
00779 switch (*(s+1)) {
00780 case '{': *be++ = *s++; bc++; break;
00781 case '(': *be++ = *s++; pc++; break;
00782 case '%': *be++ = *s++; break;
00783 }
00784 break;
00785 case '{': if (bc > 0) bc++; break;
00786 case '}': if (bc > 0) bc--; break;
00787 case '(': if (pc > 0) pc++; break;
00788 case ')': if (pc > 0) pc--; break;
00789 }
00790 *be++ = *s++;
00791 }
00792 *be = '\0';
00793
00794 if (bc || pc) {
00795 rpmlog(RPMLOG_ERR,
00796 _("Macro %%%s has unterminated body\n"), n);
00797 se = s;
00798 return se;
00799 }
00800
00801
00802
00803 while (--be >= b && (c = (int) *be) && (isblank(c) || iseol(c)))
00804 {};
00805
00806 *(++be) = '\0';
00807 }
00808
00809
00810 while (iseol(*s))
00811 s++;
00812 se = s;
00813
00814
00815 if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) {
00816 rpmlog(RPMLOG_ERR,
00817 _("Macro %%%s has illegal name (%%define)\n"), n);
00818 return se;
00819 }
00820
00821
00822 if (o && oc != (int) ')') {
00823 rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
00824 return se;
00825 }
00826
00827 if ((be - b) < 1) {
00828 rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
00829 return se;
00830 }
00831
00832
00833 if (expandbody && expandU(mb, b, (&buf[bufn] - b))) {
00834 rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
00835 return se;
00836 }
00837
00838
00839 if (n != buf)
00840 n--;
00841 if (n != buf)
00842 n--;
00843 addMacro(mb->mc, n, o, b, (level - 1));
00844
00845 return se;
00846 }
00847
00854 static const char *
00855 doUndefine(MacroContext mc, const char * se)
00856
00857
00858 {
00859 const char *s = se;
00860 char *buf = alloca(_macro_BUFSIZ);
00861 char *n = buf, *ne = n;
00862 int c;
00863
00864 COPYNAME(ne, s, c);
00865
00866
00867 while (iseol(*s))
00868 s++;
00869 se = s;
00870
00871
00872 if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) {
00873 rpmlog(RPMLOG_ERR,
00874 _("Macro %%%s has illegal name (%%undefine)\n"), n);
00875 return se;
00876 }
00877
00878 delMacro(mc, n);
00879
00880 return se;
00881 }
00882
00883 #ifdef DYING
00884 static void
00885 dumpME(const char * msg, MacroEntry me)
00886
00887
00888 {
00889 if (msg)
00890 fprintf(stderr, "%s", msg);
00891 fprintf(stderr, "\tme %p", me);
00892 if (me)
00893 fprintf(stderr,"\tname %p(%s) prev %p",
00894 me->name, me->name, me->prev);
00895 fprintf(stderr, "\n");
00896 }
00897 #endif
00898
00907 static void
00908 pushMacro( MacroEntry * mep, const char * n, const char * o,
00909 const char * b, int level)
00910
00911 {
00912 MacroEntry prev = (mep && *mep ? *mep : NULL);
00913 MacroEntry me = (MacroEntry) xmalloc(sizeof(*me));
00914 const char *name = n;
00915
00916 if (*name == '.')
00917 name++;
00918 if (*name == '.')
00919 name++;
00920
00921
00922 me->prev = prev;
00923
00924 me->name = (prev ? prev->name : xstrdup(name));
00925 me->opts = (o ? xstrdup(o) : NULL);
00926 me->body = xstrdup(b ? b : "");
00927 me->used = 0;
00928 me->level = level;
00929 me->flags = (name != n);
00930 if (mep)
00931 *mep = me;
00932 else
00933 me = _free(me);
00934 }
00935
00940 static void
00941 popMacro(MacroEntry * mep)
00942
00943 {
00944 MacroEntry me = (*mep ? *mep : NULL);
00945
00946 if (me) {
00947
00948
00949 if ((*mep = me->prev) == NULL)
00950 me->name = _free(me->name);
00951 me->opts = _free(me->opts);
00952 me->body = _free(me->body);
00953 me = _free(me);
00954
00955 }
00956 }
00957
00962 static void
00963 freeArgs(MacroBuf mb)
00964
00965 {
00966 MacroContext mc = mb->mc;
00967 int ndeleted = 0;
00968 int i;
00969
00970 if (mc == NULL || mc->macroTable == NULL)
00971 return;
00972
00973
00974 for (i = 0; i < mc->firstFree; i++) {
00975 MacroEntry *mep, me;
00976 int skiptest = 0;
00977 mep = &mc->macroTable[i];
00978 me = *mep;
00979
00980 if (me == NULL)
00981 continue;
00982 if (me->level < mb->depth)
00983 continue;
00984 if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
00985 if (*me->name == '*' && me->used > 0)
00986 skiptest = 1;
00987 } else if (!skiptest && me->used <= 0) {
00988 #if NOTYET
00989 rpmlog(RPMLOG_ERR,
00990 _("Macro %%%s (%s) was not used below level %d\n"),
00991 me->name, me->body, me->level);
00992 #endif
00993 }
00994 popMacro(mep);
00995 if (!(mep && *mep))
00996 ndeleted++;
00997 }
00998
00999
01000 if (ndeleted)
01001 sortMacroTable(mc);
01002 }
01003
01013 static const char *
01014 grabArgs(MacroBuf mb, const MacroEntry me, const char * se,
01015 const char * lastc)
01016
01017
01018 {
01019 poptContext optCon;
01020 struct poptOption *optTbl;
01021 size_t bufn = _macro_BUFSIZ;
01022 char *buf = alloca(bufn);
01023 char *b, *be;
01024 char aname[16];
01025 const char *opts;
01026 int argc = 0;
01027 const char **argv;
01028 int c;
01029 unsigned int popt_flags;
01030
01031
01032 buf[0] = '\0';
01033 b = be = stpcpy(buf, me->name);
01034
01035 addMacro(mb->mc, "0", NULL, buf, mb->depth);
01036
01037 argc = 1;
01038
01039
01040 *be++ = ' ';
01041 while ((c = (int) *se++) != (int) '\0' && (se-1) != lastc) {
01042
01043 if (!isblank(c)) {
01044 *be++ = (char) c;
01045 continue;
01046 }
01047
01048
01049 if (be[-1] == ' ')
01050 continue;
01051
01052 *be++ = ' ';
01053 argc++;
01054 }
01055 if (c == (int) '\0') se--;
01056 if (be[-1] != ' ')
01057 argc++, be++;
01058 be[-1] = '\0';
01059 if (*b == ' ') b++;
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070 addMacro(mb->mc, "**", NULL, b, mb->depth);
01071
01072 #ifdef NOTYET
01073
01074 expandU(mb, buf, bufn);
01075 #endif
01076
01077
01078 argv = (const char **) alloca((argc + 1) * sizeof(*argv));
01079 be[-1] = ' ';
01080 be[0] = '\0';
01081
01082 b = buf;
01083 for (c = 0; c < argc; c++) {
01084 argv[c] = b;
01085 b = strchr(b, ' ');
01086 *b++ = '\0';
01087 }
01088
01089 argv[argc] = NULL;
01090
01091
01092
01093
01094 popt_flags = POPT_CONTEXT_NO_EXEC;
01095 #if defined(RPM_VENDOR_OPENPKG)
01096 popt_flags |= POPT_CONTEXT_POSIXMEHARDER;
01097 #endif
01098 if (me->opts[0] == '+') popt_flags |= POPT_CONTEXT_POSIXMEHARDER;
01099
01100
01101 opts = me->opts;
01102 if (*opts == '+') opts++;
01103 for (c = 0; *opts != '\0'; opts++)
01104 if (*opts != ':') c++;
01105
01106
01107 optTbl = xcalloc(sizeof(*optTbl), (c + 1));
01108 opts = me->opts;
01109 if (*opts == '+') opts++;
01110 for (c = 0; *opts != '\0'; opts++) {
01111 if (*opts == ':') continue;
01112 optTbl[c].shortName = opts[0];
01113 optTbl[c].val = (int) opts[0];
01114 if (opts[1] == ':')
01115 optTbl[c].argInfo = POPT_ARG_STRING;
01116 c++;
01117 }
01118
01119
01120
01121 optCon = poptGetContext(argv[0], argc, argv, optTbl, popt_flags);
01122
01123 while ((c = poptGetNextOpt(optCon)) > 0) {
01124 const char * optArg = poptGetOptArg(optCon);
01125 *be++ = '-';
01126 *be++ = (char) c;
01127 if (optArg != NULL) {
01128 *be++ = ' ';
01129 be = stpcpy(be, optArg);
01130 }
01131 *be++ = '\0';
01132 aname[0] = '-'; aname[1] = (char)c; aname[2] = '\0';
01133 addMacro(mb->mc, aname, NULL, b, mb->depth);
01134 if (optArg != NULL) {
01135 aname[0] = '-'; aname[1] = (char)c; aname[2] = '*'; aname[3] = '\0';
01136 addMacro(mb->mc, aname, NULL, optArg, mb->depth);
01137 }
01138 be = b;
01139
01140 optArg = _free(optArg);
01141
01142 }
01143 if (c < -1) {
01144 rpmlog(RPMLOG_ERR, _("Unknown option in macro %s(%s): %s: %s\n"),
01145 me->name, me->opts,
01146 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c));
01147 goto exit;
01148 }
01149
01150 argv = poptGetArgs(optCon);
01151 argc = 0;
01152 if (argv != NULL)
01153 for (c = 0; argv[c] != NULL; c++)
01154 argc++;
01155
01156
01157 sprintf(aname, "%d", argc);
01158 addMacro(mb->mc, "#", NULL, aname, mb->depth);
01159
01160
01161 if (be) {
01162 *be = '\0';
01163 if (argv != NULL)
01164 for (c = 0; c < argc; c++) {
01165 sprintf(aname, "%d", (c + 1));
01166 addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
01167 if (be != b) *be++ = ' ';
01168 be = stpcpy(be, argv[c]);
01169 }
01170 }
01171
01172
01173 addMacro(mb->mc, "*", NULL, b, mb->depth);
01174
01175 exit:
01176 optCon = poptFreeContext(optCon);
01177 optTbl = _free(optTbl);
01178 return se;
01179 }
01180
01188 static void
01189 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
01190
01191
01192 {
01193 size_t bufn = _macro_BUFSIZ + msglen;
01194 char *buf = alloca(bufn);
01195
01196 strncpy(buf, msg, msglen);
01197 buf[msglen] = '\0';
01198 (void) expandU(mb, buf, bufn);
01199 if (waserror)
01200 rpmlog(RPMLOG_ERR, "%s\n", buf);
01201 else
01202 fprintf(stderr, "%s", buf);
01203 }
01204
01214 static void
01215 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
01216 const char * g, size_t gn)
01217
01218
01219 {
01220 size_t bufn = _macro_BUFSIZ + fn + gn;
01221 char * buf = alloca(bufn);
01222 char *b = NULL, *be;
01223 int c;
01224
01225 buf[0] = '\0';
01226 if (g != NULL) {
01227 strncpy(buf, g, gn);
01228 buf[gn] = '\0';
01229 (void) expandU(mb, buf, bufn);
01230 }
01231 if (fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) {
01232
01233 for (c = 5; c < (int)(fn-1) && f[c] == '0' && xisdigit((int)f[c+1]);)
01234 c++;
01235 b = buf;
01236 be = stpncpy( stpcpy(b, "%patch -P "), f+c, fn-c);
01237 *be = '\0';
01238 } else
01239 if (STREQ("basename", f, fn)) {
01240 if ((b = strrchr(buf, '/')) == NULL)
01241 b = buf;
01242 else
01243 b++;
01244 } else if (STREQ("dirname", f, fn)) {
01245 if ((b = strrchr(buf, '/')) != NULL)
01246 *b = '\0';
01247 b = buf;
01248 #if !defined(__LCLINT__)
01249 } else if (STREQ("realpath", f, fn)) {
01250 char rp[PATH_MAX];
01251 char *cp;
01252 size_t l;
01253 if ((cp = realpath(buf, rp)) != NULL) {
01254 l = strlen(cp);
01255 if ((size_t)(l+1) <= bufn) {
01256 memcpy(buf, cp, l+1);
01257 b = buf;
01258 }
01259 }
01260 #endif
01261 } else if (STREQ("getenv", f, fn)) {
01262 char *cp;
01263 if ((cp = getenv(buf)) != NULL)
01264 b = cp;
01265 } else if (STREQ("shrink", f, fn)) {
01266
01267
01268
01269
01270 int i, j, k, was_space = 0;
01271 for (i = 0, j = 0, k = (int)strlen(buf); i < k; ) {
01272 if (xisspace((int)(buf[i]))) {
01273 was_space = 1;
01274 i++;
01275 continue;
01276 }
01277 else if (was_space) {
01278 was_space = 0;
01279 if (j > 0)
01280 buf[j++] = ' ';
01281
01282 }
01283 buf[j++] = buf[i++];
01284 }
01285 buf[j] = '\0';
01286 b = buf;
01287 } else if (STREQ("suffix", f, fn)) {
01288 if ((b = strrchr(buf, '.')) != NULL)
01289 b++;
01290 } else if (STREQ("expand", f, fn)) {
01291 b = buf;
01292 } else if (STREQ("verbose", f, fn)) {
01293 #if defined(RPMLOG_MASK)
01294 if (negate)
01295 b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? NULL : buf);
01296 else
01297 b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? buf : NULL);
01298 #else
01299
01300 b = (negate) ? NULL : buf;
01301 #endif
01302 } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
01303 int ut = urlPath(buf, (const char **)&b);
01304 ut = ut;
01305 if (*b == '\0') b = "/";
01306 } else if (STREQ("uncompress", f, fn)) {
01307 rpmCompressedMagic compressed = COMPRESSED_OTHER;
01308
01309 for (b = buf; (c = (int)*b) && isblank(c);)
01310 b++;
01311
01312 for (be = b; (c = (int)*be) && !isblank(c);)
01313 be++;
01314
01315 *be++ = '\0';
01316 (void) isCompressed(b, &compressed);
01317 switch(compressed) {
01318 default:
01319 case 0:
01320 sprintf(be, "%%__cat %s", b);
01321 break;
01322 case 1:
01323 sprintf(be, "%%__gzip -dc '%s'", b);
01324 break;
01325 case 2:
01326 sprintf(be, "%%__bzip2 -dc '%s'", b);
01327 break;
01328 case 3:
01329 sprintf(be, "%%__unzip -qq '%s'", b);
01330 break;
01331 case 4:
01332 sprintf(be, "%%__lzop -dc '%s'", b);
01333 break;
01334 case 5:
01335 sprintf(be, "%%__lzma -dc '%s'", b);
01336 break;
01337 case 6:
01338 sprintf(be, "%%__xz -dc '%s'", b);
01339 break;
01340 }
01341 b = be;
01342 } else if (STREQ("mkstemp", f, fn)) {
01343
01344 for (b = buf; (c = (int)*b) && isblank(c);)
01345 b++;
01346
01347 for (be = b; (c = (int)*be) && !isblank(c);)
01348 be++;
01349
01350 #if defined(HAVE_MKSTEMP)
01351 (void) close(mkstemp(b));
01352 #else
01353 (void) mktemp(b);
01354 #endif
01355 } else if (STREQ("mkdtemp", f, fn)) {
01356
01357 for (b = buf; (c = (int)*b) && isblank(c);)
01358 b++;
01359
01360 for (be = b; (c = (int)*be) && !isblank(c);)
01361 be++;
01362
01363 #if defined(HAVE_MKDTEMP) && !defined(__LCLINT__)
01364 if (mkdtemp(b) == NULL)
01365 perror("mkdtemp");
01366 #else
01367 if ((b = tmpnam(b)) != NULL)
01368 (void) mkdir(b, 0700);
01369 #endif
01370 } else if (STREQ("uuid", f, fn)) {
01371 int uuid_version;
01372 const char *uuid_ns;
01373 const char *uuid_data;
01374 char *cp;
01375 size_t n;
01376
01377 uuid_version = 1;
01378 uuid_ns = NULL;
01379 uuid_data = NULL;
01380 cp = buf;
01381 if ((n = strspn(cp, " \t\n")) > 0)
01382 cp += n;
01383 if ((n = strcspn(cp, " \t\n")) > 0) {
01384 uuid_version = (int)strtol(cp, (char **)NULL, 10);
01385 cp += n;
01386 if ((n = strspn(cp, " \t\n")) > 0)
01387 cp += n;
01388 if ((n = strcspn(cp, " \t\n")) > 0) {
01389 uuid_ns = cp;
01390 cp += n;
01391 *cp++ = '\0';
01392 if ((n = strspn(cp, " \t\n")) > 0)
01393 cp += n;
01394 if ((n = strcspn(cp, " \t\n")) > 0) {
01395 uuid_data = cp;
01396 cp += n;
01397 *cp++ = '\0';
01398 }
01399 }
01400 }
01401
01402 if (rpmuuidMake(uuid_version, uuid_ns, uuid_data, buf, NULL))
01403 rpmlog(RPMLOG_ERR, "failed to create UUID\n");
01404 else
01405 b = buf;
01406
01407 } else if (STREQ("S", f, fn)) {
01408 for (b = buf; (c = (int)*b) && xisdigit(c);)
01409 b++;
01410 if (!c) {
01411 b++;
01412 sprintf(b, "%%SOURCE%s", buf);
01413 } else
01414 b = buf;
01415 } else if (STREQ("P", f, fn)) {
01416 for (b = buf; (c = (int) *b) && xisdigit(c);)
01417 b++;
01418 if (!c) {
01419 b++;
01420 sprintf(b, "%%PATCH%s", buf);
01421 } else
01422 b = buf;
01423 } else if (STREQ("F", f, fn)) {
01424 b = buf + strlen(buf) + 1;
01425 sprintf(b, "file%s.file", buf);
01426 }
01427
01428 if (b) {
01429 (void) expandT(mb, b, strlen(b));
01430 }
01431 }
01432
01433 static int expandFIFO(MacroBuf mb, MacroEntry me, const char *g, size_t gn)
01434
01435
01436 {
01437 int rc = 0;
01438
01439 if (me) {
01440 if (me->prev) {
01441 rc = expandFIFO(mb, me->prev, g, gn);
01442 rc = expandT(mb, g, gn);
01443 }
01444 rc = expandT(mb, me->body, strlen(me->body));
01445 }
01446 return rc;
01447 }
01448
01449 #if !defined(DEBUG_MACROS)
01450
01451
01452
01453 #define POPT_ERROR_NOARG -10
01454 #define POPT_ERROR_BADQUOTE -15
01455 #define POPT_ERROR_MALLOC -21
01457 #define POPT_ARGV_ARRAY_GROW_DELTA 5
01458
01459 static int XpoptDupArgv(int argc, const char **argv,
01460 int * argcPtr, const char *** argvPtr)
01461
01462 {
01463 size_t nb = (argc + 1) * sizeof(*argv);
01464 const char ** argv2;
01465 char * dst;
01466 int i;
01467
01468 if (argc <= 0 || argv == NULL)
01469 return POPT_ERROR_NOARG;
01470 for (i = 0; i < argc; i++) {
01471 if (argv[i] == NULL)
01472 return POPT_ERROR_NOARG;
01473 nb += strlen(argv[i]) + 1;
01474 }
01475
01476 dst = xmalloc(nb);
01477 if (dst == NULL)
01478 return POPT_ERROR_MALLOC;
01479 argv2 = (void *) dst;
01480 dst += (argc + 1) * sizeof(*argv);
01481
01482 for (i = 0; i < argc; i++) {
01483 argv2[i] = dst;
01484 dst += strlen(strcpy(dst, argv[i])) + 1;
01485 }
01486 argv2[argc] = NULL;
01487
01488 if (argvPtr) {
01489 *argvPtr = argv2;
01490 } else {
01491 free(argv2);
01492 argv2 = NULL;
01493 }
01494 if (argcPtr)
01495 *argcPtr = argc;
01496 return 0;
01497 }
01498
01499 static int XpoptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
01500
01501 {
01502 const char * src;
01503 char quote = '\0';
01504 int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
01505 const char ** argv = xmalloc(sizeof(*argv) * argvAlloced);
01506 int argc = 0;
01507 size_t buflen = strlen(s) + 1;
01508 char * buf = memset(alloca(buflen), 0, buflen);
01509 int rc = POPT_ERROR_MALLOC;
01510
01511 if (argv == NULL) return rc;
01512 argv[argc] = buf;
01513
01514 for (src = s; *src != '\0'; src++) {
01515 if (quote == *src) {
01516 quote = '\0';
01517 } else if (quote != '\0') {
01518 if (*src == '\\') {
01519 src++;
01520 if (!*src) {
01521 rc = POPT_ERROR_BADQUOTE;
01522 goto exit;
01523 }
01524 if (*src != quote) *buf++ = '\\';
01525 }
01526 *buf++ = *src;
01527 } else if (isspace(*src)) {
01528 if (*argv[argc] != '\0') {
01529 buf++, argc++;
01530 if (argc == argvAlloced) {
01531 argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
01532 argv = realloc(argv, sizeof(*argv) * argvAlloced);
01533 if (argv == NULL) goto exit;
01534 }
01535 argv[argc] = buf;
01536 }
01537 } else switch (*src) {
01538 case '"':
01539 case '\'':
01540 quote = *src;
01541 break;
01542 case '\\':
01543 src++;
01544 if (!*src) {
01545 rc = POPT_ERROR_BADQUOTE;
01546 goto exit;
01547 }
01548
01549 default:
01550 *buf++ = *src;
01551 break;
01552 }
01553 }
01554
01555 if (strlen(argv[argc])) {
01556 argc++, buf++;
01557 }
01558
01559 rc = XpoptDupArgv(argc, argv, argcPtr, argvPtr);
01560
01561 exit:
01562 if (argv) free(argv);
01563 return rc;
01564 }
01565 #endif
01566
01574 #if defined(WITH_FICL) || defined(WITH_JS) || defined(WITH_PERLEMBED) || defined(WITH_PYTHONEMBED) || defined(WITH_RUBYEMBED) || defined(WITH_TCL)
01575 static char * parseEmbedded(const char * s, size_t nb, const char *** avp)
01576
01577 {
01578 char * script = NULL;
01579 const char * se;
01580
01581
01582 for (se = s + 1; se < (s+nb); se++)
01583 switch (*se) {
01584 default: continue; break;
01585 case ':': goto bingo; break;
01586 }
01587
01588 bingo:
01589 { size_t na = (size_t)(se-s-1);
01590 char * args = NULL;
01591 int ac;
01592 int rc;
01593
01594 args = memcpy(xmalloc(na+1), s+1, na);
01595 args[na] = '\0';
01596
01597 ac = 0;
01598 rc = XpoptParseArgvString(args, &ac, avp);
01599 args = _free(args);
01600 nb -= na;
01601 }
01602
01603 nb -= 3;
01604 script = memcpy(xmalloc(nb+1), se+1, nb+1);
01605 script[nb] = '\0';
01606 return script;
01607 }
01608 #endif
01609
01616 static int
01617 expandMacro(MacroBuf mb)
01618
01619
01620
01621
01622
01623
01624 {
01625 MacroEntry *mep;
01626 MacroEntry me;
01627 const char *s = mb->s, *se;
01628 const char *f, *fe;
01629 const char *g, *ge;
01630 size_t fn, gn;
01631 char *t = mb->t;
01632 int c;
01633 int rc = 0;
01634 int negate;
01635 int stackarray;
01636 const char * lastc;
01637 int chkexist;
01638
01639 if (++mb->depth > max_macro_depth) {
01640 rpmlog(RPMLOG_ERR,
01641 _("Recursion depth(%d) greater than max(%d)\n"),
01642 mb->depth, max_macro_depth);
01643 mb->depth--;
01644 mb->expand_trace = 1;
01645 return 1;
01646 }
01647
01648 while (rc == 0 && mb->nb > 0 && (c = (int)*s) != (int)'\0') {
01649 s++;
01650
01651 switch(c) {
01652 case '%':
01653 if (*s != '\0') {
01654 if (*s != '%')
01655 break;
01656 s++;
01657 }
01658
01659 default:
01660 SAVECHAR(mb, c);
01661 continue;
01662 break;
01663 }
01664
01665
01666 f = fe = NULL;
01667 g = ge = NULL;
01668 if (mb->depth > 1)
01669 t = mb->t;
01670 stackarray = chkexist = negate = 0;
01671 lastc = NULL;
01672 switch ((c = (int) *s)) {
01673 default:
01674 while (*s != '\0' && strchr("!?@", *s) != NULL) {
01675 switch(*s++) {
01676 case '@':
01677 stackarray = ((stackarray + 1) % 2);
01678 break;
01679 case '!':
01680 negate = ((negate + 1) % 2);
01681 break;
01682 case '?':
01683 chkexist++;
01684 break;
01685 }
01686 }
01687 f = se = s;
01688 if (*se == '-')
01689 se++;
01690 while((c = (int) *se) && (xisalnum(c) || c == (int) '_'))
01691 se++;
01692
01693 switch (*se) {
01694 case '*':
01695 se++;
01696 if (*se == '*') se++;
01697 break;
01698 case '#':
01699 se++;
01700 break;
01701 default:
01702 break;
01703 }
01704 fe = se;
01705
01706
01707 if ((c = (int) *fe) && isblank(c))
01708 if ((lastc = strchr(fe,'\n')) == NULL)
01709 lastc = strchr(fe, '\0');
01710
01711 break;
01712 case '(':
01713 if ((se = matchchar(s, (char)c, ')')) == NULL) {
01714 rpmlog(RPMLOG_ERR,
01715 _("Unterminated %c: %s\n"), (char)c, s);
01716 rc = 1;
01717 continue;
01718 }
01719 if (mb->macro_trace)
01720 printMacro(mb, s, se+1);
01721
01722 s++;
01723 rc = doShellEscape(mb, s, (se - s));
01724 se++;
01725
01726 s = se;
01727 continue;
01728 break;
01729 case '{':
01730 if ((se = matchchar(s, (char)c, '}')) == NULL) {
01731 rpmlog(RPMLOG_ERR,
01732 _("Unterminated %c: %s\n"), (char)c, s);
01733 rc = 1;
01734 continue;
01735 }
01736 f = s+1;
01737 se++;
01738 while (strchr("!?@", *f) != NULL) {
01739 switch(*f++) {
01740 case '@':
01741 stackarray = ((stackarray + 1) % 2);
01742 break;
01743 case '!':
01744 negate = ((negate + 1) % 2);
01745 break;
01746 case '?':
01747 chkexist++;
01748 break;
01749 }
01750 }
01751
01752 for (fe = f; (c = (int) *fe) && !strchr(" :}", c);)
01753 fe++;
01754 switch (c) {
01755 case ':':
01756 g = fe + 1;
01757 ge = se - 1;
01758 break;
01759 case ' ':
01760 lastc = se-1;
01761 break;
01762 default:
01763 break;
01764 }
01765 break;
01766 }
01767
01768
01769 fn = (fe - f);
01770 gn = (ge - g);
01771 if ((fe - f) <= 0) {
01772
01773 c = (int) '%';
01774 SAVECHAR(mb, c);
01775 #if 0
01776 rpmlog(RPMLOG_ERR,
01777 _("A %% is followed by an unparseable macro\n"));
01778 #endif
01779 s = se;
01780 continue;
01781 }
01782
01783 if (mb->macro_trace)
01784 printMacro(mb, s, se);
01785
01786
01787 if (STREQ("load", f, fn)) {
01788 if (g != NULL) {
01789 char * mfn = strncpy(alloca(gn + 1), g, gn);
01790 int xx;
01791 mfn[gn] = '\0';
01792 xx = rpmLoadMacroFile(NULL, mfn);
01793
01794 if (xx != 0 && chkexist == negate)
01795 rpmlog(RPMLOG_ERR, _("%s: load macros failed\n"), mfn);
01796 }
01797 s = se;
01798 continue;
01799 }
01800 if (STREQ("global", f, fn)) {
01801 s = doDefine(mb, se, RMIL_GLOBAL, 1);
01802 continue;
01803 }
01804 if (STREQ("define", f, fn)) {
01805 s = doDefine(mb, se, mb->depth, 0);
01806 continue;
01807 }
01808 if (STREQ("undefine", f, fn)) {
01809 s = doUndefine(mb->mc, se);
01810 continue;
01811 }
01812
01813 if (STREQ("echo", f, fn) ||
01814 STREQ("warn", f, fn) ||
01815 STREQ("error", f, fn)) {
01816 int waserror = 0;
01817 if (STREQ("error", f, fn))
01818 waserror = 1, rc = 1;
01819 if (g != NULL && g < ge)
01820 doOutput(mb, waserror, g, gn);
01821 else
01822 doOutput(mb, waserror, f, fn);
01823 s = se;
01824 continue;
01825 }
01826
01827 if (STREQ("trace", f, fn)) {
01828
01829 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
01830 if (mb->depth == 1) {
01831 print_macro_trace = mb->macro_trace;
01832 print_expand_trace = mb->expand_trace;
01833 }
01834 s = se;
01835 continue;
01836 }
01837
01838 if (STREQ("dump", f, fn)) {
01839 rpmDumpMacroTable(mb->mc, NULL);
01840 while (iseol(*se))
01841 se++;
01842 s = se;
01843 continue;
01844 }
01845
01846 #ifdef WITH_LUA
01847 if (STREQ("lua", f, fn)) {
01848 rpmlua lua = rpmluaGetGlobalState();
01849 rpmlua olua = memcpy(alloca(sizeof(*olua)), lua, sizeof(*olua));
01850 const char *ls = s+sizeof("{lua:")-1;
01851 const char *lse = se-sizeof("}")+1;
01852 char *scriptbuf = (char *)xmalloc((lse-ls)+1);
01853 const char *printbuf;
01854
01855
01856 lua->storeprint = 1;
01857 lua->printbuf = NULL;
01858 lua->printbufsize = 0;
01859 lua->printbufused = 0;
01860
01861 memcpy(scriptbuf, ls, lse-ls);
01862 scriptbuf[lse-ls] = '\0';
01863 if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
01864 rc = 1;
01865 printbuf = rpmluaGetPrintBuffer(lua);
01866 if (printbuf) {
01867 size_t len = strlen(printbuf);
01868 if (len > mb->nb)
01869 len = mb->nb;
01870 memcpy(mb->t, printbuf, len);
01871 mb->t += len;
01872 mb->nb -= len;
01873 }
01874
01875
01876 lua->storeprint = olua->storeprint;
01877 lua->printbuf = olua->printbuf;
01878 lua->printbufsize = olua->printbufsize;
01879 lua->printbufused = olua->printbufused;
01880
01881 free(scriptbuf);
01882 s = se;
01883 continue;
01884 }
01885 #endif
01886
01887 #ifdef WITH_FICL
01888 if (STREQ("ficl", f, fn)) {
01889 const char ** av = NULL;
01890 char * script = parseEmbedded(s, (size_t)(se-s), &av);
01891 rpmficl ficl = rpmficlNew(av, _globalI);
01892 const char * result = NULL;
01893
01894 if (rpmficlRun(ficl, script, &result) != RPMRC_OK)
01895 rc = 1;
01896 else {
01897 if (result == NULL) result = "FIXME";
01898 if (result != NULL && *result != '\0') {
01899 size_t len = strlen(result);
01900 if (len > mb->nb)
01901 len = mb->nb;
01902 memcpy(mb->t, result, len);
01903 mb->t += len;
01904 mb->nb -= len;
01905 }
01906 }
01907 ficl = rpmficlFree(ficl);
01908 av = _free(av);
01909 script = _free(script);
01910 s = se;
01911 continue;
01912 }
01913 #endif
01914
01915 #ifdef WITH_JS
01916 if (STREQ("js", f, fn)) {
01917 const char ** av = NULL;
01918 char * script = parseEmbedded(s, (size_t)(se-s), &av);
01919 rpmjs js = rpmjsNew(av, _globalI);
01920 const char * result = NULL;
01921
01922 if (rpmjsRun(js, script, &result) != RPMRC_OK)
01923 rc = 1;
01924 else {
01925 if (result == NULL) result = "FIXME";
01926 if (result != NULL && *result != '\0') {
01927 size_t len = strlen(result);
01928 if (len > mb->nb)
01929 len = mb->nb;
01930 memcpy(mb->t, result, len);
01931 mb->t += len;
01932 mb->nb -= len;
01933 }
01934 }
01935 js = rpmjsFree(js);
01936 av = _free(av);
01937 script = _free(script);
01938 s = se;
01939 continue;
01940 }
01941 #endif
01942
01943 #ifdef WITH_PERLEMBED
01944 if (STREQ("perl", f, fn)) {
01945 const char ** av = NULL;
01946 char * script = parseEmbedded(s, (size_t)(se-s), &av);
01947 rpmperl perl = rpmperlNew(av, _globalI);
01948 const char * result = NULL;
01949
01950 if (rpmperlRun(perl, script, &result) != RPMRC_OK)
01951 rc = 1;
01952 else {
01953 if (result == NULL) result = "FIXME";
01954 if (result != NULL && *result != '\0') {
01955 size_t len = strlen(result);
01956 if (len > mb->nb)
01957 len = mb->nb;
01958 memcpy(mb->t, result, len);
01959 mb->t += len;
01960 mb->nb -= len;
01961 }
01962 }
01963 perl = rpmperlFree(perl);
01964 av = _free(av);
01965 script = _free(script);
01966 s = se;
01967 continue;
01968 }
01969 #endif
01970
01971 #ifdef WITH_PYTHONEMBED
01972 if (STREQ("python", f, fn)) {
01973 const char ** av = NULL;
01974 char * script = parseEmbedded(s, (size_t)(se-s), &av);
01975 rpmpython python = rpmpythonNew(av, _globalI);
01976 const char * result = NULL;
01977
01978 if (rpmpythonRun(python, script, &result) != RPMRC_OK)
01979 rc = 1;
01980 else {
01981 if (result == NULL) result = "FIXME";
01982 if (result != NULL && *result != '\0') {
01983 size_t len = strlen(result);
01984 if (len > mb->nb)
01985 len = mb->nb;
01986 memcpy(mb->t, result, len);
01987 mb->t += len;
01988 mb->nb -= len;
01989 }
01990 }
01991 python = rpmpythonFree(python);
01992 av = _free(av);
01993 script = _free(script);
01994 s = se;
01995 continue;
01996 }
01997 #endif
01998
01999 #ifdef WITH_RUBYEMBED
02000 if (STREQ("ruby", f, fn)) {
02001 const char ** av = NULL;
02002 char * script = parseEmbedded(s, (size_t)(se-s), &av);
02003 rpmruby ruby = rpmrubyNew(av, _globalI);
02004 const char * result = NULL;
02005
02006 if (rpmrubyRun(ruby, script, &result) != RPMRC_OK)
02007 rc = 1;
02008 else {
02009 if (result == NULL) result = "FIXME";
02010 if (result != NULL && *result != '\0') {
02011 size_t len = strlen(result);
02012 if (len > mb->nb)
02013 len = mb->nb;
02014 memcpy(mb->t, result, len);
02015 mb->t += len;
02016 mb->nb -= len;
02017 }
02018 }
02019 ruby = rpmrubyFree(ruby);
02020 av = _free(av);
02021 script = _free(script);
02022 s = se;
02023 continue;
02024 }
02025 #endif
02026
02027 #ifdef WITH_TCL
02028 if (STREQ("tcl", f, fn)) {
02029 const char ** av = NULL;
02030 char * script = parseEmbedded(s, (size_t)(se-s), &av);
02031 rpmtcl tcl = rpmtclNew(av, _globalI);
02032 const char * result = NULL;
02033
02034 if (rpmtclRun(tcl, script, &result) != RPMRC_OK)
02035 rc = 1;
02036 else if (result != NULL && *result != '\0') {
02037 size_t len = strlen(result);
02038 if (len > mb->nb)
02039 len = mb->nb;
02040 memcpy(mb->t, result, len);
02041 mb->t += len;
02042 mb->nb -= len;
02043 }
02044 tcl = rpmtclFree(tcl);
02045 av = _free(av);
02046 script = _free(script);
02047 s = se;
02048 continue;
02049 }
02050 #endif
02051
02052
02053 if (lastc && fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) {
02054
02055 doFoo(mb, negate, f, (lastc - f), NULL, 0);
02056
02057 s = lastc;
02058 continue;
02059 }
02060
02061
02062 if (STREQ("basename", f, fn) ||
02063 STREQ("dirname", f, fn) ||
02064 STREQ("realpath", f, fn) ||
02065 STREQ("getenv", f, fn) ||
02066 STREQ("shrink", f, fn) ||
02067 STREQ("suffix", f, fn) ||
02068 STREQ("expand", f, fn) ||
02069 STREQ("verbose", f, fn) ||
02070 STREQ("uncompress", f, fn) ||
02071 STREQ("mkstemp", f, fn) ||
02072 STREQ("mkdtemp", f, fn) ||
02073 STREQ("uuid", f, fn) ||
02074 STREQ("url2path", f, fn) ||
02075 STREQ("u2p", f, fn) ||
02076 STREQ("S", f, fn) ||
02077 STREQ("P", f, fn) ||
02078 STREQ("F", f, fn)) {
02079
02080 doFoo(mb, negate, f, fn, g, gn);
02081
02082 s = se;
02083 continue;
02084 }
02085
02086
02087 mep = findEntry(mb->mc, f, fn);
02088 me = (mep ? *mep : NULL);
02089
02090
02091 if (*f == '-') {
02092 if (me)
02093 me->used++;
02094 if ((me == NULL && !negate) ||
02095 (me != NULL && negate)) {
02096 s = se;
02097 continue;
02098 }
02099
02100 if (g && g < ge) {
02101 rc = expandT(mb, g, gn);
02102 } else
02103 if (me && me->body && *me->body) {
02104 rc = expandT(mb, me->body, strlen(me->body));
02105 }
02106 s = se;
02107 continue;
02108 }
02109
02110
02111 if (chkexist) {
02112 if ((me == NULL && !negate) ||
02113 (me != NULL && negate)) {
02114 s = se;
02115 continue;
02116 }
02117 if (g && g < ge) {
02118 rc = expandT(mb, g, gn);
02119 } else
02120 if (me && me->body && *me->body) {
02121 rc = expandT(mb, me->body, strlen(me->body));
02122 }
02123 s = se;
02124 continue;
02125 }
02126
02127 if (me == NULL) {
02128 #if !defined(RPM_VENDOR_WINDRIVER_DEBUG)
02129 #if DEAD
02130
02131 if (fn == 1 && *f == '*') {
02132 s = se;
02133 continue;
02134 }
02135 #endif
02136
02137 c = (int) '%';
02138 SAVECHAR(mb, c);
02139 #else
02140 if (!strncmp(f, "if", fn) ||
02141 !strncmp(f, "else", fn) ||
02142 !strncmp(f, "endif", fn)) {
02143 c = '%';
02144 SAVECHAR(mb, c);
02145 } else {
02146 rpmlog(RPMLOG_ERR,
02147 _("Macro %%%.*s not found, skipping\n"), fn, f);
02148 s = se;
02149 }
02150 #endif
02151 continue;
02152 }
02153
02154
02155 if (stackarray) {
02156 if (!(g && g < ge)) {
02157 g = "\n";
02158 gn = strlen(g);
02159 }
02160 rc = expandFIFO(mb, me, g, gn);
02161 s = se;
02162 continue;
02163 }
02164
02165
02166 if (me && me->opts != NULL) {
02167 if (lastc != NULL) {
02168 se = grabArgs(mb, me, fe, lastc);
02169 } else {
02170 addMacro(mb->mc, "**", NULL, "", mb->depth);
02171 addMacro(mb->mc, "*", NULL, "", mb->depth);
02172 addMacro(mb->mc, "#", NULL, "0", mb->depth);
02173 addMacro(mb->mc, "0", NULL, me->name, mb->depth);
02174 }
02175 }
02176
02177
02178 if (me->body && *me->body) {
02179 mb->s = me->body;
02180 rc = expandMacro(mb);
02181 if (rc == 0)
02182 me->used++;
02183 }
02184
02185
02186 if (me->opts != NULL)
02187 freeArgs(mb);
02188
02189 s = se;
02190 }
02191
02192 *mb->t = '\0';
02193 mb->s = s;
02194 mb->depth--;
02195 if (rc != 0 || mb->expand_trace)
02196 printExpansion(mb, t, mb->t);
02197 return rc;
02198 }
02199
02200 #if defined(RPM_VENDOR_OPENPKG) || \
02201 !defined(POPT_ERROR_BADCONFIG)
02202 int rpmSecuritySaneFile(const char *filename)
02203 {
02204 struct stat sb;
02205 uid_t uid;
02206
02207 if (stat(filename, &sb) == -1)
02208 return 1;
02209 uid = getuid();
02210 if (sb.st_uid != uid)
02211 return 0;
02212 if (!S_ISREG(sb.st_mode))
02213 return 0;
02214 if (sb.st_mode & (S_IWGRP|S_IWOTH))
02215 return 0;
02216 return 1;
02217 }
02218 #endif
02219
02220 #if !defined(DEBUG_MACROS)
02221
02222
02223 static int _debug = 0;
02224
02225 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
02226 {
02227 int ac = 0;
02228 const char ** av = NULL;
02229 int argc = 0;
02230 const char ** argv = NULL;
02231 char * globRoot = NULL;
02232 #ifdef ENABLE_NLS
02233 const char * old_collate = NULL;
02234 const char * old_ctype = NULL;
02235 const char * t;
02236 #endif
02237 size_t maxb, nb;
02238 size_t i;
02239 int j;
02240 int rc;
02241
02242 rc = XpoptParseArgvString(patterns, &ac, &av);
02243 if (rc)
02244 return rc;
02245 #ifdef ENABLE_NLS
02246 t = setlocale(LC_COLLATE, NULL);
02247 if (t)
02248 old_collate = xstrdup(t);
02249 t = setlocale(LC_CTYPE, NULL);
02250 if (t)
02251 old_ctype = xstrdup(t);
02252 (void) setlocale(LC_COLLATE, "C");
02253 (void) setlocale(LC_CTYPE, "C");
02254 #endif
02255
02256 if (av != NULL)
02257 for (j = 0; j < ac; j++) {
02258 const char * globURL;
02259 const char * path;
02260 int ut = urlPath(av[j], &path);
02261 glob_t gl;
02262
02263 if (!Glob_pattern_p(av[j], 0) && strchr(path, '~') == NULL) {
02264 argv = xrealloc(argv, (argc+2) * sizeof(*argv));
02265 argv[argc] = xstrdup(av[j]);
02266 if (_debug)
02267 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]);
02268 argc++;
02269 continue;
02270 }
02271
02272 gl.gl_pathc = 0;
02273 gl.gl_pathv = NULL;
02274 rc = Glob(av[j], GLOB_TILDE, Glob_error, &gl);
02275 if (rc)
02276 goto exit;
02277
02278
02279 maxb = 0;
02280 for (i = 0; i < gl.gl_pathc; i++) {
02281 if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
02282 maxb = nb;
02283 }
02284
02285 nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0);
02286 maxb += nb;
02287 maxb += 1;
02288 globURL = globRoot = xmalloc(maxb);
02289
02290 switch (ut) {
02291 case URL_IS_PATH:
02292 case URL_IS_DASH:
02293 strncpy(globRoot, av[j], nb);
02294 break;
02295 case URL_IS_HTTPS:
02296 case URL_IS_HTTP:
02297 case URL_IS_FTP:
02298 case URL_IS_HKP:
02299 case URL_IS_UNKNOWN:
02300 default:
02301 break;
02302 }
02303 globRoot += nb;
02304 *globRoot = '\0';
02305 if (_debug)
02306 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
02307
02308 argv = xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
02309
02310 if (argv != NULL)
02311 for (i = 0; i < gl.gl_pathc; i++) {
02312 const char * globFile = &(gl.gl_pathv[i][0]);
02313 if (globRoot > globURL && globRoot[-1] == '/')
02314 while (*globFile == '/') globFile++;
02315 strcpy(globRoot, globFile);
02316 if (_debug)
02317 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
02318 argv[argc++] = xstrdup(globURL);
02319 }
02320
02321 Globfree(&gl);
02322
02323 globURL = _free(globURL);
02324 }
02325
02326 if (argv != NULL && argc > 0) {
02327 argv[argc] = NULL;
02328 if (argvPtr)
02329 *argvPtr = argv;
02330 if (argcPtr)
02331 *argcPtr = argc;
02332 rc = 0;
02333 } else
02334 rc = 1;
02335
02336
02337 exit:
02338 #ifdef ENABLE_NLS
02339 if (old_collate) {
02340 (void) setlocale(LC_COLLATE, old_collate);
02341 old_collate = _free(old_collate);
02342 }
02343 if (old_ctype) {
02344 (void) setlocale(LC_CTYPE, old_ctype);
02345 old_ctype = _free(old_ctype);
02346 }
02347 #endif
02348 av = _free(av);
02349 if (rc || argvPtr == NULL) {
02350
02351 if (argv != NULL)
02352 for (j = 0; j < argc; j++)
02353 argv[j] = _free(argv[j]);
02354 argv = _free(argv);
02355
02356 }
02357 return rc;
02358 }
02359 #endif
02360
02361
02362
02363 int
02364 expandMacros(void * spec, MacroContext mc, char * sbuf, size_t slen)
02365 {
02366 MacroBuf mb = alloca(sizeof(*mb));
02367 char *tbuf;
02368 int rc;
02369
02370 if (sbuf == NULL || slen == 0)
02371 return 0;
02372 if (mc == NULL) mc = rpmGlobalMacroContext;
02373
02374 tbuf = alloca(slen + 1);
02375 tbuf[0] = '\0';
02376
02377 mb->s = sbuf;
02378 mb->t = tbuf;
02379 mb->nb = slen;
02380 mb->depth = 0;
02381 mb->macro_trace = print_macro_trace;
02382 mb->expand_trace = print_expand_trace;
02383
02384 mb->spec = spec;
02385 mb->mc = mc;
02386
02387 rc = expandMacro(mb);
02388
02389 tbuf[slen] = '\0';
02390 if (mb->nb == 0)
02391 rpmlog(RPMLOG_ERR, _("Macro expansion too big for target buffer\n"));
02392 else
02393 strncpy(sbuf, tbuf, (slen - mb->nb + 1));
02394
02395 return rc;
02396 }
02397
02398 void
02399 addMacro(MacroContext mc,
02400 const char * n, const char * o, const char * b, int level)
02401 {
02402 MacroEntry * mep;
02403 const char * name = n;
02404
02405 if (*name == '.')
02406 name++;
02407 if (*name == '.')
02408 name++;
02409
02410 if (mc == NULL) mc = rpmGlobalMacroContext;
02411
02412
02413 if ((mep = findEntry(mc, name, 0)) == NULL) {
02414 if (mc->firstFree == mc->macrosAllocated)
02415 expandMacroTable(mc);
02416 if (mc->macroTable != NULL)
02417 mep = mc->macroTable + mc->firstFree++;
02418 }
02419
02420 if (mep != NULL) {
02421
02422 if (*mep && (*mep)->flags && !(n[0] == '.' && n[1] == '.')) {
02423
02424 if (strcmp((*mep)->name, "buildroot"))
02425 rpmlog(RPMLOG_ERR, _("Macro '%s' is readonly and cannot be changed.\n"), n);
02426 return;
02427 }
02428
02429 pushMacro(mep, n, o, b, level);
02430
02431
02432 if ((*mep)->prev == NULL)
02433 sortMacroTable(mc);
02434 }
02435 }
02436
02437 void
02438 delMacro(MacroContext mc, const char * n)
02439 {
02440 MacroEntry * mep;
02441
02442 if (mc == NULL) mc = rpmGlobalMacroContext;
02443
02444 if ((mep = findEntry(mc, n, 0)) != NULL) {
02445 popMacro(mep);
02446
02447 if (!(mep && *mep))
02448 sortMacroTable(mc);
02449 }
02450 }
02451
02452
02453 int
02454 rpmDefineMacro(MacroContext mc, const char * macro, int level)
02455 {
02456 MacroBuf mb = alloca(sizeof(*mb));
02457
02458 memset(mb, 0, sizeof(*mb));
02459
02460 mb->mc = (mc ? mc : rpmGlobalMacroContext);
02461 (void) doDefine(mb, macro, level, 0);
02462 return 0;
02463 }
02464
02465
02466
02467 int
02468 rpmUndefineMacro(MacroContext mc, const char * macro)
02469 {
02470 (void) doUndefine(mc ? mc : rpmGlobalMacroContext, macro);
02471 return 0;
02472 }
02473
02474
02475 void
02476 rpmLoadMacros(MacroContext mc, int level)
02477 {
02478
02479 if (mc == NULL || mc == rpmGlobalMacroContext)
02480 return;
02481
02482 if (mc->macroTable != NULL) {
02483 int i;
02484 for (i = 0; i < mc->firstFree; i++) {
02485 MacroEntry *mep, me;
02486 mep = &mc->macroTable[i];
02487 me = *mep;
02488
02489 if (me == NULL)
02490 continue;
02491 addMacro(NULL, me->name, me->opts, me->body, (level - 1));
02492 }
02493 }
02494 }
02495
02496 #if defined(RPM_VENDOR_OPENPKG)
02497 static void expand_macrosfile_macro(const char *file_name, const char *buf, size_t bufn)
02498 {
02499 char *cp;
02500 size_t l, k;
02501 static const char *macro_name = "%{macrosfile}";
02502
02503 l = strlen(macro_name);
02504 k = strlen(file_name);
02505 while ((cp = strstr(buf, macro_name)) != NULL) {
02506 if (((strlen(buf) - l) + k) < bufn) {
02507 memmove(cp+k, cp+l, strlen(cp+l)+1);
02508 memcpy(cp, file_name, k);
02509 }
02510 }
02511 return;
02512 }
02513 #endif
02514
02515 int
02516 rpmLoadMacroFile(MacroContext mc, const char * fn)
02517 {
02518
02519 FD_t fd = Fopen(fn, "r.fpio");
02520 size_t bufn = _macro_BUFSIZ;
02521 char *buf = alloca(bufn);
02522 int rc = -1;
02523
02524 if (fd == NULL || Ferror(fd)) {
02525 if (fd) (void) Fclose(fd);
02526 return rc;
02527 }
02528
02529
02530
02531 max_macro_depth = _MAX_MACRO_DEPTH;
02532
02533
02534 buf[0] = '\0';
02535 while(rdcl(buf, bufn, fd) != NULL) {
02536 char *n;
02537 int c;
02538
02539 n = buf;
02540 SKIPBLANK(n, c);
02541
02542 if (c != (int) '%')
02543 continue;
02544 n++;
02545 #if defined(RPM_VENDOR_OPENPKG)
02546 expand_macrosfile_macro(fn, buf, bufn);
02547 #endif
02548 rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
02549 }
02550 rc = Fclose(fd);
02551 return rc;
02552 }
02553
02554 void
02555 rpmInitMacros(MacroContext mc, const char * macrofiles)
02556 {
02557 char *mfiles, *m, *me;
02558
02559 if (macrofiles == NULL)
02560 return;
02561 #ifdef DYING
02562 if (mc == NULL) mc = rpmGlobalMacroContext;
02563 #endif
02564
02565 mfiles = xstrdup(macrofiles);
02566 for (m = mfiles; m && *m != '\0'; m = me) {
02567 const char ** av;
02568 int ac;
02569 int i;
02570
02571 for (me = m; (me = strchr(me, ':')) != NULL; me++) {
02572
02573 if (!(me[1] == '/' && me[2] == '/'))
02574 break;
02575 }
02576
02577 if (me && *me == ':')
02578 *me++ = '\0';
02579 else
02580 me = m + strlen(m);
02581
02582
02583 ac = 0;
02584 av = NULL;
02585 #if defined(DEBUG_MACROS)
02586 ac = 1;
02587 av = xmalloc((ac + 1) * sizeof(*av));
02588 av[0] = strdup(m);
02589 av[1] = NULL;
02590 #else
02591 i = rpmGlob(m, &ac, &av);
02592 if (i != 0)
02593 continue;
02594 #endif
02595
02596
02597
02598 for (i = 0; i < ac; i++) {
02599 size_t slen = strlen(av[i]);
02600 const char *fn = av[i];
02601
02602 if (fn[0] == '@' ) {
02603 fn++;
02604 #if defined(RPM_VENDOR_OPENPKG) || \
02605 !defined(POPT_ERROR_BADCONFIG)
02606 if (!rpmSecuritySaneFile(fn))
02607 #else
02608 if (!poptSaneFile(fn))
02609 #endif
02610 {
02611 rpmlog(RPMLOG_WARNING, "existing RPM macros file \"%s\" considered INSECURE -- not loaded\n", fn);
02612 continue;
02613 }
02614 }
02615
02616
02617 #define _suffix(_s, _x) \
02618 (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
02619 if (!(_suffix(fn, "~")
02620 || _suffix(fn, ".rpmnew")
02621 || _suffix(fn, ".rpmorig")
02622 || _suffix(fn, ".rpmsave"))
02623 )
02624 (void) rpmLoadMacroFile(mc, fn);
02625 #undef _suffix
02626
02627 av[i] = _free(av[i]);
02628 }
02629 av = _free(av);
02630 }
02631 mfiles = _free(mfiles);
02632
02633
02634
02635 rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
02636
02637 }
02638
02639
02640 void
02641 rpmFreeMacros(MacroContext mc)
02642 {
02643
02644 if (mc == NULL) mc = rpmGlobalMacroContext;
02645
02646 if (mc->macroTable != NULL) {
02647 int i;
02648 for (i = 0; i < mc->firstFree; i++) {
02649 MacroEntry me;
02650 while ((me = mc->macroTable[i]) != NULL) {
02651
02652
02653 if ((mc->macroTable[i] = me->prev) == NULL)
02654 me->name = _free(me->name);
02655
02656 me->opts = _free(me->opts);
02657 me->body = _free(me->body);
02658 me = _free(me);
02659 }
02660 }
02661 mc->macroTable = _free(mc->macroTable);
02662 }
02663 memset(mc, 0, sizeof(*mc));
02664 }
02665
02666
02667
02668 int isCompressed(const char * file, rpmCompressedMagic * compressed)
02669 {
02670 FD_t fd;
02671 ssize_t nb;
02672 int rc = -1;
02673 unsigned char magic[13];
02674 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA)
02675 size_t file_len;
02676 #endif
02677
02678 *compressed = COMPRESSED_NOT;
02679
02680 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA)
02681 file_len = strlen(file);
02682 if ((file_len > 4 && strcasecmp(file+file_len-4, ".tbz") == 0)
02683 || (file_len > 4 && strcasecmp(file+file_len-4, ".bz2") == 0)) {
02684 *compressed = COMPRESSED_BZIP2;
02685 return 0;
02686 } else
02687 if (file_len > 4 && strcasecmp(file+file_len-4, ".zip") == 0) {
02688 *compressed = COMPRESSED_ZIP;
02689 return 0;
02690 } else
02691 if ((file_len > 4 && strcasecmp(file+file_len-4, ".tlz") == 0)
02692 || (file_len > 5 && strcasecmp(file+file_len-5, ".lzma") == 0)) {
02693 *compressed = COMPRESSED_LZMA;
02694 return 0;
02695 } else
02696 if (file_len > 4 && strcasecmp(file+file_len-3, ".xz") == 0) {
02697 *compressed = COMPRESSED_XZ;
02698 return 0;
02699 } else
02700 if ((file_len > 4 && strcasecmp(file+file_len-4, ".tgz") == 0)
02701 || (file_len > 3 && strcasecmp(file+file_len-3, ".gz") == 0)
02702 || (file_len > 2 && strcasecmp(file+file_len-2, ".Z") == 0)) {
02703 *compressed = COMPRESSED_OTHER;
02704 return 0;
02705 } else
02706 if (file_len > 5 && strcasecmp(file+file_len-5, ".cpio") == 0) {
02707 *compressed = COMPRESSED_NOT;
02708 return 0;
02709 } else
02710 if (file_len > 4 && strcasecmp(file+file_len-4, ".tar") == 0) {
02711 *compressed = COMPRESSED_NOT;
02712 return 0;
02713 }
02714 #endif
02715
02716 fd = Fopen(file, "r");
02717 if (fd == NULL || Ferror(fd)) {
02718
02719 rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd));
02720 if (fd) (void) Fclose(fd);
02721 return 1;
02722 }
02723 nb = Fread(magic, sizeof(magic[0]), sizeof(magic), fd);
02724 if (nb < (ssize_t)0) {
02725 rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd));
02726 rc = 1;
02727 } else if (nb < (ssize_t)sizeof(magic)) {
02728 rpmlog(RPMLOG_ERR, _("File %s is smaller than %u bytes\n"),
02729 file, (unsigned)sizeof(magic));
02730 rc = 0;
02731 }
02732 (void) Fclose(fd);
02733 if (rc >= 0)
02734 return rc;
02735
02736 rc = 0;
02737
02738 if (magic[0] == 'B' && magic[1] == 'Z')
02739 *compressed = COMPRESSED_BZIP2;
02740 else
02741 if (magic[0] == (unsigned char) 0120 && magic[1] == (unsigned char) 0113
02742 && magic[2] == (unsigned char) 0003 && magic[3] == (unsigned char) 0004)
02743 *compressed = COMPRESSED_ZIP;
02744 else
02745 if (magic[0] == (unsigned char) 0x89 && magic[1] == 'L'
02746 && magic[2] == 'Z' && magic[3] == 'O')
02747 *compressed = COMPRESSED_LZOP;
02748 else
02749 #if !defined(RPM_VENDOR_OPENPKG) && !defined(RPM_VENDOR_FEDORA) && !defined(RPM_VENDOR_MANDRIVA)
02750
02751 if (magic[ 9] == (unsigned char) 0x00 && magic[10] == (unsigned char) 0x00 &&
02752 magic[11] == (unsigned char) 0x00 && magic[12] == (unsigned char) 0x00)
02753 *compressed = COMPRESSED_LZMA;
02754 else
02755 #endif
02756 #if defined(RPM_VENDOR_OPENSUSE)
02757 if (magic[0] == 0135 && magic[1] == 0 && magic[2] == 0) {
02758 *compressed = COMPRESSED_LZMA;
02759 else
02760 #endif
02761 if (magic[0] == (unsigned char) 0xFD && magic[1] == 0x37 && magic[2] == 0x7A
02762 && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
02763 *compressed = COMPRESSED_XZ;
02764 else
02765 if ((magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0213)
02766 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0236)
02767 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0036)
02768 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0240)
02769 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0235))
02770 *compressed = COMPRESSED_OTHER;
02771
02772 return rc;
02773 }
02774
02775
02776
02777
02778
02779 char *
02780 rpmExpand(const char *arg, ...)
02781 {
02782 MacroContext mc = NULL;
02783 const char *s;
02784 char *t, *te;
02785 size_t sn, tn;
02786 size_t bufn = 8 * _macro_BUFSIZ;
02787
02788 va_list ap;
02789
02790 if (arg == NULL)
02791 return xstrdup("");
02792
02793 t = xmalloc(bufn + strlen(arg) + 1);
02794 *t = '\0';
02795 te = stpcpy(t, arg);
02796
02797 va_start(ap, arg);
02798 while ((s = va_arg(ap, const char *)) != NULL) {
02799 sn = strlen(s);
02800 tn = (te - t);
02801 t = xrealloc(t, tn + sn + bufn + 1);
02802 te = t + tn;
02803 te = stpcpy(te, s);
02804 }
02805 va_end(ap);
02806
02807 *te = '\0';
02808 tn = (te - t);
02809 (void) expandMacros(NULL, mc, t, tn + bufn + 1);
02810 t[tn + bufn] = '\0';
02811 t = xrealloc(t, strlen(t) + 1);
02812
02813 return t;
02814 }
02815
02816 char *
02817 rpmMCExpand(MacroContext mc, const char *arg, ...)
02818 {
02819 const char *s;
02820 char *t, *te;
02821 size_t sn, tn;
02822 size_t bufn = 8 * _macro_BUFSIZ;
02823
02824 va_list ap;
02825
02826 if (arg == NULL)
02827 return xstrdup("");
02828
02829 t = xmalloc(bufn + strlen(arg) + 1);
02830 *t = '\0';
02831 te = stpcpy(t, arg);
02832
02833 va_start(ap, arg);
02834 while ((s = va_arg(ap, const char *)) != NULL) {
02835 sn = strlen(s);
02836 tn = (te - t);
02837 t = xrealloc(t, tn + sn + bufn + 1);
02838 te = t + tn;
02839 te = stpcpy(te, s);
02840 }
02841 va_end(ap);
02842
02843 *te = '\0';
02844 tn = (te - t);
02845 (void) expandMacros(NULL, mc, t, tn + bufn + 1);
02846 t[tn + bufn] = '\0';
02847 t = xrealloc(t, strlen(t) + 1);
02848
02849 return t;
02850 }
02851
02852
02853 int
02854 rpmExpandNumeric(const char *arg)
02855 {
02856 const char *val;
02857 int rc;
02858
02859 if (arg == NULL)
02860 return 0;
02861
02862 val = rpmExpand(arg, NULL);
02863 if (!(val && *val != '%'))
02864 rc = 0;
02865 else if (*val == 'Y' || *val == 'y')
02866 rc = 1;
02867 else if (*val == 'N' || *val == 'n')
02868 rc = 0;
02869 else {
02870 char *end;
02871 rc = strtol(val, &end, 0);
02872 if (!(end && *end == '\0'))
02873 rc = 0;
02874 }
02875 val = _free(val);
02876
02877 return rc;
02878 }
02879
02880
02881 char *rpmCleanPath(char * path)
02882 {
02883 const char *s;
02884 char *se, *t, *te;
02885 int begin = 1;
02886
02887 if (path == NULL)
02888 return NULL;
02889
02890
02891 s = t = te = path;
02892 while (*s != '\0') {
02893
02894 switch(*s) {
02895 case ':':
02896 if (s[1] == '/' && s[2] == '/') {
02897 *t++ = *s++;
02898 *t++ = *s++;
02899
02900 if (s[0] == '/') *t++ = *s++;
02901 te = t;
02902 break;
02903 }
02904 begin=1;
02905 break;
02906 case '/':
02907
02908 for (se = te + 1; se < t && *se != '/'; se++)
02909 {};
02910 if (se < t && *se == '/') {
02911 te = se;
02912
02913 }
02914 while (s[1] == '/')
02915 s++;
02916 while (t > te && t[-1] == '/')
02917 t--;
02918 break;
02919 case '.':
02920
02921
02922
02923
02924
02925
02926 if (begin && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
02927
02928 *t++ = *s++;
02929 break;
02930 }
02931
02932 if (begin && s[1] == '\0') {
02933 break;
02934 }
02935 if (t > path && t[-1] == '/')
02936 switch (s[1]) {
02937 case '/': s++;
02938 case '\0': s++; continue;
02939 default: break;
02940 }
02941
02942 if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
02943 t = te;
02944
02945 if (te > path)
02946 for (--te; te > path && *te != '/'; te--)
02947 {};
02948
02949 s++;
02950 s++;
02951 continue;
02952 }
02953 break;
02954 default:
02955 begin = 0;
02956 break;
02957 }
02958 *t++ = *s++;
02959 }
02960
02961
02962 if (t > &path[1] && t[-1] == '/')
02963 t--;
02964 *t = '\0';
02965
02966
02967 return path;
02968 }
02969
02970
02971
02972 const char *
02973 rpmGetPath(const char *path, ...)
02974 {
02975 size_t bufn = _macro_BUFSIZ;
02976 char *buf = alloca(bufn);
02977 const char * s;
02978 char * t, * te;
02979 va_list ap;
02980
02981 if (path == NULL)
02982 return xstrdup("");
02983
02984 buf[0] = '\0';
02985 t = buf;
02986 te = stpcpy(t, path);
02987 *te = '\0';
02988
02989 va_start(ap, path);
02990 while ((s = va_arg(ap, const char *)) != NULL) {
02991 te = stpcpy(te, s);
02992 *te = '\0';
02993 }
02994 va_end(ap);
02995
02996 (void) expandMacros(NULL, NULL, buf, bufn);
02997
02998
02999 (void) rpmCleanPath(buf);
03000 return xstrdup(buf);
03001 }
03002
03003
03004
03005 const char * rpmGenPath(const char * urlroot, const char * urlmdir,
03006 const char *urlfile)
03007 {
03008 const char * xroot = rpmGetPath(urlroot, NULL);
03009 const char * root = xroot;
03010 const char * xmdir = rpmGetPath(urlmdir, NULL);
03011 const char * mdir = xmdir;
03012 const char * xfile = rpmGetPath(urlfile, NULL);
03013 const char * file = xfile;
03014 const char * result;
03015 const char * url = NULL;
03016 int nurl = 0;
03017 int ut;
03018
03019 #if 0
03020 if (_debug) fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile);
03021 #endif
03022 ut = urlPath(xroot, &root);
03023 if (url == NULL && ut > URL_IS_DASH) {
03024 url = xroot;
03025 nurl = root - xroot;
03026 #if 0
03027 if (_debug) fprintf(stderr, "*** RGP ut %d root %s nurl %d\n", ut, root, nurl);
03028 #endif
03029 }
03030 if (root == NULL || *root == '\0') root = "/";
03031
03032 ut = urlPath(xmdir, &mdir);
03033 if (url == NULL && ut > URL_IS_DASH) {
03034 url = xmdir;
03035 nurl = mdir - xmdir;
03036 #if 0
03037 if (_debug) fprintf(stderr, "*** RGP ut %d mdir %s nurl %d\n", ut, mdir, nurl);
03038 #endif
03039 }
03040 if (mdir == NULL || *mdir == '\0') mdir = "/";
03041
03042 ut = urlPath(xfile, &file);
03043 if (url == NULL && ut > URL_IS_DASH) {
03044 url = xfile;
03045 nurl = file - xfile;
03046 #if 0
03047 if (_debug) fprintf(stderr, "*** RGP ut %d file %s nurl %d\n", ut, file, nurl);
03048 #endif
03049 }
03050
03051 if (url && nurl > 0) {
03052 char *t = strncpy(alloca(nurl+1), url, nurl);
03053 t[nurl] = '\0';
03054 url = t;
03055 } else
03056 url = "";
03057
03058 result = rpmGetPath(url, root, "/", mdir, "/", file, NULL);
03059
03060 xroot = _free(xroot);
03061 xmdir = _free(xmdir);
03062 xfile = _free(xfile);
03063 #if 0
03064 if (_debug) fprintf(stderr, "*** RGP result %s\n", result);
03065 #endif
03066 return result;
03067 }
03068
03069
03070
03071 #if defined(DEBUG_MACROS)
03072
03073 #if defined(EVAL_MACROS)
03074
03075 const char *rpmMacrofiles = MACROFILES;
03076
03077 int
03078 main(int argc, char *argv[])
03079 {
03080 int c;
03081 int errflg = 0;
03082 extern char *optarg;
03083 extern int optind;
03084
03085 while ((c = getopt(argc, argv, "f:")) != EOF ) {
03086 switch (c) {
03087 case 'f':
03088 rpmMacrofiles = optarg;
03089 break;
03090 case '?':
03091 default:
03092 errflg++;
03093 break;
03094 }
03095 }
03096 if (errflg || optind >= argc) {
03097 fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
03098 exit(1);
03099 }
03100
03101 rpmInitMacros(NULL, rpmMacrofiles);
03102
03103 for ( ; optind < argc; optind++) {
03104 const char *val;
03105
03106 val = rpmExpand(argv[optind], NULL);
03107 if (val) {
03108 fprintf(stdout, "%s:\t%s\n", argv[optind], val);
03109 val = _free(val);
03110 }
03111 }
03112 rpmFreeMacros(NULL);
03113 return 0;
03114 }
03115
03116 #else
03117
03118 const char *rpmMacrofiles = "../macros:./testmacros";
03119 const char *testfile = "./test";
03120
03121 int
03122 main(int argc, char *argv[])
03123 {
03124 size_t bufn = _macro_BUFSIZ;
03125 char *buf = alloca(bufn);
03126 FILE *fp;
03127 int x;
03128
03129 rpmInitMacros(NULL, rpmMacrofiles);
03130
03131 if ((fp = fopen(testfile, "r")) != NULL) {
03132 while(rdcl(buf, bufn, fp)) {
03133 x = expandMacros(NULL, NULL, buf, bufn);
03134 fprintf(stderr, "%d->%s\n", x, buf);
03135 memset(buf, 0, bufn);
03136 }
03137 fclose(fp);
03138 }
03139
03140 while(rdcl(buf, bufn, stdin)) {
03141 x = expandMacros(NULL, NULL, buf, bufn);
03142 fprintf(stderr, "%d->%s\n <-\n", x, buf);
03143 memset(buf, 0, bufn);
03144 }
03145 rpmFreeMacros(NULL);
03146
03147 return 0;
03148 }
03149 #endif
03150 #endif