|
rpm
5.4.4
|
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 /* XXX fixme */ 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 /*@unused@*/ static inline /*@null@*/ void * 00052 _free(/*@only@*/ /*@null@*/ const void * p) 00053 /*@modifies p@*/ 00054 { 00055 if (p != NULL) free((void *)p); 00056 return NULL; 00057 } 00058 00059 #else 00060 00061 /*@observer@*/ /*@checked@*/ 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 /* XXX lua->printbuf access */ 00070 #include <rpmlua.h> 00071 #endif 00072 00073 #define _RPMAUG_INTERNAL /* XXX for _rpmaugFoo globals */ 00074 #include <rpmaug.h> 00075 #include <rpmficl.h> 00076 #include <rpmjs.h> 00077 00078 #if defined(WITH_NIX) 00079 #define _RPMNIX_INTERNAL 00080 #include <rpmnix.h> 00081 #endif 00082 00083 #include <rpmjs.h> 00084 #include <rpmperl.h> 00085 #include <rpmpython.h> 00086 #include <rpmruby.h> 00087 #include <rpmsm.h> 00088 #include <rpmsquirrel.h> 00089 #include <rpmsql.h> 00090 #include <rpmtcl.h> 00091 00092 #endif 00093 00094 #include <rpmuuid.h> 00095 00096 #define _MACRO_INTERNAL 00097 #include <rpmmacro.h> 00098 00099 #include "debug.h" 00100 00101 /*@unchecked@*/ 00102 #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) 00103 static int _globalI = 0x80000000; 00104 #endif 00105 00106 #if defined(__LCLINT__) 00107 /*@-exportheader@*/ 00108 extern const unsigned short int **__ctype_b_loc (void) /*@*/; 00109 /*@=exportheader@*/ 00110 #endif 00111 00112 /*@access FD_t @*/ /* XXX compared with NULL */ 00113 /*@access miRE @*/ /* XXX cast */ 00114 /*@access MacroContext @*/ 00115 /*@access MacroEntry@ */ 00116 /*@access rpmlua @*/ 00117 /*@access rpmtcl @*/ 00118 00119 static struct MacroContext_s rpmGlobalMacroContext_s; 00120 /*@-compmempass@*/ 00121 MacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s; 00122 /*@=compmempass@*/ 00123 00124 static struct MacroContext_s rpmCLIMacroContext_s; 00125 /*@-compmempass@*/ 00126 MacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s; 00127 /*@=compmempass@*/ 00128 00132 typedef /*@abstract@*/ struct MacroBuf_s { 00133 /*@kept@*/ /*@exposed@*/ 00134 const char * s; 00135 /*@shared@*/ 00136 char * t; 00137 size_t nb; 00138 int depth; 00139 int macro_trace; 00140 int expand_trace; 00141 /*@kept@*/ /*@exposed@*/ /*@null@*/ 00142 void * spec; 00143 /*@kept@*/ /*@exposed@*/ 00144 MacroContext mc; 00145 } * MacroBuf; 00146 00147 #define SAVECHAR(_mb, _c) { *(_mb)->t = (char) (_c), (_mb)->t++, (_mb)->nb--; } 00148 00149 /*@-exportlocal -exportheadervar@*/ 00150 00151 #define _MAX_MACRO_DEPTH 16 00152 /*@unchecked@*/ 00153 int max_macro_depth = _MAX_MACRO_DEPTH; 00154 00155 #define _PRINT_MACRO_TRACE 0 00156 /*@unchecked@*/ 00157 int print_macro_trace = _PRINT_MACRO_TRACE; 00158 00159 #define _PRINT_EXPAND_TRACE 0 00160 /*@unchecked@*/ 00161 int print_expand_trace = _PRINT_EXPAND_TRACE; 00162 00163 #define _MAX_LOAD_DEPTH 2 00164 /*@unchecked@*/ 00165 int _max_load_depth = _MAX_LOAD_DEPTH; 00166 /*@=exportlocal =exportheadervar@*/ 00167 00168 #define MACRO_CHUNK_SIZE 16 00169 00170 /* Size of expansion buffers. */ 00171 /*@unchecked@*/ 00172 static size_t _macro_BUFSIZ = 16 * 1024; 00173 00174 /* forward ref */ 00175 static int expandMacro(MacroBuf mb) 00176 /*@globals rpmGlobalMacroContext, 00177 print_macro_trace, print_expand_trace, h_errno, 00178 fileSystem, internalState @*/ 00179 /*@modifies mb, rpmGlobalMacroContext, 00180 print_macro_trace, print_expand_trace, 00181 fileSystem, internalState @*/; 00182 00183 /* =============================================================== */ 00184 00191 static int 00192 compareMacroName(const void * ap, const void * bp) 00193 /*@*/ 00194 { 00195 MacroEntry ame = *((MacroEntry *)ap); 00196 MacroEntry bme = *((MacroEntry *)bp); 00197 00198 if (ame == NULL && bme == NULL) 00199 return 0; 00200 if (ame == NULL) 00201 return 1; 00202 if (bme == NULL) 00203 return -1; 00204 return strcmp(ame->name, bme->name); 00205 } 00206 00211 static void 00212 expandMacroTable(MacroContext mc) 00213 /*@modifies mc @*/ 00214 { 00215 if (mc->macroTable == NULL) { 00216 mc->macrosAllocated = MACRO_CHUNK_SIZE; 00217 mc->macroTable = (MacroEntry *) 00218 xmalloc(sizeof(*mc->macroTable) * mc->macrosAllocated); 00219 mc->firstFree = 0; 00220 } else { 00221 mc->macrosAllocated += MACRO_CHUNK_SIZE; 00222 mc->macroTable = (MacroEntry *) 00223 xrealloc(mc->macroTable, sizeof(*mc->macroTable) * 00224 mc->macrosAllocated); 00225 } 00226 memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable))); 00227 } 00228 00233 static void 00234 sortMacroTable(MacroContext mc) 00235 /*@modifies mc @*/ 00236 { 00237 int i; 00238 00239 if (mc == NULL || mc->macroTable == NULL) 00240 return; 00241 00242 qsort(mc->macroTable, mc->firstFree, sizeof(mc->macroTable[0]), 00243 compareMacroName); 00244 00245 /* Empty pointers are now at end of table. Reset first free index. */ 00246 for (i = 0; i < mc->firstFree; i++) { 00247 if (mc->macroTable[i] != NULL) 00248 continue; 00249 mc->firstFree = i; 00250 break; 00251 } 00252 } 00253 00254 #if !defined(DEBUG_MACROS) 00255 /*@only@*/ 00256 static char * dupMacroEntry(MacroEntry me) 00257 /*@*/ 00258 { 00259 char * t, * te; 00260 size_t nb; 00261 00262 assert(me != NULL); 00263 nb = strlen(me->name) + sizeof("%") - 1; 00264 if (me->opts) 00265 nb += strlen(me->opts) + sizeof("()") - 1; 00266 if (me->body) 00267 nb += strlen(me->body) + sizeof("\t") - 1; 00268 nb++; 00269 00270 t = te = xmalloc(nb); 00271 *te = '\0'; 00272 te = stpcpy( stpcpy(te, "%"), me->name); 00273 if (me->opts) 00274 te = stpcpy( stpcpy( stpcpy(te, "("), me->opts), ")"); 00275 if (me->body) 00276 te = stpcpy( stpcpy(te, "\t"), me->body); 00277 *te = '\0'; 00278 00279 return t; 00280 } 00281 #endif 00282 00283 void 00284 rpmDumpMacroTable(MacroContext mc, FILE * fp) 00285 { 00286 int nempty = 0; 00287 int nactive = 0; 00288 00289 if (mc == NULL) mc = rpmGlobalMacroContext; 00290 if (fp == NULL) fp = stderr; 00291 00292 fprintf(fp, "========================\n"); 00293 if (mc->macroTable != NULL) { 00294 int i; 00295 for (i = 0; i < mc->firstFree; i++) { 00296 MacroEntry me; 00297 if ((me = mc->macroTable[i]) == NULL) { 00298 /* XXX this should never happen */ 00299 nempty++; 00300 continue; 00301 } 00302 fprintf(fp, "%3d%c %s", me->level, 00303 (me->used > 0 ? '=' : ':'), me->name); 00304 if (me->opts && *me->opts) 00305 fprintf(fp, "(%s)", me->opts); 00306 if (me->body && *me->body) 00307 fprintf(fp, "\t%s", me->body); 00308 fprintf(fp, "\n"); 00309 nactive++; 00310 } 00311 } 00312 fprintf(fp, _("======================== active %d empty %d\n"), 00313 nactive, nempty); 00314 } 00315 00316 #if !defined(DEBUG_MACROS) 00317 int 00318 rpmGetMacroEntries(MacroContext mc, void * _mire, int used, 00319 const char *** avp) 00320 { 00321 /*@-assignexpose -castexpose @*/ 00322 miRE mire = (miRE) _mire; 00323 /*@=assignexpose =castexpose @*/ 00324 const char ** av; 00325 int ac = 0; 00326 int i; 00327 00328 if (mc == NULL) 00329 mc = rpmGlobalMacroContext; 00330 00331 if (avp == NULL) 00332 return mc->firstFree; 00333 00334 av = xcalloc( (mc->firstFree+1), sizeof(mc->macroTable[0])); 00335 if (mc->macroTable != NULL) 00336 for (i = 0; i < mc->firstFree; i++) { 00337 MacroEntry me; 00338 me = mc->macroTable[i]; 00339 if (used > 0 && me->used < used) 00340 continue; 00341 if (used == 0 && me->used != 0) 00342 continue; 00343 #if !defined(DEBUG_MACROS) /* XXX preserve standalone build */ 00344 if (mire != NULL && mireRegexec(mire, me->name, 0) < 0) 00345 continue; 00346 #endif 00347 av[ac++] = dupMacroEntry(me); 00348 } 00349 av[ac] = NULL; 00350 *avp = av = xrealloc(av, (ac+1) * sizeof(*av)); 00351 00352 return ac; 00353 } 00354 #endif 00355 00363 /*@dependent@*/ /*@null@*/ 00364 static MacroEntry * 00365 findEntry(MacroContext mc, const char * name, size_t namelen) 00366 /*@*/ 00367 { 00368 MacroEntry key, *ret; 00369 00370 /*@-globs@*/ 00371 if (mc == NULL) mc = rpmGlobalMacroContext; 00372 /*@=globs@*/ 00373 if (mc->macroTable == NULL || mc->firstFree == 0) 00374 return NULL; 00375 00376 if (namelen > 0) { 00377 char * t = strncpy(alloca(namelen + 1), name, namelen); 00378 t[namelen] = '\0'; 00379 name = t; 00380 } 00381 00382 key = memset(alloca(sizeof(*key)), 0, sizeof(*key)); 00383 /*@-temptrans -assignexpose@*/ 00384 key->name = (char *)name; 00385 /*@=temptrans =assignexpose@*/ 00386 ret = (MacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree, 00387 sizeof(*(mc->macroTable)), compareMacroName); 00388 /* XXX TODO: find 1st empty slot and return that */ 00389 return ret; 00390 } 00391 00392 /* =============================================================== */ 00393 00401 /*@null@*/ 00402 static char * 00403 rdcl(/*@returned@*/ char * buf, size_t size, FD_t fd) 00404 /*@globals fileSystem @*/ 00405 /*@modifies buf, fileSystem @*/ 00406 { 00407 char *q = buf - 1; /* initialize just before buffer. */ 00408 size_t nb = 0; 00409 size_t nread = 0; 00410 FILE * f = fdGetFILE(fd); 00411 int pc = 0, bc = 0; 00412 char *p = buf; 00413 00414 if (f != NULL) 00415 do { 00416 *(++q) = '\0'; /* terminate and move forward. */ 00417 if (fgets(q, (int)size, f) == NULL) /* read next line. */ 00418 break; 00419 nb = strlen(q); 00420 nread += nb; /* trim trailing \r and \n */ 00421 for (q += nb - 1; nb > 0 && iseol(*q); q--) 00422 nb--; 00423 for (; p <= q; p++) { 00424 switch (*p) { 00425 case '\\': 00426 switch (*(p+1)) { 00427 case '\r': /*@switchbreak@*/ break; 00428 case '\n': /*@switchbreak@*/ break; 00429 case '\0': /*@switchbreak@*/ break; 00430 default: p++; /*@switchbreak@*/ break; 00431 } 00432 /*@switchbreak@*/ break; 00433 case '%': 00434 switch (*(p+1)) { 00435 case '{': p++, bc++; /*@switchbreak@*/ break; 00436 case '(': p++, pc++; /*@switchbreak@*/ break; 00437 case '%': p++; /*@switchbreak@*/ break; 00438 } 00439 /*@switchbreak@*/ break; 00440 case '{': if (bc > 0) bc++; /*@switchbreak@*/ break; 00441 case '}': if (bc > 0) bc--; /*@switchbreak@*/ break; 00442 case '(': if (pc > 0) pc++; /*@switchbreak@*/ break; 00443 case ')': if (pc > 0) pc--; /*@switchbreak@*/ break; 00444 } 00445 } 00446 if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') { 00447 *(++q) = '\0'; /* trim trailing \r, \n */ 00448 break; 00449 } 00450 q++; p++; nb++; /* copy newline too */ 00451 size -= nb; 00452 if (*q == '\r') /* XXX avoid \r madness */ 00453 *q = '\n'; 00454 } while (size > 0); 00455 return (nread > 0 ? buf : NULL); 00456 } 00457 00465 /*@null@*/ 00466 static const char * 00467 matchchar(const char * p, char pl, char pr) 00468 /*@*/ 00469 { 00470 int lvl = 0; 00471 char c; 00472 00473 while ((c = *p++) != '\0') { 00474 if (c == '\\') { /* Ignore escaped chars */ 00475 p++; 00476 continue; 00477 } 00478 if (c == pr) { 00479 if (--lvl <= 0) return --p; 00480 } else if (c == pl) 00481 lvl++; 00482 } 00483 return (const char *)NULL; 00484 } 00485 00492 static void 00493 printMacro(MacroBuf mb, const char * s, const char * se) 00494 /*@globals fileSystem @*/ 00495 /*@modifies fileSystem @*/ 00496 { 00497 const char *senl; 00498 const char *ellipsis; 00499 int choplen; 00500 00501 if (s >= se) { /* XXX just in case */ 00502 fprintf(stderr, _("%3d>%*s(empty)"), mb->depth, 00503 (2 * mb->depth + 1), ""); 00504 return; 00505 } 00506 00507 if (s[-1] == '{') 00508 s--; 00509 00510 /* Print only to first end-of-line (or end-of-string). */ 00511 for (senl = se; *senl && !iseol(*senl); senl++) 00512 {}; 00513 00514 /* Limit trailing non-trace output */ 00515 choplen = 61 - (2 * mb->depth); 00516 if ((senl - s) > choplen) { 00517 senl = s + choplen; 00518 ellipsis = "..."; 00519 } else 00520 ellipsis = ""; 00521 00522 /* Substitute caret at end-of-macro position */ 00523 fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth, 00524 (2 * mb->depth + 1), "", (int)(se - s), s); 00525 if (se[1] != '\0' && (senl - (se+1)) > 0) 00526 fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis); 00527 fprintf(stderr, "\n"); 00528 } 00529 00536 static void 00537 printExpansion(MacroBuf mb, const char * t, const char * te) 00538 /*@globals fileSystem @*/ 00539 /*@modifies fileSystem @*/ 00540 { 00541 const char *ellipsis; 00542 int choplen; 00543 00544 if (!(te > t)) { 00545 fprintf(stderr, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), ""); 00546 return; 00547 } 00548 00549 /* Shorten output which contains newlines */ 00550 while (te > t && iseol(te[-1])) 00551 te--; 00552 ellipsis = ""; 00553 if (mb->depth > 0) { 00554 const char *tenl; 00555 00556 /* Skip to last line of expansion */ 00557 while ((tenl = strchr(t, '\n')) && tenl < te) 00558 t = ++tenl; 00559 00560 /* Limit expand output */ 00561 choplen = 61 - (2 * mb->depth); 00562 if ((te - t) > choplen) { 00563 te = t + choplen; 00564 ellipsis = "..."; 00565 } 00566 } 00567 00568 fprintf(stderr, "%3d<%*s", mb->depth, (2 * mb->depth + 1), ""); 00569 if (te > t) 00570 fprintf(stderr, "%.*s%s", (int)(te - t), t, ellipsis); 00571 fprintf(stderr, "\n"); 00572 } 00573 00574 #define SKIPBLANK(_s, _c) \ 00575 /*@-globs@*/ /* FIX: __ctype_b */ \ 00576 while (((_c) = (int) *(_s)) && isblank(_c)) \ 00577 (_s)++; \ 00578 /*@=globs@*/ 00579 00580 #define SKIPNONBLANK(_s, _c) \ 00581 /*@-globs@*/ /* FIX: __ctype_b */ \ 00582 while (((_c) = (int) *(_s)) && !(isblank(_c) || iseol(_c))) \ 00583 (_s)++; \ 00584 /*@=globs@*/ 00585 00586 #define COPYNAME(_ne, _s, _c) \ 00587 { SKIPBLANK(_s,_c); \ 00588 while(((_c) = (int) *(_s)) && (xisalnum(_c) || (_c) == (int) '_')) \ 00589 *(_ne)++ = *(_s)++; \ 00590 *(_ne) = '\0'; \ 00591 } 00592 00593 #define COPYOPTS(_oe, _s, _c) \ 00594 { while(((_c) = (int) *(_s)) && (_c) != (int) ')') \ 00595 *(_oe)++ = *(_s)++; \ 00596 *(_oe) = '\0'; \ 00597 } 00598 00606 static int 00607 expandT(MacroBuf mb, const char * f, size_t flen) 00608 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00609 /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/ 00610 { 00611 char *sbuf; 00612 const char *s = mb->s; 00613 int rc; 00614 00615 sbuf = alloca(flen + 1); 00616 memset(sbuf, 0, (flen + 1)); 00617 00618 strncpy(sbuf, f, flen); 00619 sbuf[flen] = '\0'; 00620 mb->s = sbuf; 00621 rc = expandMacro(mb); 00622 mb->s = s; 00623 return rc; 00624 } 00625 00626 #if 0 00627 00634 static int 00635 expandS(MacroBuf mb, char * tbuf, size_t tbuflen) 00636 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/ 00637 /*@modifies mb, *tbuf, rpmGlobalMacroContext, fileSystem, internalState @*/ 00638 { 00639 const char *t = mb->t; 00640 size_t nb = mb->nb; 00641 int rc; 00642 00643 mb->t = tbuf; 00644 mb->nb = tbuflen; 00645 rc = expandMacro(mb); 00646 mb->t = t; 00647 mb->nb = nb; 00648 return rc; 00649 } 00650 #endif 00651 00659 static int 00660 expandU(MacroBuf mb, char * u, size_t ulen) 00661 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00662 /*@modifies mb, *u, rpmGlobalMacroContext, fileSystem, internalState @*/ 00663 { 00664 const char *s = mb->s; 00665 char *t = mb->t; 00666 size_t nb = mb->nb; 00667 char *tbuf; 00668 int rc; 00669 00670 tbuf = alloca(ulen + 1); 00671 memset(tbuf, 0, (ulen + 1)); 00672 00673 mb->s = u; 00674 mb->t = tbuf; 00675 mb->nb = ulen; 00676 rc = expandMacro(mb); 00677 00678 tbuf[ulen] = '\0'; /* XXX just in case */ 00679 if (ulen > mb->nb) 00680 strncpy(u, tbuf, (ulen - mb->nb + 1)); 00681 00682 mb->s = s; 00683 mb->t = t; 00684 mb->nb = nb; 00685 00686 return rc; 00687 } 00688 00696 static int 00697 doShellEscape(MacroBuf mb, const char * cmd, size_t clen) 00698 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00699 /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/ 00700 { 00701 size_t bufn = _macro_BUFSIZ + clen; 00702 char * buf = alloca(bufn); 00703 FILE *shf; 00704 int rc; 00705 int c; 00706 00707 strncpy(buf, cmd, clen); 00708 buf[clen] = '\0'; 00709 rc = expandU(mb, buf, bufn); 00710 if (rc) 00711 return rc; 00712 00713 if ((shf = popen(buf, "r")) == NULL) 00714 return 1; 00715 while(mb->nb > 0 && (c = fgetc(shf)) != EOF) 00716 SAVECHAR(mb, c); 00717 (void) pclose(shf); 00718 00719 /* XXX delete trailing \r \n */ 00720 while (iseol(mb->t[-1])) { 00721 *(mb->t--) = '\0'; 00722 mb->nb++; 00723 } 00724 return 0; 00725 } 00726 00735 /*@dependent@*/ static const char * 00736 doDefine(MacroBuf mb, /*@returned@*/ const char * se, int level, int expandbody) 00737 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00738 /*@modifies mb, rpmGlobalMacroContext, internalState @*/ 00739 { 00740 const char *s = se; 00741 size_t bufn = _macro_BUFSIZ; 00742 char *buf = alloca(bufn); 00743 char *n = buf, *ne; 00744 char *o = NULL, *oe; 00745 char *b, *be; 00746 int c; 00747 int oc = (int) ')'; 00748 00749 SKIPBLANK(s, c); 00750 if (c == (int) '.') /* XXX readonly macros */ 00751 /*@i@*/ *n++ = c = *s++; 00752 if (c == (int) '.') /* XXX readonly macros */ 00753 /*@i@*/ *n++ = c = *s++; 00754 ne = n; 00755 00756 /* Copy name */ 00757 COPYNAME(ne, s, c); 00758 00759 /* Copy opts (if present) */ 00760 oe = ne + 1; 00761 if (*s == '(') { 00762 s++; /* skip ( */ 00763 o = oe; 00764 COPYOPTS(oe, s, oc); 00765 s++; /* skip ) */ 00766 } 00767 00768 /* Copy body, skipping over escaped newlines */ 00769 b = be = oe + 1; 00770 SKIPBLANK(s, c); 00771 if (c == (int) '{') { /* XXX permit silent {...} grouping */ 00772 if ((se = matchchar(s, (char) c, '}')) == NULL) { 00773 rpmlog(RPMLOG_ERR, 00774 _("Macro %%%s has unterminated body\n"), n); 00775 se = s; /* XXX W2DO? */ 00776 return se; 00777 } 00778 s++; /* XXX skip { */ 00779 strncpy(b, s, (se - s)); 00780 b[se - s] = '\0'; 00781 be += strlen(b); 00782 se++; /* XXX skip } */ 00783 s = se; /* move scan forward */ 00784 } else { /* otherwise free-field */ 00785 int bc = 0, pc = 0; 00786 while (*s && (bc || pc || !iseol(*s))) { 00787 switch (*s) { 00788 case '\\': 00789 switch (*(s+1)) { 00790 case '\0': /*@switchbreak@*/ break; 00791 default: s++; /*@switchbreak@*/ break; 00792 } 00793 /*@switchbreak@*/ break; 00794 case '%': 00795 switch (*(s+1)) { 00796 case '{': *be++ = *s++; bc++; /*@switchbreak@*/ break; 00797 case '(': *be++ = *s++; pc++; /*@switchbreak@*/ break; 00798 case '%': *be++ = *s++; /*@switchbreak@*/ break; 00799 } 00800 /*@switchbreak@*/ break; 00801 case '{': if (bc > 0) bc++; /*@switchbreak@*/ break; 00802 case '}': if (bc > 0) bc--; /*@switchbreak@*/ break; 00803 case '(': if (pc > 0) pc++; /*@switchbreak@*/ break; 00804 case ')': if (pc > 0) pc--; /*@switchbreak@*/ break; 00805 } 00806 *be++ = *s++; 00807 } 00808 *be = '\0'; 00809 00810 if (bc || pc) { 00811 rpmlog(RPMLOG_ERR, 00812 _("Macro %%%s has unterminated body\n"), n); 00813 se = s; /* XXX W2DO? */ 00814 return se; 00815 } 00816 00817 /* Trim trailing blanks/newlines */ 00818 /*@-globs@*/ 00819 while (--be >= b && (c = (int) *be) && (isblank(c) || iseol(c))) 00820 {}; 00821 /*@=globs@*/ 00822 *(++be) = '\0'; /* one too far */ 00823 } 00824 00825 /* Move scan over body */ 00826 while (iseol(*s)) 00827 s++; 00828 se = s; 00829 00830 /* Names must start with alphabetic or _ and be at least 3 chars */ 00831 if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) { 00832 rpmlog(RPMLOG_ERR, 00833 _("Macro %%%s has illegal name (%%define)\n"), n); 00834 return se; 00835 } 00836 00837 /* Options must be terminated with ')' */ 00838 if (o && oc != (int) ')') { 00839 rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n); 00840 return se; 00841 } 00842 00843 if ((be - b) < 1) { 00844 rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n); 00845 return se; 00846 } 00847 00848 /*@-modfilesys@*/ 00849 if (expandbody && expandU(mb, b, (&buf[bufn] - b))) { 00850 rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n); 00851 return se; 00852 } 00853 /*@=modfilesys@*/ 00854 00855 if (n != buf) /* XXX readonly macros */ 00856 n--; 00857 if (n != buf) /* XXX readonly macros */ 00858 n--; 00859 addMacro(mb->mc, n, o, b, (level - 1)); 00860 00861 return se; 00862 } 00863 00870 /*@dependent@*/ static const char * 00871 doUndefine(MacroContext mc, /*@returned@*/ const char * se) 00872 /*@globals rpmGlobalMacroContext @*/ 00873 /*@modifies mc, rpmGlobalMacroContext @*/ 00874 { 00875 const char *s = se; 00876 char *buf = alloca(_macro_BUFSIZ); 00877 char *n = buf, *ne = n; 00878 int c; 00879 00880 COPYNAME(ne, s, c); 00881 00882 /* Move scan over body */ 00883 while (iseol(*s)) 00884 s++; 00885 se = s; 00886 00887 /* Names must start with alphabetic or _ and be at least 3 chars */ 00888 if (!((c = (int) *n) && (xisalpha(c) || c == (int) '_') && (ne - n) > 2)) { 00889 rpmlog(RPMLOG_ERR, 00890 _("Macro %%%s has illegal name (%%undefine)\n"), n); 00891 return se; 00892 } 00893 00894 delMacro(mc, n); 00895 00896 return se; 00897 } 00898 00899 #ifdef DYING 00900 static void 00901 dumpME(const char * msg, MacroEntry me) 00902 /*@globals fileSystem @*/ 00903 /*@modifies fileSystem @*/ 00904 { 00905 if (msg) 00906 fprintf(stderr, "%s", msg); 00907 fprintf(stderr, "\tme %p", me); 00908 if (me) 00909 fprintf(stderr,"\tname %p(%s) prev %p", 00910 me->name, me->name, me->prev); 00911 fprintf(stderr, "\n"); 00912 } 00913 #endif 00914 00923 static void 00924 pushMacro(/*@out@*/ MacroEntry * mep, const char * n, /*@null@*/ const char * o, 00925 /*@null@*/ const char * b, int level) 00926 /*@modifies *mep @*/ 00927 { 00928 MacroEntry prev = (mep && *mep ? *mep : NULL); 00929 MacroEntry me = (MacroEntry) xmalloc(sizeof(*me)); 00930 const char *name = n; 00931 00932 if (*name == '.') /* XXX readonly macros */ 00933 name++; 00934 if (*name == '.') /* XXX readonly macros */ 00935 name++; 00936 00937 /*@-assignexpose@*/ 00938 me->prev = prev; 00939 /*@=assignexpose@*/ 00940 me->name = (prev ? prev->name : xstrdup(name)); 00941 me->opts = (o ? xstrdup(o) : NULL); 00942 me->body = xstrdup(b ? b : ""); 00943 me->used = 0; 00944 me->level = level; 00945 me->flags = (name != n); 00946 if (mep) 00947 *mep = me; 00948 else 00949 me = _free(me); 00950 } 00951 00956 static void 00957 popMacro(MacroEntry * mep) 00958 /*@modifies *mep @*/ 00959 { 00960 MacroEntry me = (*mep ? *mep : NULL); 00961 00962 if (me) { 00963 /* XXX cast to workaround const */ 00964 /*@-onlytrans@*/ 00965 if ((*mep = me->prev) == NULL) 00966 me->name = _free(me->name); 00967 me->opts = _free(me->opts); 00968 me->body = _free(me->body); 00969 me = _free(me); 00970 /*@=onlytrans@*/ 00971 } 00972 } 00973 00978 static void 00979 freeArgs(MacroBuf mb) 00980 /*@modifies mb @*/ 00981 { 00982 MacroContext mc = mb->mc; 00983 int ndeleted = 0; 00984 int i; 00985 00986 if (mc == NULL || mc->macroTable == NULL) 00987 return; 00988 00989 /* Delete dynamic macro definitions */ 00990 for (i = 0; i < mc->firstFree; i++) { 00991 MacroEntry *mep, me; 00992 int skiptest = 0; 00993 mep = &mc->macroTable[i]; 00994 me = *mep; 00995 00996 if (me == NULL) /* XXX this should never happen */ 00997 continue; 00998 if (me->level < mb->depth) 00999 continue; 01000 if (strlen(me->name) == 1 && strchr("#*0", *me->name)) { 01001 if (*me->name == '*' && me->used > 0) 01002 skiptest = 1; /* XXX skip test for %# %* %0 */ 01003 } else if (!skiptest && me->used <= 0) { 01004 #if NOTYET 01005 rpmlog(RPMLOG_ERR, 01006 _("Macro %%%s (%s) was not used below level %d\n"), 01007 me->name, me->body, me->level); 01008 #endif 01009 } 01010 popMacro(mep); 01011 if (!(mep && *mep)) 01012 ndeleted++; 01013 } 01014 01015 /* If any deleted macros, sort macro table */ 01016 if (ndeleted) 01017 sortMacroTable(mc); 01018 } 01019 01029 /*@dependent@*/ static const char * 01030 grabArgs(MacroBuf mb, const MacroEntry me, /*@returned@*/ const char * se, 01031 const char * lastc) 01032 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/ 01033 /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/ 01034 { 01035 poptContext optCon; 01036 struct poptOption *optTbl; 01037 size_t bufn = _macro_BUFSIZ; 01038 char *buf = alloca(bufn); 01039 char *b, *be; 01040 char aname[16]; 01041 const char *opts; 01042 int argc = 0; 01043 const char **argv; 01044 int c; 01045 unsigned int popt_flags; 01046 01047 /* Copy macro name as argv[0], save beginning of args. */ 01048 buf[0] = '\0'; 01049 b = be = stpcpy(buf, me->name); 01050 01051 addMacro(mb->mc, "0", NULL, buf, mb->depth); 01052 01053 argc = 1; /* XXX count argv[0] */ 01054 01055 /* Copy args into buf until lastc */ 01056 *be++ = ' '; 01057 while ((c = (int) *se++) != (int) '\0' && (se-1) != lastc) { 01058 /*@-globs@*/ 01059 if (!isblank(c)) { 01060 *be++ = (char) c; 01061 continue; 01062 } 01063 /*@=globs@*/ 01064 /* c is blank */ 01065 if (be[-1] == ' ') 01066 continue; 01067 /* a word has ended */ 01068 *be++ = ' '; 01069 argc++; 01070 } 01071 if (c == (int) '\0') se--; /* one too far */ 01072 if (be[-1] != ' ') 01073 argc++, be++; /* last word has not trailing ' ' */ 01074 be[-1] = '\0'; 01075 if (*b == ' ') b++; /* skip the leading ' ' */ 01076 01077 /* 01078 * The macro %* analoguous to the shell's $* means "Pass all non-macro 01079 * parameters." Consequently, there needs to be a macro that means "Pass all 01080 * (including macro parameters) options". This is useful for verifying 01081 * parameters during expansion and yet transparently passing all parameters 01082 * through for higher level processing (e.g. %description and/or %setup). 01083 * This is the (potential) justification for %{**} ... 01084 */ 01085 /* Add unexpanded args as macro */ 01086 addMacro(mb->mc, "**", NULL, b, mb->depth); 01087 01088 #ifdef NOTYET 01089 /* XXX if macros can be passed as args ... */ 01090 expandU(mb, buf, bufn); 01091 #endif 01092 01093 /* Build argv array */ 01094 argv = (const char **) alloca((argc + 1) * sizeof(*argv)); 01095 be[-1] = ' '; /* assert((be - 1) == (b + strlen(b) == buf + strlen(buf))) */ 01096 be[0] = '\0'; 01097 01098 b = buf; 01099 for (c = 0; c < argc; c++) { 01100 argv[c] = b; 01101 b = strchr(b, ' '); 01102 *b++ = '\0'; 01103 } 01104 /* assert(b == be); */ 01105 argv[argc] = NULL; 01106 01107 /* '+' as the first character means that options are recognized 01108 * only before positional arguments, as POSIX requires. 01109 */ 01110 popt_flags = POPT_CONTEXT_NO_EXEC; 01111 #if defined(RPM_VENDOR_OPENPKG) /* always-strict-posix-option-parsing */ 01112 popt_flags |= POPT_CONTEXT_POSIXMEHARDER; 01113 #endif 01114 if (me->opts[0] == '+') popt_flags |= POPT_CONTEXT_POSIXMEHARDER; 01115 01116 /* Count the number of short options. */ 01117 opts = me->opts; 01118 if (*opts == '+') opts++; 01119 for (c = 0; *opts != '\0'; opts++) 01120 if (*opts != ':') c++; 01121 01122 /* Set up popt option table. */ 01123 optTbl = xcalloc(sizeof(*optTbl), (c + 1)); 01124 opts = me->opts; 01125 if (*opts == '+') opts++; 01126 for (c = 0; *opts != '\0'; opts++) { 01127 if (*opts == ':') continue; 01128 optTbl[c].shortName = opts[0]; 01129 optTbl[c].val = (int) opts[0]; 01130 if (opts[1] == ':') 01131 optTbl[c].argInfo = POPT_ARG_STRING; 01132 c++; 01133 } 01134 01135 /* Parse the options, defining option macros. */ 01136 /*@-nullstate@*/ 01137 optCon = poptGetContext(argv[0], argc, argv, optTbl, popt_flags); 01138 /*@=nullstate@*/ 01139 while ((c = poptGetNextOpt(optCon)) > 0) { 01140 const char * optArg = poptGetOptArg(optCon); 01141 *be++ = '-'; 01142 *be++ = (char) c; 01143 if (optArg != NULL) { 01144 *be++ = ' '; 01145 be = stpcpy(be, optArg); 01146 } 01147 *be++ = '\0'; 01148 aname[0] = '-'; aname[1] = (char)c; aname[2] = '\0'; 01149 addMacro(mb->mc, aname, NULL, b, mb->depth); 01150 if (optArg != NULL) { 01151 aname[0] = '-'; aname[1] = (char)c; aname[2] = '*'; aname[3] = '\0'; 01152 addMacro(mb->mc, aname, NULL, optArg, mb->depth); 01153 } 01154 be = b; /* reuse the space */ 01155 /*@-dependenttrans -modobserver -observertrans @*/ 01156 optArg = _free(optArg); 01157 /*@=dependenttrans =modobserver =observertrans @*/ 01158 } 01159 if (c < -1) { 01160 rpmlog(RPMLOG_ERR, _("Unknown option in macro %s(%s): %s: %s\n"), 01161 me->name, me->opts, 01162 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c)); 01163 goto exit; 01164 } 01165 01166 argv = poptGetArgs(optCon); 01167 argc = 0; 01168 if (argv != NULL) 01169 for (c = 0; argv[c] != NULL; c++) 01170 argc++; 01171 01172 /* Add arg count as macro. */ 01173 sprintf(aname, "%d", argc); 01174 addMacro(mb->mc, "#", NULL, aname, mb->depth); 01175 01176 /* Add macro for each arg. Concatenate args for %*. */ 01177 if (be) { 01178 *be = '\0'; 01179 if (argv != NULL) 01180 for (c = 0; c < argc; c++) { 01181 sprintf(aname, "%d", (c + 1)); 01182 addMacro(mb->mc, aname, NULL, argv[c], mb->depth); 01183 if (be != b) *be++ = ' '; /* Add space between args */ 01184 be = stpcpy(be, argv[c]); 01185 } 01186 } 01187 01188 /* Add unexpanded args as macro. */ 01189 addMacro(mb->mc, "*", NULL, b, mb->depth); 01190 01191 exit: 01192 optCon = poptFreeContext(optCon); 01193 optTbl = _free(optTbl); 01194 return se; 01195 } 01196 01204 static void 01205 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen) 01206 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01207 /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/ 01208 { 01209 size_t bufn = _macro_BUFSIZ + msglen; 01210 char *buf = alloca(bufn); 01211 01212 strncpy(buf, msg, msglen); 01213 buf[msglen] = '\0'; 01214 (void) expandU(mb, buf, bufn); 01215 if (waserror) 01216 rpmlog(RPMLOG_ERR, "%s\n", buf); 01217 else 01218 fprintf(stderr, "%s", buf); 01219 } 01220 01230 static void 01231 doFoo(MacroBuf mb, int negate, const char * f, size_t fn, 01232 /*@null@*/ const char * g, size_t gn) 01233 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01234 /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/ 01235 { 01236 size_t bufn = _macro_BUFSIZ + fn + gn; 01237 char * buf = alloca(bufn); 01238 char *b = NULL, *be; 01239 int c; 01240 mode_t mode; 01241 01242 buf[0] = '\0'; 01243 if (g != NULL) { 01244 strncpy(buf, g, gn); 01245 buf[gn] = '\0'; 01246 (void) expandU(mb, buf, bufn); 01247 } 01248 if (fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) { 01249 /* Skip leading zeros */ 01250 for (c = 5; c < (int)(fn-1) && f[c] == '0' && xisdigit((int)f[c+1]);) 01251 c++; 01252 b = buf; 01253 be = stpncpy( stpcpy(b, "%patch -P "), f+c, fn-c); 01254 *be = '\0'; 01255 } else 01256 if (STREQ("basename", f, fn)) { 01257 if ((b = strrchr(buf, '/')) == NULL) 01258 b = buf; 01259 else 01260 b++; 01261 } else if (STREQ("dirname", f, fn)) { 01262 if ((b = strrchr(buf, '/')) != NULL) 01263 *b = '\0'; 01264 b = buf; 01265 #if !defined(__LCLINT__) /* XXX LCL: realpath(3) annotations are buggy. */ 01266 } else if (STREQ("realpath", f, fn)) { 01267 char rp[PATH_MAX]; 01268 char *cp; 01269 size_t l; 01270 if ((cp = realpath(buf, rp)) != NULL) { 01271 l = strlen(cp); 01272 if ((size_t)(l+1) <= bufn) { 01273 memcpy(buf, cp, l+1); 01274 b = buf; 01275 } 01276 } 01277 #endif 01278 } else if (STREQ("getenv", f, fn)) { 01279 char *cp; 01280 if ((cp = getenv(buf)) != NULL) 01281 b = cp; 01282 } else if (STREQ("shrink", f, fn)) { 01283 /* 01284 * shrink body by removing all leading and trailing whitespaces and 01285 * reducing intermediate whitespaces to a single space character. 01286 */ 01287 int i, j, k, was_space = 0; 01288 for (i = 0, j = 0, k = (int)strlen(buf); i < k; ) { 01289 if (xisspace((int)(buf[i]))) { 01290 was_space = 1; 01291 i++; 01292 continue; 01293 } 01294 else if (was_space) { 01295 was_space = 0; 01296 if (j > 0) /* remove leading blanks at all */ 01297 buf[j++] = ' '; 01298 /* fallthrough */ 01299 } 01300 buf[j++] = buf[i++]; 01301 } 01302 buf[j] = '\0'; 01303 b = buf; 01304 } else if (STREQ("suffix", f, fn)) { 01305 if ((b = strrchr(buf, '.')) != NULL) 01306 b++; 01307 } else if (STREQ("expand", f, fn)) { 01308 b = buf; 01309 } else if (STREQ("verbose", f, fn)) { 01310 #if defined(RPMLOG_MASK) 01311 if (negate) 01312 b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? NULL : buf); 01313 else 01314 b = ((rpmlogSetMask(0) >= RPMLOG_MASK( RPMLOG_INFO )) ? buf : NULL); 01315 #else 01316 /* XXX assume always verbose when running standalone */ 01317 b = (negate) ? NULL : buf; 01318 #endif 01319 } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) { 01320 int ut = urlPath(buf, (const char **)&b); 01321 ut = ut; /* XXX quiet gcc */ 01322 if (*b == '\0') b = "/"; 01323 } else if (STREQ("uncompress", f, fn)) { 01324 rpmCompressedMagic compressed = COMPRESSED_OTHER; 01325 /*@-globs@*/ 01326 for (b = buf; (c = (int)*b) && isblank(c);) 01327 b++; 01328 /* XXX FIXME: file paths with embedded white space needs rework. */ 01329 for (be = b; (c = (int)*be) && !isblank(c);) 01330 be++; 01331 /*@=globs@*/ 01332 *be++ = '\0'; 01333 (void) isCompressed(b, &compressed); 01334 switch(compressed) { 01335 default: 01336 case 0: /* COMPRESSED_NOT */ 01337 sprintf(be, "%%__cat %s", b); 01338 break; 01339 case 1: /* COMPRESSED_OTHER */ 01340 sprintf(be, "%%__gzip -dc '%s'", b); 01341 break; 01342 case 2: /* COMPRESSED_BZIP2 */ 01343 sprintf(be, "%%__bzip2 -dc '%s'", b); 01344 break; 01345 case 3: /* COMPRESSED_ZIP */ 01346 sprintf(be, "%%__unzip -qq '%s'", b); 01347 break; 01348 case 4: /* COMPRESSED_LZOP */ 01349 sprintf(be, "%%__lzop -dc '%s'", b); 01350 break; 01351 case 5: /* COMPRESSED_LZMA */ 01352 sprintf(be, "%%__lzma -dc '%s'", b); 01353 break; 01354 case 6: /* COMPRESSED_XZ */ 01355 sprintf(be, "%%__xz -dc '%s'", b); 01356 break; 01357 case 7: /* COMPRESSED_LRZIP */ 01358 sprintf(be, "%%__lrzip -dqo- %s", b); 01359 break; 01360 case 8: /* COMPRESSED_LZIP */ 01361 sprintf(be, "%%__lzip -dc %s", b); 01362 break; 01363 } 01364 b = be; 01365 } else if (STREQ("mkstemp", f, fn)) { 01366 /*@-globs@*/ 01367 for (b = buf; (c = (int)*b) && isblank(c);) 01368 b++; 01369 /* XXX FIXME: file paths with embedded white space needs rework. */ 01370 for (be = b; (c = (int)*be) && !isblank(c);) 01371 be++; 01372 /*@=globs@*/ 01373 #if defined(HAVE_MKSTEMP) 01374 mode = umask(0077); 01375 (void) close(mkstemp(b)); 01376 (void) umask(mode); 01377 #else 01378 (void) mktemp(b); 01379 #endif 01380 } else if (STREQ("mkdtemp", f, fn)) { 01381 /*@-globs@*/ 01382 for (b = buf; (c = (int)*b) && isblank(c);) 01383 b++; 01384 /* XXX FIXME: file paths with embedded white space needs rework. */ 01385 for (be = b; (c = (int)*be) && !isblank(c);) 01386 be++; 01387 /*@=globs@*/ 01388 #if defined(HAVE_MKDTEMP) && !defined(__LCLINT__) 01389 if (mkdtemp(b) == NULL) 01390 perror("mkdtemp"); 01391 #else 01392 if ((b = tmpnam(b)) != NULL) 01393 (void) mkdir(b, 0700); /* XXX S_IWRSXU is not included. */ 01394 #endif 01395 } else if (STREQ("uuid", f, fn)) { 01396 int uuid_version; 01397 const char *uuid_ns; 01398 const char *uuid_data; 01399 char *cp; 01400 size_t n; 01401 01402 uuid_version = 1; 01403 uuid_ns = NULL; 01404 uuid_data = NULL; 01405 cp = buf; 01406 if ((n = strspn(cp, " \t\n")) > 0) 01407 cp += n; 01408 if ((n = strcspn(cp, " \t\n")) > 0) { 01409 uuid_version = (int)strtol(cp, (char **)NULL, 10); 01410 cp += n; 01411 if ((n = strspn(cp, " \t\n")) > 0) 01412 cp += n; 01413 if ((n = strcspn(cp, " \t\n")) > 0) { 01414 uuid_ns = cp; 01415 cp += n; 01416 *cp++ = '\0'; 01417 if ((n = strspn(cp, " \t\n")) > 0) 01418 cp += n; 01419 if ((n = strcspn(cp, " \t\n")) > 0) { 01420 uuid_data = cp; 01421 cp += n; 01422 *cp++ = '\0'; 01423 } 01424 } 01425 } 01426 /*@-nullpass@*/ /* FIX: uuid_ns may be NULL */ 01427 if (rpmuuidMake(uuid_version, uuid_ns, uuid_data, buf, NULL)) 01428 rpmlog(RPMLOG_ERR, "failed to create UUID\n"); 01429 else 01430 b = buf; 01431 /*@=nullpass@*/ 01432 } else if (STREQ("S", f, fn)) { 01433 for (b = buf; (c = (int)*b) && xisdigit(c);) 01434 b++; 01435 if (!c) { /* digit index */ 01436 b++; 01437 sprintf(b, "%%SOURCE%s", buf); 01438 } else 01439 b = buf; 01440 } else if (STREQ("P", f, fn)) { 01441 for (b = buf; (c = (int) *b) && xisdigit(c);) 01442 b++; 01443 if (!c) { /* digit index */ 01444 b++; 01445 sprintf(b, "%%PATCH%s", buf); 01446 } else 01447 b = buf; 01448 } else if (STREQ("F", f, fn)) { 01449 b = buf + strlen(buf) + 1; 01450 sprintf(b, "file%s.file", buf); 01451 } 01452 01453 if (b) { 01454 (void) expandT(mb, b, strlen(b)); 01455 } 01456 } 01457 01458 static int expandFIFO(MacroBuf mb, MacroEntry me, const char *g, size_t gn) 01459 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01460 /*@modifies mb, rpmGlobalMacroContext, fileSystem, internalState @*/ 01461 { 01462 int rc = 0; 01463 01464 if (me) { 01465 if (me->prev) { 01466 rc = expandFIFO(mb, me->prev, g, gn); 01467 rc = expandT(mb, g, gn); 01468 } 01469 rc = expandT(mb, me->body, strlen(me->body)); 01470 } 01471 return rc; 01472 } 01473 01474 #if !defined(DEBUG_MACROS) 01475 /* =============================================================== */ 01476 /* XXX dupe'd to avoid change in linkage conventions. */ 01477 01478 #define POPT_ERROR_NOARG -10 01479 #define POPT_ERROR_BADQUOTE -15 01480 #define POPT_ERROR_MALLOC -21 01482 #define POPT_ARGV_ARRAY_GROW_DELTA 5 01483 01484 static int XpoptDupArgv(int argc, char **argv, 01485 int * argcPtr, char *** argvPtr) 01486 /*@modifies *argcPtr, *argvPtr @*/ 01487 { 01488 size_t nb = (argc + 1) * sizeof(*argv); 01489 char ** argv2; 01490 char * dst; 01491 int i; 01492 01493 if (argc <= 0 || argv == NULL) /* XXX can't happen */ 01494 return POPT_ERROR_NOARG; 01495 for (i = 0; i < argc; i++) { 01496 if (argv[i] == NULL) 01497 return POPT_ERROR_NOARG; 01498 nb += strlen(argv[i]) + 1; 01499 } 01500 01501 dst = xmalloc(nb); 01502 if (dst == NULL) /* XXX can't happen */ 01503 return POPT_ERROR_MALLOC; 01504 argv2 = (void *) dst; 01505 dst += (argc + 1) * sizeof(*argv); 01506 01507 for (i = 0; i < argc; i++) { 01508 argv2[i] = dst; 01509 dst += strlen(strcpy(dst, argv[i])) + 1; 01510 } 01511 argv2[argc] = NULL; 01512 01513 if (argvPtr) { 01514 *argvPtr = argv2; 01515 } else { 01516 free(argv2); 01517 argv2 = NULL; 01518 } 01519 if (argcPtr) 01520 *argcPtr = argc; 01521 return 0; 01522 } 01523 01524 static int XpoptParseArgvString(const char * s, int * argcPtr, char *** argvPtr) 01525 /*@modifies *argcPtr, *argvPtr @*/ 01526 { 01527 const char * src; 01528 char quote = '\0'; 01529 int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; 01530 char ** argv = xmalloc(sizeof(*argv) * argvAlloced); 01531 int argc = 0; 01532 size_t buflen = strlen(s) + 1; 01533 char * buf = memset(alloca(buflen), 0, buflen); 01534 int rc = POPT_ERROR_MALLOC; 01535 01536 if (argv == NULL) return rc; 01537 argv[argc] = buf; 01538 01539 for (src = s; *src != '\0'; src++) { 01540 if (quote == *src) { 01541 quote = '\0'; 01542 } else if (quote != '\0') { 01543 if (*src == '\\') { 01544 src++; 01545 if (!*src) { 01546 rc = POPT_ERROR_BADQUOTE; 01547 goto exit; 01548 } 01549 if (*src != quote) *buf++ = '\\'; 01550 } 01551 *buf++ = *src; 01552 } else if (isspace(*src)) { 01553 if (*argv[argc] != '\0') { 01554 buf++, argc++; 01555 if (argc == argvAlloced) { 01556 argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; 01557 argv = realloc(argv, sizeof(*argv) * argvAlloced); 01558 if (argv == NULL) goto exit; 01559 } 01560 argv[argc] = buf; 01561 } 01562 } else switch (*src) { 01563 case '"': 01564 case '\'': 01565 quote = *src; 01566 /*@switchbreak@*/ break; 01567 case '\\': 01568 src++; 01569 if (!*src) { 01570 rc = POPT_ERROR_BADQUOTE; 01571 goto exit; 01572 } 01573 /*@fallthrough@*/ 01574 default: 01575 *buf++ = *src; 01576 /*@switchbreak@*/ break; 01577 } 01578 } 01579 01580 if (strlen(argv[argc])) { 01581 argc++, buf++; 01582 } 01583 01584 rc = XpoptDupArgv(argc, argv, argcPtr, argvPtr); 01585 01586 exit: 01587 if (argv) free(argv); 01588 return rc; 01589 } 01590 #endif /* !defined(DEBUG_MACROS) */ 01591 01599 #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) 01600 static char * parseEmbedded(const char * s, size_t nb, char *** avp) 01601 /*@*/ 01602 { 01603 char * script = NULL; 01604 const char * se; 01605 01606 /* XXX FIXME: args might have embedded : too. */ 01607 for (se = s + 1; se < (s+nb); se++) 01608 switch (*se) { 01609 default: continue; /*@notreached@*/ break; 01610 case ':': goto bingo; /*@notreached@*/ break; 01611 } 01612 01613 bingo: 01614 { size_t na = (size_t)(se-s-1); 01615 char * args = NULL; 01616 int ac; 01617 int rc; 01618 01619 args = memcpy(xmalloc(na+1), s+1, na); 01620 args[na] = '\0'; 01621 01622 ac = 0; 01623 rc = XpoptParseArgvString(args, &ac, avp); 01624 args = _free(args); 01625 nb -= na; 01626 } 01627 01628 nb -= 3; 01629 script = memcpy(xmalloc(nb+1), se+1, nb+1); 01630 script[nb] = '\0'; 01631 return script; 01632 } 01633 #endif 01634 01641 static int 01642 expandMacro(MacroBuf mb) 01643 /*@globals rpmGlobalMacroContext, 01644 print_macro_trace, print_expand_trace, h_errno, 01645 fileSystem, internalState @*/ 01646 /*@modifies mb, rpmGlobalMacroContext, 01647 print_macro_trace, print_expand_trace, 01648 fileSystem, internalState @*/ 01649 { 01650 MacroEntry *mep; 01651 MacroEntry me; 01652 const char *s = mb->s, *se; 01653 const char *f, *fe; 01654 const char *g, *ge; 01655 size_t fn, gn; 01656 char *t = mb->t; /* save expansion pointer for printExpand */ 01657 int c; 01658 int rc = 0; 01659 int negate; 01660 int stackarray; 01661 const char * lastc; 01662 int chkexist; 01663 01664 if (++mb->depth > max_macro_depth) { 01665 rpmlog(RPMLOG_ERR, 01666 _("Recursion depth(%d) greater than max(%d)\n"), 01667 mb->depth, max_macro_depth); 01668 mb->depth--; 01669 mb->expand_trace = 1; 01670 return 1; 01671 } 01672 01673 while (rc == 0 && mb->nb > 0 && (c = (int)*s) != (int)'\0') { 01674 s++; 01675 /* Copy text until next macro */ 01676 switch(c) { 01677 case '%': 01678 if (*s != '\0') { /* Ensure not end-of-string. */ 01679 if (*s != '%') 01680 /*@switchbreak@*/ break; 01681 s++; /* skip first % in %% */ 01682 } 01683 /*@fallthrough@*/ 01684 default: 01685 SAVECHAR(mb, c); 01686 continue; 01687 /*@notreached@*/ /*@switchbreak@*/ break; 01688 } 01689 01690 /* Expand next macro */ 01691 f = fe = NULL; 01692 g = ge = NULL; 01693 if (mb->depth > 1) /* XXX full expansion for outermost level */ 01694 t = mb->t; /* save expansion pointer for printExpand */ 01695 stackarray = chkexist = negate = 0; 01696 lastc = NULL; 01697 switch ((c = (int) *s)) { 01698 default: /* %name substitution */ 01699 while (*s != '\0' && strchr("!?@", *s) != NULL) { 01700 switch(*s++) { 01701 case '@': 01702 stackarray = ((stackarray + 1) % 2); 01703 /*@switchbreak@*/ break; 01704 case '!': 01705 negate = ((negate + 1) % 2); 01706 /*@switchbreak@*/ break; 01707 case '?': 01708 chkexist++; 01709 /*@switchbreak@*/ break; 01710 } 01711 } 01712 f = se = s; 01713 if (*se == '-') 01714 se++; 01715 while((c = (int) *se) && (xisalnum(c) || c == (int) '_')) 01716 se++; 01717 /* Recognize non-alnum macros too */ 01718 switch (*se) { 01719 case '*': 01720 se++; 01721 if (*se == '*') se++; 01722 /*@innerbreak@*/ break; 01723 case '#': 01724 se++; 01725 /*@innerbreak@*/ break; 01726 default: 01727 /*@innerbreak@*/ break; 01728 } 01729 fe = se; 01730 /* For "%name " macros ... */ 01731 /*@-globs@*/ 01732 if ((c = (int) *fe) && isblank(c)) 01733 if ((lastc = strchr(fe,'\n')) == NULL) 01734 lastc = strchr(fe, '\0'); 01735 /*@=globs@*/ 01736 /*@switchbreak@*/ break; 01737 case '(': /* %(...) shell escape */ 01738 if ((se = matchchar(s, (char)c, ')')) == NULL) { 01739 rpmlog(RPMLOG_ERR, 01740 _("Unterminated %c: %s\n"), (char)c, s); 01741 rc = 1; 01742 continue; 01743 } 01744 if (mb->macro_trace) 01745 printMacro(mb, s, se+1); 01746 01747 s++; /* skip ( */ 01748 rc = doShellEscape(mb, s, (se - s)); 01749 se++; /* skip ) */ 01750 01751 s = se; 01752 continue; 01753 /*@notreached@*/ /*@switchbreak@*/ break; 01754 case '{': /* %{...}/%{...:...} substitution */ 01755 if ((se = matchchar(s, (char)c, '}')) == NULL) { 01756 rpmlog(RPMLOG_ERR, 01757 _("Unterminated %c: %s\n"), (char)c, s); 01758 rc = 1; 01759 continue; 01760 } 01761 f = s+1;/* skip { */ 01762 se++; /* skip } */ 01763 while (strchr("!?@", *f) != NULL) { 01764 switch(*f++) { 01765 case '@': 01766 stackarray = ((stackarray + 1) % 2); 01767 /*@switchbreak@*/ break; 01768 case '!': 01769 negate = ((negate + 1) % 2); 01770 /*@switchbreak@*/ break; 01771 case '?': 01772 chkexist++; 01773 /*@switchbreak@*/ break; 01774 } 01775 } 01776 /* Find end-of-expansion, handle %{foo:bar} expansions. */ 01777 for (fe = f; (c = (int) *fe) && !strchr(" :}", c);) 01778 fe++; 01779 switch (c) { 01780 case ':': 01781 g = fe + 1; 01782 ge = se - 1; 01783 /*@innerbreak@*/ break; 01784 case ' ': 01785 lastc = se-1; 01786 /*@innerbreak@*/ break; 01787 default: 01788 /*@innerbreak@*/ break; 01789 } 01790 /*@switchbreak@*/ break; 01791 } 01792 01793 /* XXX Everything below expects fe > f */ 01794 fn = (fe - f); 01795 gn = (ge - g); 01796 if ((fe - f) <= 0) { 01797 /* XXX Process % in unknown context */ 01798 c = (int) '%'; /* XXX only need to save % */ 01799 SAVECHAR(mb, c); 01800 #if 0 01801 rpmlog(RPMLOG_ERR, 01802 _("A %% is followed by an unparseable macro\n")); 01803 #endif 01804 s = se; 01805 continue; 01806 } 01807 01808 if (mb->macro_trace) 01809 printMacro(mb, s, se); 01810 01811 /* Expand builtin macros */ 01812 if (STREQ("load", f, fn)) { 01813 if (g != NULL) { 01814 char * mfn = strncpy(alloca(gn + 1), g, gn); 01815 int xx; 01816 mfn[gn] = '\0'; 01817 xx = rpmLoadMacroFile(NULL, mfn, _max_load_depth); 01818 /* Print failure iff %{load:...} or %{!?load:...} */ 01819 if (xx != 0 && chkexist == negate) 01820 rpmlog(RPMLOG_ERR, _("%s: load macros failed\n"), mfn); 01821 } 01822 s = se; 01823 continue; 01824 } 01825 if (STREQ("global", f, fn)) { 01826 s = doDefine(mb, se, RMIL_GLOBAL, 1); 01827 continue; 01828 } 01829 if (STREQ("define", f, fn)) { 01830 s = doDefine(mb, se, mb->depth, 0); 01831 continue; 01832 } 01833 if (STREQ("undefine", f, fn)) { 01834 s = doUndefine(mb->mc, se); 01835 continue; 01836 } 01837 01838 if (STREQ("echo", f, fn) || 01839 STREQ("warn", f, fn) || 01840 STREQ("error", f, fn)) { 01841 int waserror = 0; 01842 if (STREQ("error", f, fn)) 01843 waserror = 1, rc = 1; 01844 if (g != NULL && g < ge) 01845 doOutput(mb, waserror, g, gn); 01846 else 01847 doOutput(mb, waserror, f, fn); 01848 s = se; 01849 continue; 01850 } 01851 01852 if (STREQ("trace", f, fn)) { 01853 /* XXX TODO restore expand_trace/macro_trace to 0 on return */ 01854 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth); 01855 if (mb->depth == 1) { 01856 print_macro_trace = mb->macro_trace; 01857 print_expand_trace = mb->expand_trace; 01858 } 01859 s = se; 01860 continue; 01861 } 01862 01863 if (STREQ("dump", f, fn)) { 01864 rpmDumpMacroTable(mb->mc, NULL); 01865 while (iseol(*se)) 01866 se++; 01867 s = se; 01868 continue; 01869 } 01870 01871 #ifdef WITH_LUA 01872 if (STREQ("lua", f, fn)) { 01873 rpmlua lua = rpmluaGetGlobalState(); 01874 rpmlua olua = memcpy(alloca(sizeof(*olua)), lua, sizeof(*olua)); 01875 const char *ls = s+sizeof("{lua:")-1; 01876 const char *lse = se-sizeof("}")+1; 01877 char *scriptbuf = (char *)xmalloc((lse-ls)+1); 01878 const char *printbuf; 01879 01880 /* Reset the stateful output buffer before recursing down. */ 01881 lua->storeprint = 1; 01882 lua->printbuf = NULL; 01883 lua->printbufsize = 0; 01884 lua->printbufused = 0; 01885 01886 memcpy(scriptbuf, ls, lse-ls); 01887 scriptbuf[lse-ls] = '\0'; 01888 if (rpmluaRunScript(lua, scriptbuf, NULL) == -1) 01889 rc = 1; 01890 printbuf = rpmluaGetPrintBuffer(lua); 01891 if (printbuf) { 01892 size_t len = strlen(printbuf); 01893 if (len > mb->nb) 01894 len = mb->nb; 01895 memcpy(mb->t, printbuf, len); 01896 mb->t += len; 01897 mb->nb -= len; 01898 } 01899 01900 /* Restore the stateful output buffer after recursion. */ 01901 lua->storeprint = olua->storeprint; 01902 lua->printbuf = olua->printbuf; 01903 lua->printbufsize = olua->printbufsize; 01904 lua->printbufused = olua->printbufused; 01905 01906 free(scriptbuf); 01907 s = se; 01908 continue; 01909 } 01910 #endif 01911 01912 #ifdef WITH_AUGEAS 01913 if (STREQ("augeas", f, fn)) { 01914 /* XXX change rpmaugNew() to common embedded interpreter API */ 01915 #ifdef NOTYET 01916 char ** av = NULL; 01917 char * script = parseEmbedded(s, (size_t)(se-s), &av); 01918 #else 01919 char * script = strndup(g, (size_t)(se-g-1)); 01920 #endif 01921 rpmaug aug = (_globalI ? NULL 01922 : rpmaugNew(_rpmaugRoot, _rpmaugLoadpath, _rpmaugFlags)); 01923 const char * result = NULL; 01924 01925 if (rpmaugRun(aug, script, &result) != RPMRC_OK) 01926 rc = 1; 01927 else { 01928 if (result == NULL) result = "FIXME"; 01929 if (result != NULL && *result != '\0') { 01930 size_t len = strlen(result); 01931 if (len > mb->nb) 01932 len = mb->nb; 01933 memcpy(mb->t, result, len); 01934 mb->t += len; 01935 mb->nb -= len; 01936 } 01937 } 01938 aug = rpmaugFree(aug); 01939 #ifdef NOTYET 01940 av = _free(av); 01941 #endif 01942 script = _free(script); 01943 s = se; 01944 continue; 01945 } 01946 #endif 01947 01948 #ifdef WITH_FICL 01949 if (STREQ("ficl", f, fn)) { 01950 char ** av = NULL; 01951 char * script = parseEmbedded(s, (size_t)(se-s), &av); 01952 rpmficl ficl = rpmficlNew(av, _globalI); 01953 const char * result = NULL; 01954 01955 if (rpmficlRun(ficl, script, &result) != RPMRC_OK) 01956 rc = 1; 01957 else { 01958 if (result == NULL) result = "FIXME"; 01959 if (result != NULL && *result != '\0') { 01960 size_t len = strlen(result); 01961 if (len > mb->nb) 01962 len = mb->nb; 01963 memcpy(mb->t, result, len); 01964 mb->t += len; 01965 mb->nb -= len; 01966 } 01967 } 01968 ficl = rpmficlFree(ficl); 01969 av = _free(av); 01970 script = _free(script); 01971 s = se; 01972 continue; 01973 } 01974 #endif 01975 01976 #ifdef WITH_GPSEE 01977 if (STREQ("js", f, fn)) { 01978 char ** av = NULL; 01979 char * script = parseEmbedded(s, (size_t)(se-s), &av); 01980 rpmjs js = rpmjsNew(av, _globalI); 01981 const char * result = NULL; 01982 01983 if (rpmjsRun(js, script, &result) != RPMRC_OK) 01984 rc = 1; 01985 else { 01986 if (result == NULL) result = "FIXME"; 01987 if (result != NULL && *result != '\0') { 01988 size_t len = strlen(result); 01989 if (len > mb->nb) 01990 len = mb->nb; 01991 memcpy(mb->t, result, len); 01992 mb->t += len; 01993 mb->nb -= len; 01994 } 01995 } 01996 js = rpmjsFree(js); 01997 av = _free(av); 01998 script = _free(script); 01999 s = se; 02000 continue; 02001 } 02002 #endif 02003 02004 #ifdef WITH_NIX 02005 if (STREQ("nix", f, fn)) { 02006 char ** av = NULL; 02007 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02008 int (*_vec) (rpmnix nix) = rpmnixEcho; 02009 uint32_t _flags = RPMNIX_FLAGS_NONE; 02010 rpmnix nix; 02011 const char * result = NULL; 02012 int xx; 02013 02014 if (av == NULL || av[0] == NULL || av[1] == NULL 02015 || !strcmp(av[0], "echo")) 02016 { 02017 _vec = rpmnixEcho; 02018 } else 02019 if (!strcmp(av[1], "build")) { 02020 _vec = rpmnixBuild; 02021 _flags = RPMNIX_FLAGS_NOOUTLINK; 02022 } else 02023 if (!strcmp(av[1], "channel")) { 02024 _vec = rpmnixChannel; 02025 } else 02026 if (!strcmp(av[1], "collect-garbage")) { 02027 _vec = rpmnixCollectGarbage; 02028 } else 02029 if (!strcmp(av[1], "copy-closure")) { 02030 _vec = rpmnixCopyClosure; 02031 } else 02032 if (!strcmp(av[1], "env")) { 02033 _vec = rpmnixEnv; 02034 } else 02035 if (!strcmp(av[1], "hash")) { 02036 _vec = rpmnixHash; 02037 } else 02038 if (!strcmp(av[1], "install-package")) { 02039 _vec = rpmnixInstallPackage; 02040 _flags = RPMNIX_FLAGS_INTERACTIVE; 02041 } else 02042 if (!strcmp(av[1], "instantiate")) { 02043 _vec = rpmnixInstantiate; 02044 } else 02045 if (!strcmp(av[1], "prefetch-url")) { 02046 _vec = rpmnixPrefetchURL; 02047 } else 02048 if (!strcmp(av[1], "push")) { 02049 _vec = rpmnixPush; 02050 } else 02051 if (!strcmp(av[1], "pull")) { 02052 _vec = rpmnixPull; 02053 } else 02054 if (!strcmp(av[1], "store")) { 02055 _vec = rpmnixStore; 02056 } else 02057 if (!strcmp(av[1], "worker")) { 02058 _vec = rpmnixWorker; 02059 } else 02060 assert(0); 02061 02062 nix = rpmnixNew(av, _flags, NULL); 02063 02064 #ifdef NOTYET 02065 if (rpmnixRun(nix, script, &result) != RPMRC_OK) 02066 rc = 1; 02067 else { 02068 if (result == NULL) result = "FIXME"; 02069 if (result != NULL && *result != '\0') { 02070 size_t len = strlen(result); 02071 if (len > mb->nb) 02072 len = mb->nb; 02073 memcpy(mb->t, result, len); 02074 mb->t += len; 02075 mb->nb -= len; 02076 } 02077 } 02078 #else 02079 xx = (*_vec) (nix); 02080 result = xstrdup(""); 02081 #endif /* NOTYET */ 02082 02083 nix = rpmnixFree(nix); 02084 av = _free(av); 02085 script = _free(script); 02086 s = se; 02087 continue; 02088 } 02089 #endif 02090 02091 #ifdef WITH_PERLEMBED 02092 if (STREQ("perl", f, fn)) { 02093 char ** av = NULL; 02094 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02095 rpmperl perl = rpmperlNew(av, _globalI); 02096 const char * result = NULL; 02097 02098 if (rpmperlRun(perl, script, &result) != RPMRC_OK) 02099 rc = 1; 02100 else { 02101 if (result == NULL) result = "FIXME"; 02102 if (result != NULL && *result != '\0') { 02103 size_t len = strlen(result); 02104 if (len > mb->nb) 02105 len = mb->nb; 02106 memcpy(mb->t, result, len); 02107 mb->t += len; 02108 mb->nb -= len; 02109 } 02110 } 02111 perl = rpmperlFree(perl); 02112 av = _free(av); 02113 script = _free(script); 02114 s = se; 02115 continue; 02116 } 02117 #endif 02118 02119 #ifdef WITH_PYTHONEMBED 02120 if (STREQ("python", f, fn)) { 02121 char ** av = NULL; 02122 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02123 rpmpython python = rpmpythonNew(av, _globalI); 02124 const char * result = NULL; 02125 02126 if (rpmpythonRun(python, script, &result) != RPMRC_OK) 02127 rc = 1; 02128 else { 02129 if (result == NULL) result = "FIXME"; 02130 if (result != NULL && *result != '\0') { 02131 size_t len = strlen(result); 02132 if (len > mb->nb) 02133 len = mb->nb; 02134 memcpy(mb->t, result, len); 02135 mb->t += len; 02136 mb->nb -= len; 02137 } 02138 } 02139 python = rpmpythonFree(python); 02140 av = _free(av); 02141 script = _free(script); 02142 s = se; 02143 continue; 02144 } 02145 #endif 02146 02147 #ifdef WITH_RUBYEMBED 02148 if (STREQ("ruby", f, fn)) { 02149 char ** av = NULL; 02150 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02151 rpmruby ruby = rpmrubyNew(av, _globalI); 02152 const char * result = NULL; 02153 02154 if (rpmrubyRun(ruby, script, &result) != RPMRC_OK) 02155 rc = 1; 02156 else { 02157 if (result == NULL) result = "FIXME"; 02158 if (result != NULL && *result != '\0') { 02159 size_t len = strlen(result); 02160 if (len > mb->nb) 02161 len = mb->nb; 02162 memcpy(mb->t, result, len); 02163 mb->t += len; 02164 mb->nb -= len; 02165 } 02166 } 02167 ruby = rpmrubyFree(ruby); 02168 av = _free(av); 02169 script = _free(script); 02170 s = se; 02171 continue; 02172 } 02173 #endif 02174 02175 #ifdef WITH_SEMANAGE 02176 if (STREQ("spook", f, fn)) { 02177 /* XXX change rpmsmNew() to common embedded interpreter API */ 02178 #ifdef NOTYET 02179 char ** av = NULL; 02180 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02181 #else 02182 /* XXX use xstrndup (which never returns NULL) instead. */ 02183 char * script = strndup(g, (size_t)(se-g-1)); 02184 char * av[2]; 02185 /* XXX FIXME */ 02186 static const char * _rpmsmStore = "targeted"; 02187 static unsigned int _rpmsmFlags = 0; 02188 #endif 02189 rpmsm sm = (_globalI ? NULL 02190 : rpmsmNew(_rpmsmStore, _rpmsmFlags)); 02191 const char * result = NULL; 02192 02193 /* XXX HACK: use an argv for now. */ 02194 av[0] = script; 02195 av[1] = NULL; 02196 if (rpmsmRun(sm, av, &result) != RPMRC_OK) 02197 rc = 1; 02198 else { 02199 if (result == NULL) result = "FIXME"; 02200 if (result != NULL && *result != '\0') { 02201 size_t len = strlen(result); 02202 if (len > mb->nb) 02203 len = mb->nb; 02204 memcpy(mb->t, result, len); 02205 mb->t += len; 02206 mb->nb -= len; 02207 } 02208 } 02209 sm = rpmsmFree(sm); 02210 #ifdef NOTYET 02211 av = _free(av); 02212 #endif 02213 script = _free(script); 02214 s = se; 02215 continue; 02216 } 02217 #endif 02218 02219 #ifdef WITH_SQLITE 02220 if (STREQ("sql", f, fn)) { 02221 char ** av = NULL; 02222 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02223 rpmsql sql = rpmsqlNew(av, _globalI); 02224 const char * result = NULL; 02225 02226 if (rpmsqlRun(sql, script, &result) != RPMRC_OK) 02227 rc = 1; 02228 else { 02229 if (result == NULL) result = "FIXME"; 02230 if (result != NULL && *result != '\0') { 02231 size_t len = strlen(result); 02232 if (len > mb->nb) 02233 len = mb->nb; 02234 memcpy(mb->t, result, len); 02235 mb->t += len; 02236 mb->nb -= len; 02237 } 02238 } 02239 sql = rpmsqlFree(sql); 02240 av = _free(av); 02241 script = _free(script); 02242 s = se; 02243 continue; 02244 } 02245 #endif 02246 02247 #ifdef WITH_SQUIRREL 02248 if (STREQ("squirrel", f, fn)) { 02249 char ** av = NULL; 02250 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02251 rpmsquirrel squirrel = rpmsquirrelNew(av, _globalI); 02252 const char * result = NULL; 02253 02254 if (rpmsquirrelRun(squirrel, script, &result) != RPMRC_OK) 02255 rc = 1; 02256 else { 02257 if (result == NULL) result = "FIXME"; 02258 if (result != NULL && *result != '\0') { 02259 size_t len = strlen(result); 02260 if (len > mb->nb) 02261 len = mb->nb; 02262 memcpy(mb->t, result, len); 02263 mb->t += len; 02264 mb->nb -= len; 02265 } 02266 } 02267 squirrel = rpmsquirrelFree(squirrel); 02268 av = _free(av); 02269 script = _free(script); 02270 s = se; 02271 continue; 02272 } 02273 #endif 02274 02275 #ifdef WITH_TCL 02276 if (STREQ("tcl", f, fn)) { 02277 char ** av = NULL; 02278 char * script = parseEmbedded(s, (size_t)(se-s), &av); 02279 rpmtcl tcl = rpmtclNew(av, _globalI); 02280 const char * result = NULL; 02281 02282 if (rpmtclRun(tcl, script, &result) != RPMRC_OK) 02283 rc = 1; 02284 else if (result != NULL && *result != '\0') { 02285 size_t len = strlen(result); 02286 if (len > mb->nb) 02287 len = mb->nb; 02288 memcpy(mb->t, result, len); 02289 mb->t += len; 02290 mb->nb -= len; 02291 } 02292 tcl = rpmtclFree(tcl); 02293 av = _free(av); 02294 script = _free(script); 02295 s = se; 02296 continue; 02297 } 02298 #endif 02299 02300 /* Rewrite "%patchNN ..." as "%patch -P NN ..." and expand. */ 02301 if (lastc && fn > 5 && STREQ("patch", f, 5) && xisdigit((int)f[5])) { 02302 /*@-internalglobs@*/ /* FIX: verbose may be set */ 02303 doFoo(mb, negate, f, (lastc - f), NULL, 0); 02304 /*@=internalglobs@*/ 02305 s = lastc; 02306 continue; 02307 } 02308 02309 /* XXX necessary but clunky */ 02310 if (STREQ("basename", f, fn) || 02311 STREQ("dirname", f, fn) || 02312 STREQ("realpath", f, fn) || 02313 STREQ("getenv", f, fn) || 02314 STREQ("shrink", f, fn) || 02315 STREQ("suffix", f, fn) || 02316 STREQ("expand", f, fn) || 02317 STREQ("verbose", f, fn) || 02318 STREQ("uncompress", f, fn) || 02319 STREQ("mkstemp", f, fn) || 02320 STREQ("mkdtemp", f, fn) || 02321 STREQ("uuid", f, fn) || 02322 STREQ("url2path", f, fn) || 02323 STREQ("u2p", f, fn) || 02324 STREQ("S", f, fn) || 02325 STREQ("P", f, fn) || 02326 STREQ("F", f, fn)) { 02327 /*@-internalglobs@*/ /* FIX: verbose may be set */ 02328 doFoo(mb, negate, f, fn, g, gn); 02329 /*@=internalglobs@*/ 02330 s = se; 02331 continue; 02332 } 02333 02334 /* Expand defined macros */ 02335 mep = findEntry(mb->mc, f, fn); 02336 me = (mep ? *mep : NULL); 02337 02338 /* XXX Special processing for flags */ 02339 if (*f == '-') { 02340 if (me) 02341 me->used++; /* Mark macro as used */ 02342 if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */ 02343 (me != NULL && negate)) { /* With -f, skip %{!-f...} */ 02344 s = se; 02345 continue; 02346 } 02347 02348 if (g && g < ge) { /* Expand X in %{-f:X} */ 02349 rc = expandT(mb, g, gn); 02350 } else 02351 if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */ 02352 rc = expandT(mb, me->body, strlen(me->body)); 02353 } 02354 s = se; 02355 continue; 02356 } 02357 02358 /* XXX Special processing for macro existence */ 02359 if (chkexist) { 02360 if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */ 02361 (me != NULL && negate)) { /* With -f, skip %{!?f...} */ 02362 s = se; 02363 continue; 02364 } 02365 if (g && g < ge) { /* Expand X in %{?f:X} */ 02366 rc = expandT(mb, g, gn); 02367 } else 02368 if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */ 02369 rc = expandT(mb, me->body, strlen(me->body)); 02370 } 02371 s = se; 02372 continue; 02373 } 02374 02375 if (me == NULL) { /* leave unknown %... as is */ 02376 #if !defined(RPM_VENDOR_WINDRIVER_DEBUG) /* XXX usually disabled */ 02377 #if DEAD 02378 /* XXX hack to skip over empty arg list */ 02379 if (fn == 1 && *f == '*') { 02380 s = se; 02381 continue; 02382 } 02383 #endif 02384 /* XXX hack to permit non-overloaded %foo to be passed */ 02385 c = (int) '%'; /* XXX only need to save % */ 02386 SAVECHAR(mb, c); 02387 #else 02388 if (!strncmp(f, "if", fn) || 02389 !strncmp(f, "else", fn) || 02390 !strncmp(f, "endif", fn)) { 02391 c = '%'; /* XXX only need to save % */ 02392 SAVECHAR(mb, c); 02393 } else { 02394 rpmlog(RPMLOG_ERR, 02395 _("Macro %%%.*s not found, skipping\n"), fn, f); 02396 s = se; 02397 } 02398 #endif 02399 continue; 02400 } 02401 02402 /* XXX Special processing to create a tuple from stack'd values. */ 02403 if (stackarray) { 02404 if (!(g && g < ge)) { 02405 g = "\n"; 02406 gn = strlen(g); 02407 } 02408 rc = expandFIFO(mb, me, g, gn); 02409 s = se; 02410 continue; 02411 } 02412 02413 /* Setup args for "%name " macros with opts */ 02414 if (me && me->opts != NULL) { 02415 if (lastc != NULL) { 02416 se = grabArgs(mb, me, fe, lastc); 02417 } else { 02418 addMacro(mb->mc, "**", NULL, "", mb->depth); 02419 addMacro(mb->mc, "*", NULL, "", mb->depth); 02420 addMacro(mb->mc, "#", NULL, "0", mb->depth); 02421 addMacro(mb->mc, "0", NULL, me->name, mb->depth); 02422 } 02423 } 02424 02425 /* Recursively expand body of macro */ 02426 if (me->body && *me->body) { 02427 mb->s = me->body; 02428 rc = expandMacro(mb); 02429 if (rc == 0) 02430 me->used++; /* Mark macro as used */ 02431 } 02432 02433 /* Free args for "%name " macros with opts */ 02434 if (me->opts != NULL) 02435 freeArgs(mb); 02436 02437 s = se; 02438 } 02439 02440 *mb->t = '\0'; 02441 mb->s = s; 02442 mb->depth--; 02443 if (rc != 0 || mb->expand_trace) 02444 printExpansion(mb, t, mb->t); 02445 return rc; 02446 } 02447 02448 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \ 02449 !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */ 02450 int rpmSecuritySaneFile(const char *filename) 02451 { 02452 struct stat sb; 02453 uid_t uid; 02454 02455 if (stat(filename, &sb) == -1) 02456 return 1; 02457 uid = getuid(); 02458 if (sb.st_uid != uid) 02459 return 0; 02460 if (!S_ISREG(sb.st_mode)) 02461 return 0; 02462 if (sb.st_mode & (S_IWGRP|S_IWOTH)) 02463 return 0; 02464 return 1; 02465 } 02466 #endif 02467 02468 #if !defined(DEBUG_MACROS) 02469 /* =============================================================== */ 02470 /*@unchecked@*/ 02471 static int _debug = 0; 02472 02473 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr) 02474 { 02475 int ac = 0; 02476 char ** av = NULL; 02477 int argc = 0; 02478 const char ** argv = NULL; 02479 char * globRoot = NULL; 02480 #ifdef ENABLE_NLS 02481 const char * old_collate = NULL; 02482 const char * old_ctype = NULL; 02483 const char * t; 02484 #endif 02485 size_t maxb, nb; 02486 size_t i; 02487 int j; 02488 int rc; 02489 02490 rc = XpoptParseArgvString(patterns, &ac, &av); 02491 if (rc) 02492 return rc; 02493 #ifdef ENABLE_NLS 02494 t = setlocale(LC_COLLATE, NULL); 02495 if (t) 02496 old_collate = xstrdup(t); 02497 t = setlocale(LC_CTYPE, NULL); 02498 if (t) 02499 old_ctype = xstrdup(t); 02500 (void) setlocale(LC_COLLATE, "C"); 02501 (void) setlocale(LC_CTYPE, "C"); 02502 #endif 02503 02504 if (av != NULL) 02505 for (j = 0; j < ac; j++) { 02506 const char * globURL; 02507 const char * path; 02508 int ut = urlPath(av[j], &path); 02509 glob_t gl; 02510 02511 if (!Glob_pattern_p(av[j], 0) && strchr(path, '~') == NULL) { 02512 argv = xrealloc(argv, (argc+2) * sizeof(*argv)); 02513 argv[argc] = xstrdup(av[j]); 02514 if (_debug) 02515 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]); 02516 argc++; 02517 continue; 02518 } 02519 02520 gl.gl_pathc = 0; 02521 gl.gl_pathv = NULL; 02522 rc = Glob(av[j], GLOB_TILDE, Glob_error, &gl); 02523 if (rc) 02524 goto exit; 02525 02526 /* XXX Prepend the URL leader for globs that have stripped it off */ 02527 maxb = 0; 02528 for (i = 0; i < gl.gl_pathc; i++) { 02529 if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb) 02530 maxb = nb; 02531 } 02532 02533 nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0); 02534 maxb += nb; 02535 maxb += 1; 02536 globURL = globRoot = xmalloc(maxb); 02537 02538 switch (ut) { 02539 case URL_IS_PATH: 02540 case URL_IS_DASH: 02541 strncpy(globRoot, av[j], nb); 02542 /*@switchbreak@*/ break; 02543 case URL_IS_HKP: 02544 case URL_IS_FTP: 02545 case URL_IS_HTTP: 02546 case URL_IS_HTTPS: 02547 case URL_IS_MONGO: /* XXX FIXME */ 02548 case URL_IS_UNKNOWN: 02549 default: 02550 /*@switchbreak@*/ break; 02551 } 02552 globRoot += nb; 02553 *globRoot = '\0'; 02554 if (_debug) 02555 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL); 02556 02557 argv = xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv)); 02558 02559 if (argv != NULL) 02560 for (i = 0; i < gl.gl_pathc; i++) { 02561 const char * globFile = &(gl.gl_pathv[i][0]); 02562 if (globRoot > globURL && globRoot[-1] == '/') 02563 while (*globFile == '/') globFile++; 02564 strcpy(globRoot, globFile); 02565 if (_debug) 02566 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL); 02567 argv[argc++] = xstrdup(globURL); 02568 } 02569 /*@-immediatetrans@*/ 02570 Globfree(&gl); 02571 /*@=immediatetrans@*/ 02572 globURL = _free(globURL); 02573 } 02574 02575 if (argv != NULL && argc > 0) { 02576 argv[argc] = NULL; 02577 if (argvPtr) 02578 *argvPtr = argv; 02579 if (argcPtr) 02580 *argcPtr = argc; 02581 rc = 0; 02582 } else 02583 rc = 1; 02584 02585 02586 exit: 02587 #ifdef ENABLE_NLS 02588 if (old_collate) { 02589 (void) setlocale(LC_COLLATE, old_collate); 02590 old_collate = _free(old_collate); 02591 } 02592 if (old_ctype) { 02593 (void) setlocale(LC_CTYPE, old_ctype); 02594 old_ctype = _free(old_ctype); 02595 } 02596 #endif 02597 av = _free(av); 02598 if (rc || argvPtr == NULL) { 02599 /*@-dependenttrans -unqualifiedtrans@*/ 02600 if (argv != NULL) 02601 for (j = 0; j < argc; j++) 02602 argv[j] = _free(argv[j]); 02603 argv = _free(argv); 02604 /*@=dependenttrans =unqualifiedtrans@*/ 02605 } 02606 return rc; 02607 } 02608 #endif /* !defined(DEBUG_MACROS) */ 02609 02610 /* =============================================================== */ 02611 02612 int 02613 expandMacros(void * spec, MacroContext mc, char * sbuf, size_t slen) 02614 { 02615 MacroBuf mb = alloca(sizeof(*mb)); 02616 char *tbuf; 02617 int rc; 02618 02619 if (sbuf == NULL || slen == 0) 02620 return 0; 02621 if (mc == NULL) mc = rpmGlobalMacroContext; 02622 02623 tbuf = alloca(slen + 1); 02624 tbuf[0] = '\0'; 02625 02626 mb->s = sbuf; 02627 mb->t = tbuf; 02628 mb->nb = slen; 02629 mb->depth = 0; 02630 mb->macro_trace = print_macro_trace; 02631 mb->expand_trace = print_expand_trace; 02632 02633 mb->spec = spec; /* (future) %file expansion info */ 02634 mb->mc = mc; 02635 02636 rc = expandMacro(mb); 02637 02638 tbuf[slen] = '\0'; 02639 if (mb->nb == 0) 02640 rpmlog(RPMLOG_ERR, _("Macro expansion too big for target buffer\n")); 02641 else 02642 strncpy(sbuf, tbuf, (slen - mb->nb + 1)); 02643 02644 return rc; 02645 } 02646 02647 void 02648 addMacro(MacroContext mc, 02649 const char * n, const char * o, const char * b, int level) 02650 { 02651 MacroEntry * mep; 02652 const char * name = n; 02653 02654 if (*name == '.') /* XXX readonly macros */ 02655 name++; 02656 if (*name == '.') /* XXX readonly macros */ 02657 name++; 02658 02659 if (mc == NULL) mc = rpmGlobalMacroContext; 02660 02661 /* If new name, expand macro table */ 02662 if ((mep = findEntry(mc, name, 0)) == NULL) { 02663 if (mc->firstFree == mc->macrosAllocated) 02664 expandMacroTable(mc); 02665 if (mc->macroTable != NULL) 02666 mep = mc->macroTable + mc->firstFree++; 02667 } 02668 02669 if (mep != NULL) { 02670 /* XXX permit "..foo" to be pushed over ".foo" */ 02671 if (*mep && (*mep)->flags && !(n[0] == '.' && n[1] == '.')) { 02672 /* XXX avoid error message for %buildroot */ 02673 if (strcmp((*mep)->name, "buildroot")) 02674 rpmlog(RPMLOG_ERR, _("Macro '%s' is readonly and cannot be changed.\n"), n); 02675 return; 02676 } 02677 /* Push macro over previous definition */ 02678 pushMacro(mep, n, o, b, level); 02679 02680 /* If new name, sort macro table */ 02681 if ((*mep)->prev == NULL) 02682 sortMacroTable(mc); 02683 } 02684 } 02685 02686 void 02687 delMacro(MacroContext mc, const char * n) 02688 { 02689 MacroEntry * mep; 02690 02691 if (mc == NULL) mc = rpmGlobalMacroContext; 02692 /* If name exists, pop entry */ 02693 if ((mep = findEntry(mc, n, 0)) != NULL) { 02694 popMacro(mep); 02695 /* If deleted name, sort macro table */ 02696 if (!(mep && *mep)) 02697 sortMacroTable(mc); 02698 } 02699 } 02700 02701 /*@-mustmod@*/ /* LCL: mc is modified through mb->mc, mb is abstract */ 02702 int 02703 rpmDefineMacro(MacroContext mc, const char * macro, int level) 02704 { 02705 MacroBuf mb = alloca(sizeof(*mb)); 02706 02707 memset(mb, 0, sizeof(*mb)); 02708 /* XXX just enough to get by */ 02709 mb->mc = (mc ? mc : rpmGlobalMacroContext); 02710 (void) doDefine(mb, macro, level, 0); 02711 return 0; 02712 } 02713 /*@=mustmod@*/ 02714 02715 /*@-mustmod@*/ /* LCL: mc is modified through mb->mc, mb is abstract */ 02716 int 02717 rpmUndefineMacro(MacroContext mc, const char * macro) 02718 { 02719 (void) doUndefine(mc ? mc : rpmGlobalMacroContext, macro); 02720 return 0; 02721 } 02722 /*@=mustmod@*/ 02723 02724 void 02725 rpmLoadMacros(MacroContext mc, int level) 02726 { 02727 02728 if (mc == NULL || mc == rpmGlobalMacroContext) 02729 return; 02730 02731 if (mc->macroTable != NULL) { 02732 int i; 02733 for (i = 0; i < mc->firstFree; i++) { 02734 MacroEntry *mep, me; 02735 mep = &mc->macroTable[i]; 02736 me = *mep; 02737 02738 if (me == NULL) /* XXX this should never happen */ 02739 continue; 02740 addMacro(NULL, me->name, me->opts, me->body, (level - 1)); 02741 } 02742 } 02743 } 02744 02745 #if defined(RPM_VENDOR_OPENPKG) /* expand-macrosfile-macro */ 02746 static void expand_macrosfile_macro(const char *file_name, const char *buf, size_t bufn) 02747 { 02748 char *cp; 02749 size_t l, k; 02750 static const char *macro_name = "%{macrosfile}"; 02751 02752 l = strlen(macro_name); 02753 k = strlen(file_name); 02754 while ((cp = strstr(buf, macro_name)) != NULL) { 02755 if (((strlen(buf) - l) + k) < bufn) { 02756 memmove(cp+k, cp+l, strlen(cp+l)+1); 02757 memcpy(cp, file_name, k); 02758 } 02759 } 02760 return; 02761 } 02762 #endif 02763 02764 int 02765 rpmLoadMacroFile(MacroContext mc, const char * fn, int nesting) 02766 { 02767 size_t bufn = _macro_BUFSIZ; 02768 char *buf = alloca(bufn); 02769 int lineno = 0; 02770 int rc = -1; 02771 FD_t fd; 02772 int xx; 02773 02774 /* XXX TODO: teach rdcl() to read through a URI, eliminate ".fpio". */ 02775 fd = Fopen(fn, "r.fpio"); 02776 if (fd == NULL || Ferror(fd)) { 02777 if (fd) (void) Fclose(fd); 02778 return rc; 02779 } 02780 02781 /* XXX Assume new fangled macro expansion */ 02782 /*@-mods@*/ 02783 max_macro_depth = _MAX_MACRO_DEPTH; 02784 /*@=mods@*/ 02785 02786 buf[0] = '\0'; 02787 while(rdcl(buf, bufn, fd) != NULL) { 02788 char * s; 02789 int c; 02790 02791 lineno++; 02792 s = buf; 02793 SKIPBLANK(s, c); 02794 02795 if (c != (int) '%') 02796 continue; 02797 02798 /* Parse %{load:...} immediately recursively. */ 02799 if (s[1] == '{' && !strncmp(s+2, "load:", sizeof("load:")-1)) { 02800 char * se = (char *) matchchar(s, '{', '}'); 02801 if (se == NULL) { 02802 rpmlog(RPMLOG_WARNING, 02803 _("%s:%u Missing '}' in \"%s\", skipping.\n"), 02804 fn, lineno, buf); 02805 continue; 02806 } 02807 s += sizeof("%{load:") - 1; 02808 SKIPBLANK(s, c); 02809 *se = '\0'; 02810 if (nesting <= 0) { 02811 rpmlog(RPMLOG_WARNING, 02812 _("%s:%u load depth exceeded, \"%s\" ignored.\n"), 02813 fn, lineno, buf); 02814 continue; 02815 } 02816 se = rpmMCExpand(mc, s, NULL); 02817 rc = rpmLoadMacroFile(mc, se, nesting - 1); 02818 se = _free(se); 02819 if (rc != 0) 02820 goto exit; 02821 } else { 02822 #if defined(RPM_VENDOR_OPENPKG) /* expand-macro-source */ 02823 expand_macrosfile_macro(fn, buf, bufn); 02824 #endif 02825 if (*s == '%') s++; 02826 rc = rpmDefineMacro(mc, s, RMIL_MACROFILES); 02827 } 02828 } 02829 rc = 0; 02830 exit: 02831 xx = Fclose(fd); 02832 return rc; 02833 } 02834 02835 void 02836 rpmInitMacros(MacroContext mc, const char * macrofiles) 02837 { 02838 char *mfiles, *m, *me; 02839 02840 if (macrofiles == NULL) 02841 return; 02842 #ifdef DYING 02843 if (mc == NULL) mc = rpmGlobalMacroContext; 02844 #endif 02845 02846 mfiles = xstrdup(macrofiles); 02847 for (m = mfiles; m && *m != '\0'; m = me) { 02848 const char ** av; 02849 int ac; 02850 int i; 02851 02852 for (me = m; (me = strchr(me, ':')) != NULL; me++) { 02853 /* Skip over URI's. */ 02854 if (!(me[1] == '/' && me[2] == '/')) 02855 /*@innerbreak@*/ break; 02856 } 02857 02858 if (me && *me == ':') 02859 *me++ = '\0'; 02860 else 02861 me = m + strlen(m); 02862 02863 /* Glob expand the macro file path element, expanding ~ to $HOME. */ 02864 ac = 0; 02865 av = NULL; 02866 #if defined(DEBUG_MACROS) 02867 ac = 1; 02868 av = xmalloc((ac + 1) * sizeof(*av)); 02869 av[0] = strdup(m); 02870 av[1] = NULL; 02871 #else 02872 i = rpmGlob(m, &ac, &av); 02873 if (i != 0) 02874 continue; 02875 #endif 02876 02877 /* Read macros from each file. */ 02878 02879 for (i = 0; i < ac; i++) { 02880 size_t slen = strlen(av[i]); 02881 const char *fn = av[i]; 02882 02883 if (fn[0] == '@' /* attention */) { 02884 fn++; 02885 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \ 02886 !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */ 02887 if (!rpmSecuritySaneFile(fn)) 02888 #else 02889 if (!poptSaneFile(fn)) 02890 #endif 02891 { 02892 rpmlog(RPMLOG_WARNING, "existing RPM macros file \"%s\" considered INSECURE -- not loaded\n", fn); 02893 /*@innercontinue@*/ continue; 02894 } 02895 } 02896 02897 /* Skip backup files and %config leftovers. */ 02898 #define _suffix(_s, _x) \ 02899 (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x))) 02900 if (!(_suffix(fn, "~") 02901 || _suffix(fn, ".rpmnew") 02902 || _suffix(fn, ".rpmorig") 02903 || _suffix(fn, ".rpmsave")) 02904 ) 02905 (void) rpmLoadMacroFile(mc, fn, _max_load_depth); 02906 #undef _suffix 02907 02908 av[i] = _free(av[i]); 02909 } 02910 av = _free(av); 02911 } 02912 mfiles = _free(mfiles); 02913 02914 /* Reload cmdline macros */ 02915 /*@-mods@*/ 02916 rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE); 02917 /*@=mods@*/ 02918 } 02919 02920 /*@-globstate@*/ 02921 void 02922 rpmFreeMacros(MacroContext mc) 02923 { 02924 02925 if (mc == NULL) mc = rpmGlobalMacroContext; 02926 02927 if (mc->macroTable != NULL) { 02928 int i; 02929 for (i = 0; i < mc->firstFree; i++) { 02930 MacroEntry me; 02931 while ((me = mc->macroTable[i]) != NULL) { 02932 /* XXX cast to workaround const */ 02933 /*@-onlytrans@*/ 02934 if ((mc->macroTable[i] = me->prev) == NULL) 02935 me->name = _free(me->name); 02936 /*@=onlytrans@*/ 02937 me->opts = _free(me->opts); 02938 me->body = _free(me->body); 02939 me = _free(me); 02940 } 02941 } 02942 mc->macroTable = _free(mc->macroTable); 02943 } 02944 memset(mc, 0, sizeof(*mc)); 02945 } 02946 /*@=globstate@*/ 02947 02948 /* =============================================================== */ 02949 int isCompressed(const char * file, rpmCompressedMagic * compressed) 02950 { 02951 FD_t fd; 02952 ssize_t nb; 02953 int rc = -1; 02954 unsigned char magic[13]; 02955 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */ 02956 size_t file_len; 02957 #endif 02958 02959 *compressed = COMPRESSED_NOT; 02960 02961 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_FEDORA) || defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */ 02962 file_len = strlen(file); 02963 if ((file_len > 4 && strcasecmp(file+file_len-4, ".tbz") == 0) 02964 || (file_len > 4 && strcasecmp(file+file_len-4, ".bz2") == 0)) { 02965 *compressed = COMPRESSED_BZIP2; 02966 return 0; 02967 } else 02968 if (file_len > 4 && strcasecmp(file+file_len-4, ".zip") == 0) { 02969 *compressed = COMPRESSED_ZIP; 02970 return 0; 02971 } else 02972 if ((file_len > 4 && strcasecmp(file+file_len-4, ".tlz") == 0) 02973 || (file_len > 5 && strcasecmp(file+file_len-5, ".lzma") == 0)) { 02974 *compressed = COMPRESSED_LZMA; 02975 return 0; 02976 } else 02977 if (file_len > 4 && strcasecmp(file+file_len-3, ".xz") == 0) { 02978 *compressed = COMPRESSED_XZ; 02979 return 0; 02980 } else 02981 if ((file_len > 4 && strcasecmp(file+file_len-4, ".tgz") == 0) 02982 || (file_len > 3 && strcasecmp(file+file_len-3, ".gz") == 0) 02983 || (file_len > 2 && strcasecmp(file+file_len-2, ".Z") == 0)) { 02984 *compressed = COMPRESSED_OTHER; 02985 return 0; 02986 } else 02987 if (file_len > 5 && strcasecmp(file+file_len-5, ".cpio") == 0) { 02988 *compressed = COMPRESSED_NOT; 02989 return 0; 02990 } else 02991 if (file_len > 4 && strcasecmp(file+file_len-4, ".tar") == 0) { 02992 *compressed = COMPRESSED_NOT; 02993 return 0; 02994 } 02995 #endif 02996 02997 fd = Fopen(file, "r"); 02998 if (fd == NULL || Ferror(fd)) { 02999 /* XXX Fstrerror */ 03000 rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd)); 03001 if (fd) (void) Fclose(fd); 03002 return 1; 03003 } 03004 nb = Fread(magic, sizeof(magic[0]), sizeof(magic), fd); 03005 if (nb < (ssize_t)0) { 03006 rpmlog(RPMLOG_ERR, _("File %s: %s\n"), file, Fstrerror(fd)); 03007 rc = 1; 03008 } else if (nb < (ssize_t)sizeof(magic)) { 03009 rpmlog(RPMLOG_ERR, _("File %s is smaller than %u bytes\n"), 03010 file, (unsigned)sizeof(magic)); 03011 rc = 0; 03012 } 03013 (void) Fclose(fd); 03014 if (rc >= 0) 03015 return rc; 03016 03017 rc = 0; 03018 03019 if (magic[0] == 'B' && magic[1] == 'Z') 03020 *compressed = COMPRESSED_BZIP2; 03021 else 03022 if (magic[0] == (unsigned char) 0120 && magic[1] == (unsigned char) 0113 03023 && magic[2] == (unsigned char) 0003 && magic[3] == (unsigned char) 0004) /* pkzip */ 03024 *compressed = COMPRESSED_ZIP; 03025 else 03026 if (magic[0] == (unsigned char) 0x89 && magic[1] == 'L' 03027 && magic[2] == 'Z' && magic[3] == 'O') /* lzop */ 03028 *compressed = COMPRESSED_LZOP; 03029 else 03030 #if !defined(RPM_VENDOR_OPENPKG) && !defined(RPM_VENDOR_FEDORA) && !defined(RPM_VENDOR_MANDRIVA) /* extension-based-compression-detection */ 03031 /* XXX Ick, LZMA has no magic. See http://lkml.org/lkml/2005/6/13/285 */ 03032 if (magic[ 9] == (unsigned char) 0x00 && magic[10] == (unsigned char) 0x00 && 03033 magic[11] == (unsigned char) 0x00 && magic[12] == (unsigned char) 0x00) /* lzmash */ 03034 *compressed = COMPRESSED_LZMA; 03035 else 03036 #endif 03037 #if defined(RPM_VENDOR_OPENSUSE) 03038 if (magic[0] == 0135 && magic[1] == 0 && magic[2] == 0) /* lzma */ 03039 *compressed = COMPRESSED_LZMA; 03040 else 03041 #endif 03042 if (magic[0] == (unsigned char) 0xFD && magic[1] == 0x37 && magic[2] == 0x7A 03043 && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00) /* xz */ 03044 *compressed = COMPRESSED_XZ; 03045 else if ((magic[0] == 'L') && (magic[1] == 'Z') && 03046 (magic[2] == 'I') && (magic[3] == 'P')) /* lzip */ 03047 *compressed = COMPRESSED_LZIP; 03048 else if ((magic[0] == 'L') && (magic[1] == 'R') && 03049 (magic[2] == 'Z') && (magic[3] == 'I')) /* lrzip */ 03050 *compressed = COMPRESSED_LRZIP; 03051 else 03052 if ((magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0213) /* gzip */ 03053 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0236) /* old gzip */ 03054 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0036) /* pack */ 03055 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0240) /* SCO lzh */ 03056 || (magic[0] == (unsigned char) 0037 && magic[1] == (unsigned char) 0235)) /* compress */ 03057 *compressed = COMPRESSED_OTHER; 03058 03059 return rc; 03060 } 03061 03062 /* =============================================================== */ 03063 03064 /*@-modfilesys@*/ 03065 /* XXX TODO: merge rpmExpand and rpmMCExpand. gud enuf for now ... */ 03066 char * 03067 rpmExpand(const char *arg, ...) 03068 { 03069 MacroContext mc = NULL; 03070 const char *s; 03071 char *t, *te; 03072 size_t sn, tn; 03073 size_t bufn = 8 * _macro_BUFSIZ; 03074 03075 va_list ap; 03076 03077 if (arg == NULL) 03078 return xstrdup(""); 03079 03080 t = xmalloc(bufn + strlen(arg) + 1); 03081 *t = '\0'; 03082 te = stpcpy(t, arg); 03083 03084 va_start(ap, arg); 03085 while ((s = va_arg(ap, const char *)) != NULL) { 03086 sn = strlen(s); 03087 tn = (te - t); 03088 t = xrealloc(t, tn + sn + bufn + 1); 03089 te = t + tn; 03090 te = stpcpy(te, s); 03091 } 03092 va_end(ap); 03093 03094 *te = '\0'; 03095 tn = (te - t); 03096 (void) expandMacros(NULL, mc, t, tn + bufn + 1); 03097 t[tn + bufn] = '\0'; 03098 t = xrealloc(t, strlen(t) + 1); 03099 03100 return t; 03101 } 03102 03103 char * 03104 rpmMCExpand(MacroContext mc, const char *arg, ...) 03105 { 03106 const char *s; 03107 char *t, *te; 03108 size_t sn, tn; 03109 size_t bufn = 8 * _macro_BUFSIZ; 03110 03111 va_list ap; 03112 03113 if (arg == NULL) 03114 return xstrdup(""); 03115 03116 t = xmalloc(bufn + strlen(arg) + 1); 03117 *t = '\0'; 03118 te = stpcpy(t, arg); 03119 03120 va_start(ap, arg); 03121 while ((s = va_arg(ap, const char *)) != NULL) { 03122 sn = strlen(s); 03123 tn = (te - t); 03124 t = xrealloc(t, tn + sn + bufn + 1); 03125 te = t + tn; 03126 te = stpcpy(te, s); 03127 } 03128 va_end(ap); 03129 03130 *te = '\0'; 03131 tn = (te - t); 03132 (void) expandMacros(NULL, mc, t, tn + bufn + 1); 03133 t[tn + bufn] = '\0'; 03134 t = xrealloc(t, strlen(t) + 1); 03135 03136 return t; 03137 } 03138 /*@=modfilesys@*/ 03139 03140 int 03141 rpmExpandNumeric(const char *arg) 03142 { 03143 const char *val; 03144 int rc; 03145 03146 if (arg == NULL) 03147 return 0; 03148 03149 val = rpmExpand(arg, NULL); 03150 if (!(val && *val != '%')) 03151 rc = 0; 03152 else if (*val == 'Y' || *val == 'y') 03153 rc = 1; 03154 else if (*val == 'N' || *val == 'n') 03155 rc = 0; 03156 else { 03157 char *end; 03158 rc = strtol(val, &end, 0); 03159 if (!(end && *end == '\0')) 03160 rc = 0; 03161 } 03162 val = _free(val); 03163 03164 return rc; 03165 } 03166 03167 /* @todo "../sbin/./../bin/" not correct. */ 03168 char *rpmCleanPath(char * path) 03169 { 03170 const char *s; 03171 char *se, *t, *te; 03172 int begin = 1; 03173 03174 if (path == NULL) 03175 return NULL; 03176 03177 /*fprintf(stderr, "*** RCP %s ->\n", path); */ 03178 s = t = te = path; 03179 while (*s != '\0') { 03180 /*fprintf(stderr, "*** got \"%.*s\"\trest \"%s\"\n", (t-path), path, s); */ 03181 switch(*s) { 03182 case ':': /* handle url's */ 03183 if (s[1] == '/' && s[2] == '/') { 03184 *t++ = *s++; 03185 *t++ = *s++; 03186 /* XXX handle "file:///" */ 03187 if (s[0] == '/') *t++ = *s++; 03188 te = t; 03189 /*@switchbreak@*/ break; 03190 } 03191 begin=1; 03192 /*@switchbreak@*/ break; 03193 case '/': 03194 /* Move parent dir forward */ 03195 for (se = te + 1; se < t && *se != '/'; se++) 03196 {}; 03197 if (se < t && *se == '/') { 03198 te = se; 03199 /*fprintf(stderr, "*** next pdir \"%.*s\"\n", (te-path), path); */ 03200 } 03201 while (s[1] == '/') 03202 s++; 03203 while (t > te && t[-1] == '/') 03204 t--; 03205 /*@switchbreak@*/ break; 03206 case '.': 03207 /* Leading .. is special */ 03208 /* Check that it is ../, so that we don't interpret */ 03209 /* ..?(i.e. "...") or ..* (i.e. "..bogus") as "..". */ 03210 /* in the case of "...", this ends up being processed*/ 03211 /* as "../.", and the last '.' is stripped. This */ 03212 /* would not be correct processing. */ 03213 if (begin && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) { 03214 /*fprintf(stderr, " leading \"..\"\n"); */ 03215 *t++ = *s++; 03216 /*@switchbreak@*/ break; 03217 } 03218 /* Single . is special */ 03219 if (begin && s[1] == '\0') { 03220 /*@switchbreak@*/ break; 03221 } 03222 if (t > path && t[-1] == '/') 03223 switch (s[1]) { 03224 case '/': s++; /*@fallthrough@*/ /* Trim embedded ./ */ 03225 case '\0': s++; continue; /* Trim trailing /. */ 03226 default: /*@innerbreak@*/ break; 03227 } 03228 /* Trim embedded /../ and trailing /.. */ 03229 if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) { 03230 t = te; 03231 /* Move parent dir forward */ 03232 if (te > path) 03233 for (--te; te > path && *te != '/'; te--) 03234 {}; 03235 /*fprintf(stderr, "*** prev pdir \"%.*s\"\n", (te-path), path); */ 03236 s++; 03237 s++; 03238 continue; 03239 } 03240 /*@switchbreak@*/ break; 03241 default: 03242 begin = 0; 03243 /*@switchbreak@*/ break; 03244 } 03245 *t++ = *s++; 03246 } 03247 03248 /* Trim trailing / (but leave single / alone) */ 03249 if (t > &path[1] && t[-1] == '/') 03250 t--; 03251 *t = '\0'; 03252 03253 /*fprintf(stderr, "\t%s\n", path); */ 03254 return path; 03255 } 03256 03257 /* Return concatenated and expanded canonical path. */ 03258 03259 char * 03260 rpmGetPath(const char *path, ...) 03261 { 03262 size_t bufn = _macro_BUFSIZ; 03263 char *buf = alloca(bufn); 03264 const char * s; 03265 char * t, * te; 03266 int slashed = 0; 03267 va_list ap; 03268 03269 if (path == NULL) 03270 return xstrdup(""); 03271 03272 buf[0] = '\0'; 03273 t = buf; 03274 te = stpcpy(t, path); 03275 *te = '\0'; 03276 03277 va_start(ap, path); 03278 while ((s = va_arg(ap, const char *)) != NULL) { 03279 /* Specifically requested pesky trailing '/'? */ 03280 slashed = (s[0] == '/' && s[1] == '\0'); 03281 te = stpcpy(te, s); 03282 } 03283 va_end(ap); 03284 *te = '\0'; 03285 03286 /*@-modfilesys@*/ 03287 (void) expandMacros(NULL, NULL, buf, bufn); 03288 /*@=modfilesys@*/ 03289 03290 /* Note: rpmCleanPath will strip pesky trailing '/'. */ 03291 (void) rpmCleanPath(buf); 03292 03293 /* Re-append specifically requested pesky trailing '/'. */ 03294 if (slashed) { 03295 size_t nb = strlen(buf); 03296 if (buf[nb-1] != '/') 03297 buf[nb++] = '/'; 03298 buf[nb] = '\0'; 03299 } 03300 03301 return DRD_xstrdup(buf); /* XXX xstrdup has side effects. */ 03302 } 03303 03304 /* Merge 3 args into path, any or all of which may be a url. */ 03305 03306 const char * rpmGenPath(const char * urlroot, const char * urlmdir, 03307 const char *urlfile) 03308 { 03309 /*@owned@*/ const char * xroot = rpmGetPath(urlroot, NULL); 03310 /*@dependent@*/ const char * root = xroot; 03311 /*@owned@*/ const char * xmdir = rpmGetPath(urlmdir, NULL); 03312 /*@dependent@*/ const char * mdir = xmdir; 03313 /*@owned@*/ const char * xfile = rpmGetPath(urlfile, NULL); 03314 /*@dependent@*/ const char * file = xfile; 03315 const char * result; 03316 const char * url = NULL; 03317 size_t nurl = 0; 03318 int ut; 03319 03320 #if 0 03321 if (_debug) fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile); 03322 #endif 03323 ut = urlPath(xroot, &root); 03324 if (url == NULL && ut > URL_IS_DASH) { 03325 url = xroot; 03326 nurl = strlen(url); 03327 if (root >= url && root <= url+nurl) 03328 nurl -= strlen(root); 03329 #if 0 03330 if (_debug) fprintf(stderr, "*** RGP ut %d root %s nurl %u\n", ut, root, (unsigned)nurl); 03331 #endif 03332 } 03333 if (root == NULL || *root == '\0') root = "/"; 03334 03335 ut = urlPath(xmdir, &mdir); 03336 if (url == NULL && ut > URL_IS_DASH) { 03337 url = xmdir; 03338 nurl = strlen(url); 03339 if (mdir >= url && mdir <= url+nurl) 03340 nurl -= strlen(mdir); 03341 #if 0 03342 if (_debug) fprintf(stderr, "*** RGP ut %d mdir %s nurl %u\n", ut, mdir, (unsigned)nurl); 03343 #endif 03344 } 03345 if (mdir == NULL || *mdir == '\0') mdir = "/"; 03346 03347 ut = urlPath(xfile, &file); 03348 if (url == NULL && ut > URL_IS_DASH) { 03349 url = xfile; 03350 nurl = strlen(url); 03351 if (file >= url && file <= url+nurl) 03352 nurl -= strlen(file); 03353 #if 0 03354 if (_debug) fprintf(stderr, "*** RGP ut %d file %s nurl %u\n", ut, file, (unsigned)nurl); 03355 #endif 03356 } 03357 03358 if (url && nurl > 0) { 03359 char *t = strncpy(alloca(nurl+1), url, nurl); 03360 t[nurl] = '\0'; 03361 url = t; 03362 } else 03363 url = ""; 03364 03365 result = rpmGetPath(url, root, "/", mdir, "/", file, NULL); 03366 03367 xroot = _free(xroot); 03368 xmdir = _free(xmdir); 03369 xfile = _free(xfile); 03370 #if 0 03371 if (_debug) fprintf(stderr, "*** RGP result %s\n", result); 03372 #endif 03373 return result; 03374 } 03375 03376 /* =============================================================== */ 03377 03378 #if defined(DEBUG_MACROS) 03379 03380 #if defined(EVAL_MACROS) 03381 03382 const char *rpmMacrofiles = MACROFILES; 03383 03384 int 03385 main(int argc, char *argv[]) 03386 { 03387 int c; 03388 int errflg = 0; 03389 extern char *optarg; 03390 extern int optind; 03391 03392 while ((c = getopt(argc, argv, "f:")) != EOF ) { 03393 switch (c) { 03394 case 'f': 03395 rpmMacrofiles = optarg; 03396 break; 03397 case '?': 03398 default: 03399 errflg++; 03400 break; 03401 } 03402 } 03403 if (errflg || optind >= argc) { 03404 fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]); 03405 exit(1); 03406 } 03407 03408 rpmInitMacros(NULL, rpmMacrofiles); 03409 /* XXX getopt(3) also used for parametrized macros, expect scwewiness. */ 03410 for ( ; optind < argc; optind++) { 03411 const char *val; 03412 03413 val = rpmExpand(argv[optind], NULL); 03414 if (val) { 03415 fprintf(stdout, "%s:\t%s\n", argv[optind], val); 03416 val = _free(val); 03417 } 03418 } 03419 rpmFreeMacros(NULL); 03420 return 0; 03421 } 03422 03423 #else /* !EVAL_MACROS */ 03424 03425 const char *rpmMacrofiles = "../macros:./testmacros"; 03426 const char *testfile = "./test"; 03427 03428 int 03429 main(int argc, char *argv[]) 03430 { 03431 size_t bufn = _macro_BUFSIZ; 03432 char *buf = alloca(bufn); 03433 FILE *fp; 03434 int x; 03435 03436 rpmInitMacros(NULL, rpmMacrofiles); 03437 03438 if ((fp = fopen(testfile, "r")) != NULL) { 03439 while(rdcl(buf, bufn, fp)) { 03440 x = expandMacros(NULL, NULL, buf, bufn); 03441 fprintf(stderr, "%d->%s\n", x, buf); 03442 memset(buf, 0, bufn); 03443 } 03444 fclose(fp); 03445 } 03446 03447 while(rdcl(buf, bufn, stdin)) { 03448 x = expandMacros(NULL, NULL, buf, bufn); 03449 fprintf(stderr, "%d->%s\n <-\n", x, buf); 03450 memset(buf, 0, bufn); 03451 } 03452 rpmFreeMacros(NULL); 03453 03454 return 0; 03455 } 03456 #endif /* EVAL_MACROS */ 03457 #endif /* DEBUG_MACROS */
1.7.5.1