00001
00004 #include "system.h"
00005
00006 #include <rpmlib.h>
00007 #include <rpmio.h>
00008 #include <rpmmacro.h>
00009
00010 #define _RPMSX_INTERNAL
00011 #include "rpmsx.h"
00012
00013 #include "debug.h"
00014
00015
00016
00017
00018 int _rpmsx_debug = 0;
00019
00024 static void rpmsxSort(rpmsx sx)
00025
00026 {
00027 rpmsxp sxp;
00028 int i, j;
00029
00030
00031 sxp = xmalloc(sizeof(*sxp) * sx->Count);
00032
00033
00034 j = 0;
00035 for (i = 0; i < sx->Count; i++) {
00036 if (!sx->sxp[i].hasMetaChars)
00037 continue;
00038 memcpy(sxp + j, sx->sxp + i, sizeof(*sxp));
00039 j++;
00040 }
00041
00042
00043 for (i = 0; i < sx->Count; i++) {
00044 if (sx->sxp[i].hasMetaChars)
00045 continue;
00046 memcpy(sxp + j, sx->sxp + i, sizeof(*sxp));
00047 j++;
00048 }
00049
00050 sx->sxp = _free(sx->sxp);
00051 sx->sxp = sxp;
00052
00053 return;
00054
00055 }
00056
00057
00058 static void rpmsxpHasMetaChars(rpmsxp sxp)
00059
00060 {
00061 const char * s = sxp->pattern;
00062 size_t ns = strlen(s);
00063 const char * se = s + ns;
00064
00065 sxp->hasMetaChars = 0;
00066
00067
00068
00069 while (s != se) {
00070 switch(*s) {
00071 case '.':
00072 case '^':
00073 case '$':
00074 case '?':
00075 case '*':
00076 case '+':
00077 case '|':
00078 case '[':
00079 case '(':
00080 case '{':
00081 sxp->hasMetaChars = 1;
00082 return;
00083 break;
00084 case '\\':
00085 s++;
00086 break;
00087 default:
00088 break;
00089
00090 }
00091 s++;
00092 }
00093 return;
00094 }
00095
00100 static size_t rpmsxsPStem(const char * const buf)
00101
00102 {
00103
00104 static const char * const regex_chars = ".^$?*+|[({";
00105 const char * tmp = strchr(buf, '/');
00106 const char * ind;
00107
00108 if (!tmp)
00109 return 0;
00110
00111 for (ind = buf; ind < tmp; ind++) {
00112 if (strchr(regex_chars, (int)*ind))
00113 return 0;
00114 }
00115 return tmp - buf;
00116 }
00117
00122 static size_t rpmsxsFStem(const char * const buf)
00123
00124 {
00125 const char * tmp = strchr(buf + 1, '/');
00126
00127 if (!tmp)
00128 return 0;
00129 return tmp - buf;
00130 }
00131
00139 static int rpmsxAdd(rpmsx sx, const char ** bpp)
00140
00141 {
00142 size_t stem_len = rpmsxsPStem(*bpp);
00143 rpmsxs sxs;
00144 int i;
00145
00146 if (!stem_len)
00147 return -1;
00148 for (i = 0; i < sx->nsxs; i++) {
00149 sxs = sx->sxs + i;
00150 if (stem_len != sxs->len)
00151 continue;
00152 if (strncmp(*bpp, sxs->stem, stem_len))
00153 continue;
00154 *bpp += stem_len;
00155 return i;
00156 }
00157
00158 if (sx->nsxs == sx->maxsxs) {
00159 sx->maxsxs = sx->maxsxs * 2 + 16;
00160 sx->sxs = xrealloc(sx->sxs, sizeof(*sx->sxs) * sx->maxsxs);
00161 }
00162 sxs = sx->sxs + sx->nsxs;
00163 sxs->len = stem_len;
00164 #ifdef HAVE_STRNDUP
00165 sxs->stem = strndup(*bpp, stem_len);
00166 #else
00167 sxs->stem = xmalloc(stem_len+1);
00168 strncpy((char *)sxs->stem, *bpp, stem_len);
00169 #endif
00170 sx->nsxs++;
00171 *bpp += stem_len;
00172 return sx->nsxs - 1;
00173 }
00174
00183 static int rpmsxFind( const rpmsx sx, const char ** bpp)
00184
00185 {
00186 size_t stem_len = rpmsxsFStem(*bpp);
00187 rpmsxs sxs;
00188 int i;
00189
00190 if (sx != NULL && stem_len > 0)
00191 for (i = 0; i < sx->nsxs; i++) {
00192 sxs = sx->sxs + i;
00193 if (stem_len != sxs->len)
00194 continue;
00195 if (strncmp(*bpp, sxs->stem, stem_len))
00196 continue;
00197 *bpp += stem_len;
00198 return i;
00199 }
00200 return -1;
00201 }
00202
00203 rpmsx XrpmsxUnlink(rpmsx sx, const char * msg, const char * fn, unsigned ln)
00204 {
00205 if (sx == NULL) return NULL;
00206
00207 if (_rpmsx_debug && msg != NULL)
00208 fprintf(stderr, "--> sx %p -- %d %s at %s:%u\n", sx, sx->nrefs, msg, fn, ln);
00209
00210 sx->nrefs--;
00211 return NULL;
00212 }
00213
00214 rpmsx XrpmsxLink(rpmsx sx, const char * msg, const char * fn, unsigned ln)
00215 {
00216 if (sx == NULL) return NULL;
00217 sx->nrefs++;
00218
00219
00220 if (_rpmsx_debug && msg != NULL)
00221 fprintf(stderr, "--> sx %p ++ %d %s at %s:%u\n", sx, sx->nrefs, msg, fn, ln);
00222
00223
00224 return sx;
00225 }
00226
00227 rpmsx rpmsxFree(rpmsx sx)
00228 {
00229 int i;
00230
00231 if (sx == NULL)
00232 return NULL;
00233
00234 if (sx->nrefs > 1)
00235 return rpmsxUnlink(sx, __func__);
00236
00237
00238 if (_rpmsx_debug < 0)
00239 fprintf(stderr, "*** sx %p\t%s[%d]\n", sx, __func__, sx->Count);
00240
00241
00242 if (sx->Count > 0)
00243 for (i = 0; i < sx->Count; i++) {
00244 rpmsxp sxp = sx->sxp + i;
00245 sxp->pattern = _free(sxp->pattern);
00246 sxp->type = _free(sxp->type);
00247 sxp->context = _free(sxp->context);
00248 regfree(sxp->preg);
00249 sxp->preg = _free(sxp->preg);
00250 }
00251 sx->sxp = _free(sx->sxp);
00252
00253 if (sx->nsxs > 0)
00254 for (i = 0; i < sx->nsxs; i++) {
00255 rpmsxs sxs = sx->sxs + i;
00256 sxs->stem = _free(sxs->stem);
00257 }
00258 sx->sxs = _free(sx->sxs);
00259
00260 (void) rpmsxUnlink(sx, __func__);
00261
00262 memset(sx, 0, sizeof(*sx));
00263 sx = _free(sx);
00264
00265 return NULL;
00266 }
00267
00277 static int rpmsxpCheckNoDupes(const rpmsx sx)
00278
00279 {
00280 int i, j;
00281 int rc = 0;
00282
00283 for (i = 0; i < sx->Count; i++) {
00284 rpmsxp sxpi = sx->sxp + i;
00285 for (j = i + 1; j < sx->Count; j++) {
00286 rpmsxp sxpj = sx->sxp + j;
00287
00288
00289 if (strcmp(sxpj->pattern, sxpi->pattern))
00290 continue;
00291 if (sxpj->fmode && sxpi->fmode && sxpj->fmode != sxpi->fmode)
00292 continue;
00293
00294
00295 if (strcmp(sxpj->context, sxpi->context)) {
00296
00297
00298 fprintf(stderr,
00299 "ERROR: Multiple different specifications for %s (%s and %s).\n",
00300 sxpi->pattern, sxpj->context, sxpi->context);
00301
00302 rc = -1;
00303 } else {
00304
00305
00306 fprintf(stderr,
00307 "WARNING: Multiple same specifications for %s.\n",
00308 sxpi->pattern);
00309
00310 }
00311 }
00312 }
00313 return rc;
00314 }
00315
00316 int rpmsxParse(rpmsx sx, const char * fn)
00317 {
00318 FILE * fp;
00319 char buf[BUFSIZ + 1];
00320 char * bp;
00321 char * regex;
00322 char * type;
00323 char * context;
00324 char * anchored_regex;
00325 int items;
00326 int len;
00327 int lineno;
00328 int pass;
00329 int regerr;
00330 int nerr = 0;
00331
00332 #define inc_err() nerr++
00333
00334 if (fn == NULL)
00335 fn = "%{?__file_context_path}";
00336
00337 { const char * myfn = rpmGetPath(fn, NULL);
00338
00339 if (myfn == NULL || *myfn == '\0'
00340 || (fp = fopen(myfn, "r")) == NULL)
00341 {
00342 myfn = _free(myfn);
00343 return -1;
00344 }
00345 myfn = _free(myfn);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 for (pass = 0; pass < 2; pass++) {
00357 rpmsxp sxp;
00358
00359 lineno = 0;
00360 sx->Count = 0;
00361 sxp = sx->sxp;
00362 while (fgets(buf, sizeof(buf)-1, fp)) {
00363 buf[sizeof(buf)-1] = '\0';
00364 lineno++;
00365 len = strlen(buf);
00366 if (buf[len - 1] != '\n') {
00367 fprintf(stderr,
00368 _("%s: no newline on line number %d (only read %s)\n"),
00369 fn, lineno, buf);
00370 inc_err();
00371 continue;
00372 }
00373 buf[len - 1] = 0;
00374 bp = buf;
00375 while (isspace(*bp))
00376 bp++;
00377
00378 if (*bp == '#' || *bp == 0)
00379 continue;
00380
00381 items = sscanf(buf, "%as %as %as", ®ex, &type, &context);
00382
00383 if (items < 2) {
00384 fprintf(stderr,
00385 _("%s: line number %d is missing fields (only read %s)\n"),
00386 fn, lineno, buf);
00387 inc_err();
00388 if (items == 1)
00389 free(regex);
00390 continue;
00391 } else if (items == 2) {
00392
00393 free(context);
00394 context = type;
00395 type = 0;
00396 }
00397
00398
00399 if (pass == 1) {
00400 const char * reg_buf = regex;
00401 sxp->fstem = rpmsxAdd(sx, ®_buf);
00402 sxp->pattern = regex;
00403
00404
00405 len = strlen(reg_buf);
00406 anchored_regex = xmalloc(len + 3);
00407 sprintf(anchored_regex, "^%s$", reg_buf);
00408
00409
00410 sxp->preg = xcalloc(1, sizeof(*sxp->preg));
00411 regerr = regcomp(sxp->preg, anchored_regex,
00412 REG_EXTENDED | REG_NOSUB);
00413 if (regerr < 0) {
00414 char errbuf[BUFSIZ + 1];
00415 (void) regerror(regerr, sxp->preg, errbuf, sizeof(errbuf)-1);
00416 errbuf[sizeof(errbuf)-1] = '\0';
00417 fprintf(stderr,
00418 _("%s: unable to compile regular expression %s on line number %d: %s\n"),
00419 fn, regex, lineno,
00420 errbuf);
00421 inc_err();
00422 }
00423 free(anchored_regex);
00424
00425
00426 sxp->type = type;
00427 sxp->fmode = 0;
00428 if (!type)
00429 goto skip_type;
00430 len = strlen(type);
00431 if (type[0] != '-' || len != 2) {
00432 fprintf(stderr,
00433 _("%s: invalid type specifier %s on line number %d\n"),
00434 fn, type, lineno);
00435 inc_err();
00436 goto skip_type;
00437 }
00438 switch (type[1]) {
00439 case 'b': sxp->fmode = S_IFBLK; break;
00440 case 'c': sxp->fmode = S_IFCHR; break;
00441 case 'd': sxp->fmode = S_IFDIR; break;
00442 case 'p': sxp->fmode = S_IFIFO; break;
00443 case 'l': sxp->fmode = S_IFLNK; break;
00444 case 's': sxp->fmode = S_IFSOCK; break;
00445 case '-': sxp->fmode = S_IFREG; break;
00446 default:
00447 fprintf(stderr,
00448 _("%s: invalid type specifier %s on line number %d\n"),
00449 fn, type, lineno);
00450 inc_err();
00451 break;
00452 }
00453
00454 skip_type:
00455
00456 sxp->context = context;
00457
00458 if (strcmp(context, "<<none>>")) {
00459 if (security_check_context(context) < 0 && errno != ENOENT) {
00460 fprintf(stderr,
00461 _("%s: invalid context %s on line number %d\n"),
00462 fn, context, lineno);
00463 inc_err();
00464 }
00465 }
00466
00467
00468
00469 rpmsxpHasMetaChars(sxp);
00470 sxp++;
00471 }
00472
00473 sx->Count++;
00474 if (pass == 0) {
00475
00476 free(regex);
00477 if (type)
00478 free(type);
00479 free(context);
00480
00481 }
00482 }
00483
00484 if (nerr) {
00485 (void) fclose(fp);
00486 return -1;
00487 }
00488
00489 if (pass == 0) {
00490 if (sx->Count == 0) {
00491 (void) fclose(fp);
00492 return 0;
00493 }
00494 sx->sxp = xcalloc(sx->Count, sizeof(*sx->sxp));
00495 rewind(fp);
00496 }
00497 }
00498 (void) fclose(fp);
00499
00500
00501 rpmsxSort(sx);
00502
00503
00504 if (rpmsxpCheckNoDupes(sx) != 0)
00505 return -1;
00506
00507 return 0;
00508
00509 }
00510
00511 rpmsx rpmsxNew(const char * fn)
00512 {
00513 rpmsx sx;
00514
00515 sx = xcalloc(1, sizeof(*sx));
00516 sx->sxp = NULL;
00517 sx->Count = 0;
00518 sx->i = -1;
00519 sx->sxs = NULL;
00520 sx->nsxs = 0;
00521 sx->maxsxs = 0;
00522 sx->reverse = 0;
00523
00524 (void) rpmsxLink(sx, __func__);
00525
00526 if (rpmsxParse(sx, fn) != 0)
00527 return rpmsxFree(sx);
00528
00529 return sx;
00530 }
00531
00532 int rpmsxCount(const rpmsx sx)
00533 {
00534 return (sx != NULL ? sx->Count : 0);
00535 }
00536
00537 int rpmsxIx(const rpmsx sx)
00538 {
00539 return (sx != NULL ? sx->i : -1);
00540 }
00541
00542 int rpmsxSetIx(rpmsx sx, int ix)
00543 {
00544 int i = -1;
00545
00546 if (sx != NULL) {
00547 i = sx->i;
00548 sx->i = ix;
00549 }
00550 return i;
00551 }
00552
00553 const char * rpmsxPattern(const rpmsx sx)
00554 {
00555 const char * pattern = NULL;
00556
00557 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00558 pattern = (sx->sxp + sx->i)->pattern;
00559 return pattern;
00560 }
00561
00562 const char * rpmsxType(const rpmsx sx)
00563 {
00564 const char * type = NULL;
00565
00566 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00567 type = (sx->sxp + sx->i)->type;
00568 return type;
00569 }
00570
00571 const char * rpmsxContext(const rpmsx sx)
00572 {
00573 const char * context = NULL;
00574
00575 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00576 context = (sx->sxp + sx->i)->context;
00577 return context;
00578 }
00579
00580 regex_t * rpmsxRE(const rpmsx sx)
00581 {
00582 regex_t * preg = NULL;
00583
00584 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00585 preg = (sx->sxp + sx->i)->preg;
00586 return preg;
00587 }
00588
00589 mode_t rpmsxFMode(const rpmsx sx)
00590 {
00591 mode_t fmode = 0;
00592
00593 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00594 fmode = (sx->sxp + sx->i)->fmode;
00595 return fmode;
00596 }
00597
00598 int rpmsxFStem(const rpmsx sx)
00599 {
00600 int fstem = -1;
00601
00602 if (sx != NULL && sx->i >= 0 && sx->i < sx->Count)
00603 fstem = (sx->sxp + sx->i)->fstem;
00604 return fstem;
00605 }
00606
00607 int rpmsxNext( rpmsx sx)
00608
00609 {
00610 int i = -1;
00611
00612 if (sx != NULL) {
00613 if (sx->reverse != 0) {
00614 i = --sx->i;
00615 if (sx->i < 0) {
00616 sx->i = sx->Count;
00617 i = -1;
00618 }
00619 } else {
00620 i = ++sx->i;
00621 if (sx->i >= sx->Count) {
00622 sx->i = -1;
00623 i = -1;
00624 }
00625 }
00626
00627
00628 if (_rpmsx_debug < 0 && i != -1) {
00629 rpmsxp sxp = sx->sxp + i;
00630 fprintf(stderr, "*** sx %p\t%s[%d]\t%s\t%s\n", sx, __func__, i, sxp->pattern, sxp->context);
00631
00632 }
00633
00634 }
00635
00636 return i;
00637 }
00638
00639 rpmsx rpmsxInit( rpmsx sx, int reverse)
00640
00641 {
00642 if (sx != NULL) {
00643 sx->reverse = reverse;
00644 sx->i = (sx->reverse ? sx->Count : -1);
00645 }
00646
00647 return sx;
00648
00649 }
00650
00651 const char * rpmsxFContext(rpmsx sx, const char * fn, mode_t fmode)
00652 {
00653 const char * fcontext = NULL;
00654 const char * myfn = fn;
00655
00656 int fstem = rpmsxFind(sx, &myfn);
00657
00658 int i;
00659
00660 sx = rpmsxInit(sx, 1);
00661 if (sx != NULL)
00662 while ((i = rpmsxNext(sx)) >= 0) {
00663 regex_t * preg;
00664 mode_t sxfmode;
00665 int sxfstem;
00666 int ret;
00667
00668 sxfstem = rpmsxFStem(sx);
00669 if (sxfstem != -1 && sxfstem != fstem)
00670 continue;
00671
00672 sxfmode = rpmsxFMode(sx);
00673 if (sxfmode && (fmode & S_IFMT) != sxfmode)
00674 continue;
00675
00676 preg = rpmsxRE(sx);
00677 if (preg == NULL)
00678 continue;
00679
00680 ret = regexec(preg, (sxfstem == -1 ? fn : myfn), 0, NULL, 0);
00681 switch (ret) {
00682 case REG_NOMATCH:
00683 continue;
00684 break;
00685 case 0:
00686 fcontext = rpmsxContext(sx);
00687 break;
00688 default:
00689 { static char errbuf[BUFSIZ + 1];
00690 (void) regerror(ret, preg, errbuf, sizeof(errbuf)-1);
00691
00692 errbuf[sizeof(errbuf)-1] = '\0';
00693 fprintf(stderr, "unable to match %s against %s: %s\n",
00694 fn, rpmsxPattern(sx), errbuf);
00695
00696 } break;
00697 }
00698 break;
00699 }
00700
00701 return fcontext;
00702 }