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