rpm 5.3.7
|
00001 00004 #include "system.h" 00005 00006 #include <rpmiotypes.h> 00007 #include <rpmio.h> 00008 #include <rpmlog.h> 00009 00010 #define _MIRE_INTERNAL 00011 #include <mire.h> 00012 00013 #include "debug.h" 00014 00015 /*@access regex_t @*/ 00016 00017 /*@unchecked@*/ 00018 int _mire_debug = 0; 00019 00020 /*@unchecked@*/ 00021 const unsigned char * _mirePCREtables = NULL; 00022 00023 /*@unchecked@*/ 00024 mireEL_t _mireEL = EL_LF; 00025 00026 /*@unchecked@*/ 00027 int _mireSTRINGoptions = 0; 00028 00029 /*@unchecked@*/ 00030 int _mireGLOBoptions = FNM_EXTMATCH | FNM_PATHNAME | FNM_PERIOD; 00031 00032 /*@unchecked@*/ 00033 int _mireREGEXoptions = REG_EXTENDED | REG_NEWLINE; 00034 00035 /*@unchecked@*/ 00036 int _mirePCREoptions = 0; 00037 00038 int mireClean(miRE mire) 00039 { 00040 if (mire == NULL) return 0; 00041 mire->pattern = _free(mire->pattern); 00042 if (mire->mode == RPMMIRE_REGEX) { 00043 if (mire->preg != NULL) { 00044 regfree(mire->preg); 00045 /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */ 00046 mire->preg = _free(mire->preg); 00047 /*@=voidabstract =usereleased @*/ 00048 } 00049 } 00050 if (mire->mode == RPMMIRE_PCRE) { /* TODO: (*pcre_free)(_p) override */ 00051 mire->pcre = _free(mire->pcre); 00052 mire->hints = _free(mire->hints); 00053 } 00054 mire->errmsg = NULL; 00055 mire->erroff = 0; 00056 mire->errcode = 0; 00057 mire->fnflags = 0; 00058 mire->cflags = 0; 00059 mire->eflags = 0; 00060 mire->coptions = 0; 00061 mire->eoptions = 0; 00062 mire->notmatch = 0; 00063 /*@-modfilesys@*/ 00064 if (_mire_debug) 00065 fprintf(stderr, "<-- mireClean(%p)\n", mire); 00066 /*@=modfilesys@*/ 00067 return 0; 00068 } 00069 00070 static void mireFini(void * _mire) 00071 /*@modifies _mire @*/ 00072 { 00073 miRE mire = _mire; 00074 (void) mireClean(mire); 00075 } 00076 00077 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00078 rpmioPool _mirePool; 00079 00080 miRE mireGetPool(rpmioPool pool) 00081 { 00082 miRE mire; 00083 00084 if (_mirePool == NULL) { 00085 _mirePool = rpmioNewPool("mire", sizeof(*mire), -1, _mire_debug, 00086 NULL, NULL, mireFini); 00087 pool = _mirePool; 00088 } 00089 mire = (miRE) rpmioGetPool(pool, sizeof(*mire)); 00090 memset(((char *)mire)+sizeof(mire->_item), 0, sizeof(*mire)-sizeof(mire->_item)); 00091 return mire; 00092 } 00093 00094 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */ 00095 void * mireFreeAll(miRE mire, int nmire) 00096 { 00097 if (mire != NULL) { 00098 while (--nmire > 0) 00099 (void) mireClean(mire + nmire); 00100 /* XXX rpmgrep doesn't use mire pools yet. retrofit a fix. */ 00101 if (mire->_item.use != NULL && mire->_item.pool != NULL) 00102 mire = (miRE)rpmioFreePoolItem((rpmioItem)mire, __FUNCTION__, __FILE__, __LINE__); 00103 else 00104 mire = _free(mire); 00105 } 00106 return NULL; 00107 } 00108 /*@=onlytrans@*/ 00109 00110 miRE mireNew(rpmMireMode mode, int tag) 00111 { 00112 miRE mire = mireGetPool(_mirePool); 00113 mire->mode = mode; 00114 mire->tag = tag; 00115 return mireLink(mire); 00116 } 00117 00118 int mireSetCOptions(miRE mire, rpmMireMode mode, int tag, int options, 00119 const unsigned char * table) 00120 { 00121 int rc = 0; 00122 mire->mode = mode; 00123 mire->tag = tag; 00124 switch (mire->mode) { 00125 case RPMMIRE_DEFAULT: 00126 break; 00127 case RPMMIRE_STRCMP: 00128 /* XXX strcasecmp? */ 00129 break; 00130 case RPMMIRE_GLOB: 00131 if (options == 0) 00132 options = _mireGLOBoptions; 00133 mire->fnflags = options; 00134 break; 00135 case RPMMIRE_REGEX: 00136 if (options == 0) 00137 options = _mireREGEXoptions; 00138 mire->cflags = options; 00139 break; 00140 case RPMMIRE_PCRE: 00141 if (options == 0) 00142 options = _mirePCREoptions; 00143 /* XXX check default compile options? */ 00144 mire->coptions = options; 00145 /*@-assignexpose -temptrans @*/ 00146 mire->table = table; 00147 /*@=assignexpose =temptrans @*/ 00148 break; 00149 } 00150 return rc; 00151 } 00152 00153 int mireSetEOptions(miRE mire, int * offsets, int noffsets) 00154 { 00155 int rc = 0; 00156 if (mire->mode == RPMMIRE_PCRE) { 00157 mire->startoff = 0; 00158 mire->eoptions = 0; 00159 /*@-assignexpose@*/ 00160 mire->offsets = offsets; 00161 /*@=assignexpose@*/ 00162 mire->noffsets = noffsets; 00163 } else 00164 if (mire->mode == RPMMIRE_REGEX) { 00165 mire->startoff = 0; 00166 mire->eoptions = 0; 00167 /*@-assignexpose@*/ 00168 mire->offsets = offsets; 00169 /*@=assignexpose@*/ 00170 mire->noffsets = noffsets; 00171 } else 00172 rc = -1; 00173 00174 return rc; 00175 } 00176 00177 int mireSetGOptions(const char * newline, int caseless, int multiline, int utf8) 00178 { 00179 int rc = 0; 00180 00181 if (caseless) { 00182 #if defined(PCRE_CASELESS) 00183 _mirePCREoptions |= PCRE_CASELESS; 00184 #endif 00185 _mireREGEXoptions |= REG_ICASE; 00186 #if defined(FNM_CASEFOLD) 00187 _mireGLOBoptions |= FNM_CASEFOLD; 00188 #endif 00189 } else { 00190 #if defined(PCRE_CASELESS) 00191 _mirePCREoptions &= ~PCRE_CASELESS; 00192 #endif 00193 _mireREGEXoptions &= ~REG_ICASE; 00194 #if defined(FNM_CASEFOLD) 00195 _mireGLOBoptions &= ~FNM_CASEFOLD; 00196 #endif 00197 } 00198 00199 if (multiline) { 00200 #if defined(PCRE_MULTILINE) 00201 _mirePCREoptions |= PCRE_MULTILINE|PCRE_FIRSTLINE; 00202 #endif 00203 } else { 00204 #if defined(PCRE_MULTILINE) 00205 _mirePCREoptions &= ~(PCRE_MULTILINE|PCRE_FIRSTLINE); 00206 #endif 00207 } 00208 00209 if (utf8) { 00210 #if defined(PCRE_UTF8) 00211 _mirePCREoptions |= PCRE_UTF8; 00212 #endif 00213 } else { 00214 #if defined(PCRE_UTF8) 00215 _mirePCREoptions &= ~PCRE_UTF8; 00216 #endif 00217 } 00218 00219 /* 00220 * Set the default line ending value from the default in the PCRE library; 00221 * "lf", "cr", "crlf", and "any" are supported. Anything else is treated 00222 * as "lf". 00223 */ 00224 if (newline == NULL) { 00225 int val = 0; 00226 #if defined(PCRE_CONFIG_NEWLINE) 00227 /*@-modunconnomods@*/ 00228 (void)pcre_config(PCRE_CONFIG_NEWLINE, &val); 00229 /*@=modunconnomods@*/ 00230 #endif 00231 switch (val) { 00232 default: newline = "lf"; break; 00233 case '\r': newline = "cr"; break; 00234 /*@-shiftimplementation@*/ 00235 case ('\r' << 8) | '\n': newline = "crlf"; break; 00236 /*@=shiftimplementation@*/ 00237 case -1: newline = "any"; break; 00238 case -2: newline = "anycrlf"; break; 00239 } 00240 } 00241 00242 /* Interpret the newline type; the default settings are Unix-like. */ 00243 if (!strcasecmp(newline, "cr")) { 00244 #if defined(PCRE_NEWLINE_CR) 00245 _mirePCREoptions |= PCRE_NEWLINE_CR; 00246 #endif 00247 _mireEL = EL_CR; 00248 } else if (!strcasecmp(newline, "lf")) { 00249 #if defined(PCRE_NEWLINE_LF) 00250 _mirePCREoptions |= PCRE_NEWLINE_LF; 00251 #endif 00252 _mireEL = EL_LF; 00253 } else if (!strcasecmp(newline, "crlf")) { 00254 #if defined(PCRE_NEWLINE_CRLF) 00255 _mirePCREoptions |= PCRE_NEWLINE_CRLF; 00256 #endif 00257 _mireEL = EL_CRLF; 00258 } else if (!strcasecmp(newline, "any")) { 00259 #if defined(PCRE_NEWLINE_ANY) 00260 _mirePCREoptions |= PCRE_NEWLINE_ANY; 00261 #endif 00262 _mireEL = EL_ANY; 00263 } else if (!strcasecmp(newline, "anycrlf")) { 00264 #if defined(PCRE_NEWLINE_ANYCRLF) 00265 _mirePCREoptions |= PCRE_NEWLINE_ANYCRLF; 00266 #endif 00267 _mireEL = EL_ANYCRLF; 00268 } else { 00269 rc = -1; 00270 } 00271 00272 return rc; 00273 } 00274 00275 int mireSetLocale(/*@unused@*/ miRE mire, const char * locale) 00276 { 00277 const char * locale_from = NULL; 00278 int rc = -1; /* assume failure */ 00279 00280 /* XXX TODO: --locale jiggery-pokery should be done env LC_ALL=C rpmgrep */ 00281 if (locale == NULL) { 00282 if (locale) 00283 locale_from = "--locale"; 00284 else { 00285 /* 00286 * If a locale has not been provided as an option, see if the 00287 * LC_CTYPE or LC_ALL environment variable is set, and if so, 00288 * use it. 00289 */ 00290 /*@-dependenttrans -observertrans@*/ 00291 if ((locale = getenv("LC_ALL")) != NULL) 00292 locale_from = "LC_ALL"; 00293 else if ((locale = getenv("LC_CTYPE")) != NULL) 00294 locale_from = "LC_CTYPE"; 00295 /*@=dependenttrans =observertrans@*/ 00296 if (locale) 00297 locale = xstrdup(locale); 00298 } 00299 } 00300 00301 /* 00302 * If a locale has been provided, set it, and generate the tables PCRE 00303 * needs. Otherwise, _mirePCREtables == NULL, which uses default tables. 00304 */ 00305 if (locale != NULL) { 00306 const char * olocale = setlocale(LC_CTYPE, locale); 00307 if (olocale == NULL) { 00308 /*@-modfilesys@*/ 00309 fprintf(stderr, 00310 _("%s: Failed to set locale %s (obtained from %s)\n"), 00311 __progname, locale, locale_from); 00312 /*@=modfilesys@*/ 00313 goto exit; 00314 } 00315 #if defined(WITH_PCRE) 00316 /*@-evalorderuncon -onlytrans @*/ 00317 _mirePCREtables = pcre_maketables(); 00318 /*@=evalorderuncon =onlytrans @*/ 00319 #ifdef NOTYET 00320 if (setlocale(LC_CTYPE, olocale) == NULL) 00321 goto exit; 00322 #endif 00323 #endif 00324 } 00325 rc = 0; 00326 00327 exit: 00328 return rc; 00329 } 00330 00331 int mireRegcomp(miRE mire, const char * pattern) 00332 { 00333 int rc = 0; 00334 00335 mire->pattern = xstrdup(pattern); 00336 00337 switch (mire->mode) { 00338 case RPMMIRE_STRCMP: 00339 break; 00340 case RPMMIRE_PCRE: 00341 #ifdef WITH_PCRE 00342 mire->errcode = 0; 00343 mire->errmsg = NULL; 00344 mire->erroff = 0; 00345 mire->pcre = pcre_compile2(mire->pattern, mire->coptions, 00346 &mire->errcode, &mire->errmsg, &mire->erroff, mire->table); 00347 if (mire->pcre == NULL) { 00348 if (_mire_debug) 00349 rpmlog(RPMLOG_ERR, 00350 _("pcre_compile2 failed: %s(%d) at offset %d of \"%s\"\n"), 00351 mire->errmsg, mire->errcode, mire->erroff, mire->pattern); 00352 rc = -1; 00353 goto exit; /* XXX HACK: rpmgrep is not expecting mireClean. */ 00354 } 00355 #else 00356 rc = -99; 00357 #endif 00358 break; 00359 case RPMMIRE_DEFAULT: 00360 case RPMMIRE_REGEX: 00361 mire->preg = xcalloc(1, sizeof(*mire->preg)); 00362 if (mire->cflags == 0) 00363 mire->cflags = _mireREGEXoptions; 00364 rc = regcomp(mire->preg, mire->pattern, mire->cflags); 00365 if (rc) { 00366 char msg[256]; 00367 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1); 00368 msg[sizeof(msg)-1] = '\0'; 00369 rpmlog(RPMLOG_ERR, _("%s: regcomp failed: %s\n"), 00370 mire->pattern, msg); 00371 } 00372 break; 00373 case RPMMIRE_GLOB: 00374 if (mire->fnflags == 0) 00375 mire->fnflags = _mireGLOBoptions; 00376 break; 00377 default: 00378 rc = -1; 00379 break; 00380 } 00381 00382 if (rc) 00383 (void) mireClean(mire); 00384 00385 #ifdef WITH_PCRE 00386 exit: 00387 #endif 00388 /*@-modfilesys@*/ 00389 if (_mire_debug) 00390 fprintf(stderr, "<-- mireRegcomp(%p, \"%s\") rc %d\n", mire, pattern, rc); 00391 /*@=modfilesys@*/ 00392 return rc; 00393 } 00394 00395 int mireRegexec(miRE mire, const char * val, size_t vallen) 00396 { 00397 int rc = -1; /* assume failure */ 00398 00399 switch (mire->mode) { 00400 case RPMMIRE_STRCMP: 00401 if (mire->pattern == NULL) 00402 break; 00403 if (vallen == 0) 00404 vallen = strlen(val); 00405 /* XXX strcasecmp? */ 00406 rc = strncmp(mire->pattern, val, vallen); 00407 if (rc) rc = -1; 00408 break; 00409 case RPMMIRE_DEFAULT: 00410 case RPMMIRE_REGEX: 00411 if (mire->preg == NULL) 00412 break; 00413 /* XXX rpmgrep: ensure that the string is NUL terminated. */ 00414 if (vallen > 0) { 00415 if (val[vallen] != '\0') { 00416 char * t = strncpy(alloca(vallen+1), val, vallen); 00417 t[vallen] = '\0'; 00418 val = t; 00419 } 00420 } else 00421 if (vallen == 0) 00422 vallen = strlen(val); 00423 /*@-nullpass@*/ 00424 /* XXX HACK: PCRE returns 2/3 of array, POSIX dimensions regmatch_t. */ 00425 rc = regexec(mire->preg, val, 00426 mire->noffsets/3, (regmatch_t *)mire->offsets, mire->eflags); 00427 /*@=nullpass@*/ 00428 switch (rc) { 00429 case 0: rc = 0; /*@innerbreak@*/ break; 00430 case REG_NOMATCH: rc = -1;/*@innerbreak@*/ break; 00431 default: 00432 { char msg[256]; 00433 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1); 00434 msg[sizeof(msg)-1] = '\0'; 00435 rpmlog(RPMLOG_ERR, _("%s: regexec failed: %s(%d)\n"), 00436 mire->pattern, msg, rc); 00437 if (rc < 0) rc -= 1; /* XXX ensure -1 is nomatch. */ 00438 if (rc > 0) rc = -(rc+1); /* XXX ensure errors are negative. */ 00439 } /*@innerbreak@*/ break; 00440 } 00441 break; 00442 case RPMMIRE_PCRE: 00443 #ifdef WITH_PCRE 00444 if (mire->pcre == NULL) 00445 break; 00446 if (vallen == 0) 00447 vallen = strlen(val); 00448 rc = pcre_exec(mire->pcre, mire->hints, val, (int)vallen, mire->startoff, 00449 mire->eoptions, mire->offsets, mire->noffsets); 00450 switch (rc) { 00451 case 0: rc = 0; /*@innerbreak@*/ break; 00452 case PCRE_ERROR_NOMATCH: rc = -1;/*@innerbreak@*/ break; 00453 default: 00454 if (_mire_debug && rc < 0) 00455 rpmlog(RPMLOG_ERR, _("pcre_exec failed: return %d\n"), rc); 00456 /*@innerbreak@*/ break; 00457 } 00458 #else 00459 rc = -99; 00460 #endif 00461 break; 00462 case RPMMIRE_GLOB: 00463 if (mire->pattern == NULL) 00464 break; 00465 rc = fnmatch(mire->pattern, val, mire->fnflags); 00466 switch (rc) { 00467 case 0: rc = 0; /*@innerbreak@*/ break; 00468 case FNM_NOMATCH: rc = -1;/*@innerbreak@*/ break; 00469 default: 00470 if (_mire_debug) 00471 rpmlog(RPMLOG_ERR, _("fnmatch failed: return %d\n"), rc); 00472 if (rc < 0) rc -= 1; /* XXX ensure -1 is nomatch. */ 00473 if (rc > 0) rc = -(rc+1); /* XXX ensure errors are negative. */ 00474 /*@innerbreak@*/ break; 00475 } 00476 break; 00477 default: 00478 break; 00479 } 00480 00481 /*@-modfilesys@*/ 00482 if (_mire_debug) 00483 fprintf(stderr, "<-- mireRegexec(%p, %p[%u]) rc %d mode %d \"%.*s\"\n", mire, val, (unsigned)vallen, rc, mire->mode, (int)(vallen < 20 ? vallen : 20), val); 00484 /*@=modfilesys@*/ 00485 return rc; 00486 } 00487 00488 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */ 00489 int mireAppend(rpmMireMode mode, int tag, const char * pattern, 00490 const unsigned char * table, miRE * mirep, int * nmirep) 00491 { 00492 miRE mire; 00493 int xx; 00494 00495 if (*mirep == NULL) { 00496 (*mirep) = mireGetPool(_mirePool); 00497 mire = (*mirep); 00498 } else { 00499 void *use = (*mirep)->_item.use; 00500 void *pool = (*mirep)->_item.pool; 00501 00502 /* XXX only the 1st element in the array has a usage mutex. */ 00503 (*mirep) = xrealloc((*mirep), ((*nmirep) + 1) * sizeof(*mire)); 00504 mire = (*mirep) + (*nmirep); 00505 memset(mire, 0, sizeof(*mire)); 00506 /* XXX ensure no segfault, copy the use/pool from 1st item. */ 00507 /*@-assignexpose@*/ 00508 mire->_item.use = use; 00509 mire->_item.pool = pool; 00510 /*@=assignexpose@*/ 00511 } 00512 00513 (*nmirep)++; 00514 xx = mireSetCOptions(mire, mode, tag, 0, table); 00515 /*@-usereleased@*/ 00516 return mireRegcomp(mire, pattern); 00517 /*@=usereleased@*/ 00518 } 00519 /*@=onlytrans@*/ 00520 00521 int mireLoadPatterns(rpmMireMode mode, int tag, const char ** patterns, 00522 const unsigned char * table, miRE * mirep, int * nmirep) 00523 { 00524 const char *pattern; 00525 int rc = -1; /* assume failure */ 00526 00527 if (patterns != NULL) /* note rc=0 return with no patterns to load. */ 00528 while ((pattern = *patterns++) != NULL) { 00529 /* XXX pcre_options is not used. should it be? */ 00530 /* XXX more realloc's than necessary. */ 00531 int xx = mireAppend(mode, tag, pattern, table, mirep, nmirep); 00532 if (xx) { 00533 rc = xx; 00534 goto exit; 00535 } 00536 } 00537 rc = 0; 00538 00539 exit: 00540 return rc; 00541 } 00542 00543 int mireApply(miRE mire, int nmire, const char *s, size_t slen, int rc) 00544 { 00545 int i; 00546 00547 if (slen == 0) 00548 slen = strlen(s); 00549 00550 if (mire) 00551 for (i = 0; i < nmire; mire++, i++) { 00552 int xx = mireRegexec(mire, s, slen); 00553 00554 /* Check if excluding or including condition applies. */ 00555 if (rc < 0 && xx < 0) 00556 continue; /* excluding: continue on negative matches. */ 00557 if (rc > 0 && xx >= 0) 00558 continue; /* including: continue on positive matches. */ 00559 /* Save 1st found termination condition and exit. */ 00560 rc = xx; 00561 break; 00562 } 00563 return rc; 00564 } 00565 00566 int mireStudy(miRE mire, int nmires) 00567 { 00568 int rc = -1; /* assume failure */ 00569 int j; 00570 00571 /* Study the PCRE regex's, as we will be running them many times */ 00572 if (mire) /* note rc=0 return with no mire's. */ 00573 for (j = 0; j < nmires; mire++, j++) { 00574 if (mire->mode != RPMMIRE_PCRE) 00575 continue; 00576 #if defined(WITH_PCRE) 00577 { const char * error; 00578 mire->hints = pcre_study(mire->pcre, 0, &error); 00579 if (error != NULL) { 00580 char s[32]; 00581 if (nmires == 1) s[0] = '\0'; else sprintf(s, _(" number %d"), j); 00582 rpmlog(RPMLOG_ERR, _("%s: Error while studying regex%s: %s\n"), 00583 __progname, s, error); 00584 goto exit; 00585 } 00586 } 00587 #endif 00588 } 00589 rc = 0; 00590 00591 #if defined(WITH_PCRE) 00592 exit: 00593 #endif 00594 return rc; 00595 }