- Main Page
- Related Pages
- Modules
- Data Structures
- Files

# lib/rpmsx.c

Go to the documentation of this file.

    00001
    00004 #include "system.h"
    00005
    00006 #include <rpmlib.h>
    00007 #include <rpmio.h>
    00008 #include <rpmmacro.h>   /* for rpmGetPath() */
    00009
    00010 #define _RPMSX_INTERNAL
    00011 #include "rpmsx.h"
    00012
    00013 #include "debug.h"
    00014
    00015 /*@access regex_t @*/
    00016
    00017 /*@unchecked@*/
    00018 int _rpmsx_debug = 0;
    00019
    00024 static void rpmsxSort(rpmsx sx)
    00025        /*@modifies sx @*/
    00026 {
    00027     rpmsxp sxp;
    00028     int i, j;
    00029
    00030     /* Stable sort for policy regex's and paths. */
    00031     sxp = xmalloc(sizeof(*sxp) * sx->Count);
    00032
    00033     /* Regex patterns first ... */
    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     /* ... then file paths. */
    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 /*@-compdef@*/  /* XXX *(sx->sxp) annotation */
    00053     return;
    00054 /*@=compdef@*/
    00055 }
    00056
    00057 /* Determine if the regular expression specification has any meta characters. */
    00058 static void rpmsxpHasMetaChars(rpmsxp sxp)
    00059         /*@modifies sxp @*/
    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     /* Look at each character in the RE specification string for a
    00068      * meta character. Return when any meta character reached. */
    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             /*@notreached@*/ /*@switchbreak@*/ break;
    00084         case '\\':              /* skip the next character */
    00085             s++;
    00086             /*@switchbreak@*/ break;
    00087         default:
    00088             /*@switchbreak@*/ break;
    00089
    00090         }
    00091         s++;
    00092     }
    00093     return;
    00094 }
    00095
    00100 static size_t rpmsxsPStem(const char * const buf)
    00101         /*@*/
    00102 {
    00103     /*@observer@*/
    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         /*@modifies sx, *bpp @*/
    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 /*@i@*/    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(/*@null@*/ const rpmsx sx, const char ** bpp)
    00184         /*@modifies *bpp @*/
    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 /*@i@*/ 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 /*@-modfilesys@*/
    00207 if (_rpmsx_debug && msg != NULL)
    00208 fprintf(stderr, "--> sx %p -- %d %s at %s:%u\n", sx, sx->nrefs, msg, fn, ln);
    00209 /*@=modfilesys@*/
    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 /*@-modfilesys@*/
    00220 if (_rpmsx_debug && msg != NULL)
    00221 fprintf(stderr, "--> sx %p ++ %d %s at %s:%u\n", sx, sx->nrefs, msg, fn, ln);
    00222 /*@=modfilesys@*/
    00223
    00224     /*@-refcounttrans@*/ return sx; /*@=refcounttrans@*/
    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 /*@-modfilesys@*/
    00238 if (_rpmsx_debug < 0)
    00239 fprintf(stderr, "*** sx %p\t%s[%d]\n", sx, __func__, sx->Count);
    00240 /*@=modfilesys@*/
    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 /*@i@*/ regfree(sxp->preg);
    00249 /*@i@*/ 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     /*@-refcounttrans -usereleased@*/
    00262     memset(sx, 0, sizeof(*sx));         /* XXX trash and burn */
    00263     sx = _free(sx);
    00264     /*@=refcounttrans =usereleased@*/
    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             /* Check if same RE string */
    00289             if (strcmp(sxpj->pattern, sxpi->pattern))
    00290                 /*@innercontinue@*/ continue;
    00291             if (sxpj->fmode && sxpi->fmode && sxpj->fmode != sxpi->fmode)
    00292                 /*@innercontinue@*/ continue;
    00293
    00294             /* Same RE string found */
    00295             if (strcmp(sxpj->context, sxpi->context)) {
    00296                 /* If different contexts, give warning */
    00297 /*@-modfilesys@*/
    00298                 fprintf(stderr,
    00299                 "ERROR: Multiple different specifications for %s  (%s and %s).\n",
    00300                         sxpi->pattern, sxpj->context, sxpi->context);
    00301 /*@=modfilesys@*/
    00302                 rc = -1;
    00303             } else {
    00304                 /* If same contexts give warning */
    00305 /*@-modfilesys@*/
    00306                 fprintf(stderr,
    00307                 "WARNING: Multiple same specifications for %s.\n",
    00308                         sxpi->pattern);
    00309 /*@=modfilesys@*/
    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      * Perform two passes over the specification file.
    00350      * The first pass counts the number of specifications and
    00351      * performs simple validation of the input.  At the end
    00352      * of the first pass, the spec array is allocated.
    00353      * The second pass performs detailed validation of the input
    00354      * and fills in the spec array.
    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                 /*@innercontinue@*/ continue;
    00372             }
    00373             buf[len - 1] = 0;
    00374             bp = buf;
    00375             while (isspace(*bp))
    00376                 bp++;
    00377             /* Skip comment lines and empty lines. */
    00378             if (*bp == '#' || *bp == 0)
    00379                 /*@innercontinue@*/ continue;
    00380 /*@-formatcode@*/
    00381             items = sscanf(buf, "%as %as %as", &regex, &type, &context);
    00382 /*@=formatcode@*/
    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                 /*@innercontinue@*/ continue;
    00391             } else if (items == 2) {
    00392                 /* The type field is optional. */
    00393                 free(context);
    00394                 context = type;
    00395                 type = 0;
    00396             }
    00397
    00398             /* On pass 2, compile and store the specification. */
    00399             if (pass == 1) {
    00400                 const char * reg_buf = regex;
    00401                 sxp->fstem = rpmsxAdd(sx, &reg_buf);
    00402                 sxp->pattern = regex;
    00403
    00404                 /* Anchor the regular expression. */
    00405                 len = strlen(reg_buf);
    00406                 anchored_regex = xmalloc(len + 3);
    00407                 sprintf(anchored_regex, "^%s$", reg_buf);
    00408
    00409                 /* Compile the regular expression. */
    00410 /*@i@*/         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                 /* Convert the type string to a mode format */
    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;   /*@switchbreak@*/ break;
    00440                 case 'c':       sxp->fmode = S_IFCHR;   /*@switchbreak@*/ break;
    00441                 case 'd':       sxp->fmode = S_IFDIR;   /*@switchbreak@*/ break;
    00442                 case 'p':       sxp->fmode = S_IFIFO;   /*@switchbreak@*/ break;
    00443                 case 'l':       sxp->fmode = S_IFLNK;   /*@switchbreak@*/ break;
    00444 /*@i@*/         case 's':       sxp->fmode = S_IFSOCK;  /*@switchbreak@*/ break;
    00445                 case '-':       sxp->fmode = S_IFREG;   /*@switchbreak@*/ 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                     /*@switchbreak@*/ 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                 /* Determine if specification has
    00468                  * any meta characters in the RE */
    00469                 rpmsxpHasMetaChars(sxp);
    00470                 sxp++;
    00471             }
    00472
    00473             sx->Count++;
    00474             if (pass == 0) {
    00475 /*@-kepttrans@*/
    00476                 free(regex);
    00477                 if (type)
    00478                     free(type);
    00479                 free(context);
    00480 /*@=kepttrans@*/
    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    /* Stable sort for policy specifications, patterns before paths. */
    00501     rpmsxSort(sx);
    00502
    00503     /* Verify no exact duplicates */
    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(/*@null@*/ rpmsx sx)
    00608         /*@modifies sx @*/
    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 /*@-modfilesys @*/
    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 /*@=modfilesys @*/
    00632 }
    00633
    00634     }
    00635
    00636     return i;
    00637 }
    00638
    00639 rpmsx rpmsxInit(/*@null@*/ rpmsx sx, int reverse)
    00640         /*@modifies sx @*/
    00641 {
    00642     if (sx != NULL) {
    00643         sx->reverse = reverse;
    00644         sx->i = (sx->reverse ? sx->Count : -1);
    00645     }
    00646     /*@-refcounttrans@*/
    00647     return sx;
    00648     /*@=refcounttrans@*/
    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 /*@-mods@*/
    00656     int fstem = rpmsxFind(sx, &myfn);
    00657 /*@=mods@*/
    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             /*@notreached@*/ /*@switchbreak@*/ break;
    00685         case 0:
    00686             fcontext = rpmsxContext(sx);
    00687             /*@switchbreak@*/ break;
    00688         default:
    00689           { static char errbuf[BUFSIZ + 1];
    00690             (void) regerror(ret, preg, errbuf, sizeof(errbuf)-1);
    00691 /*@-modfilesys -nullpass @*/
    00692             errbuf[sizeof(errbuf)-1] = '\0';
    00693             fprintf(stderr, "unable to match %s against %s:  %s\n",
    00694                 fn, rpmsxPattern(sx), errbuf);
    00695 /*@=modfilesys =nullpass @*/
    00696           } /*@switchbreak@*/ break;
    00697         }
    00698         break;
    00699     }
    00700
    00701     return fcontext;
    00702 }