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