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