From a792c55ffae23f483121401fe4ca6724abc57bb5 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Wed, 29 Oct 2008 10:49:25 +0200 Subject: [PATCH] Start adding POSIX 1.e draft file capability support for real - Parse %caps() from spec filelists, making best-guess verification of capability string sanity by passing to cap_from_text() - The posix draft specifies capability export presentation through cap_copy_ext() which would be fine, except that we don't have support for arrays of binary data. So we simply store the textual representation of the capabilities in a string array which we do have. - Only add capability tag on packages which actually have capabilities to avoid unnecessary header bloat. - Add a new rpmlib() dependency for file capabilities, packages relying on file capabilities wont work correctly unless the capabilities are set. To be fully correct, support for on-filesystem file capabilities should be checked at runtime, as this depends on kernel versions and such... --- build/files.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/rpmds.c | 5 ++++ lib/rpmtag.h | 1 + 3 files changed, 97 insertions(+) diff --git a/build/files.c b/build/files.c index f4b2014..433bc15 100644 --- a/build/files.c +++ b/build/files.c @@ -68,6 +68,7 @@ typedef struct FileListRec_s { specdFlags specdFlags; /* which attributes have been explicitly specified. */ rpmVerifyFlags verifyFlags; char *langs; /* XXX locales separated with | */ + char *caps; } * FileListRec; /** @@ -116,6 +117,8 @@ typedef struct FileList_s { rpmVerifyFlags defVerifyFlags; int nLangs; char ** currentLangs; + int haveCaps; + char *currentCaps; ARGV_t docDirs; FileListRec fileList; @@ -757,6 +760,74 @@ exit: } /** + * Parse %caps from file manifest. + * @param buf current spec file line + * @param fl package file tree walk data + * @return RPMRC_OK on success + */ +static rpmRC parseForCaps(const char * buf, FileList fl) +{ + char *p, *pe, *q = NULL; + const char *name; + rpmRC rc = RPMRC_FAIL; + + if ((p = strstr(buf, (name = "%caps"))) == NULL) + return RPMRC_OK; + + /* Erase "%caps" token. */ + for (pe = p; (pe-p) < strlen(name); pe++) + *pe = ' '; + SKIPSPACE(pe); + if (*pe != '(') + return RPMRC_OK; + + /* Bracket %caps args */ + *pe++ = ' '; + for (p = pe; *pe && *pe != ')'; pe++) + {}; + + if (*pe == '\0') { + rpmlog(RPMLOG_ERR, _("Missing ')' in %s(%s\n"), name, p); + goto exit; + } + + /* Localize. Erase parsed string. */ + q = xmalloc((pe-p) + 1); + rstrlcpy(q, p, (pe-p) + 1); + while (p <= pe) + *p++ = ' '; + +#if WITH_CAP + { + char *captxt = NULL; + cap_t fcaps = cap_from_text(q); + if (fcaps == NULL) { + rpmlog(RPMLOG_ERR, _("Invalid capability: %s\n"), q); + goto exit; + } + /* run our string through cap_to_text() to get libcap presentation */ + captxt = cap_to_text(fcaps, NULL); + fl->currentCaps = xstrdup(captxt); + fl->haveCaps = 1; + cap_free(captxt); + cap_free(fcaps); + } +#else + rpmlog(RPMLOG_ERR, _("File capability support not built in\n")); + goto exit; +#endif + + rc = RPMRC_OK; + +exit: + free(q); + if (rc != RPMRC_OK) { + fl->processingFailed = 1; + } + + return rc; +} +/** */ static VFA_t virtualFileAttributes[] = { { "%dir", 0, 0 }, /* XXX why not RPMFILE_DIR? */ @@ -1112,6 +1183,10 @@ static void genCpioListAndHeader(FileList fl, } headerPutString(h, RPMTAG_FILELANGS, flp->langs); + + if (fl->haveCaps) { + headerPutString(h, RPMTAG_FILECAPS, flp->caps); + } buf[0] = '\0'; if (S_ISREG(flp->fl_mode)) @@ -1162,6 +1237,10 @@ static void genCpioListAndHeader(FileList fl, rpmlibNeedsFeature(h, "FileDigests", "4.4.90-1"); } + if (fl->haveCaps) { + rpmlibNeedsFeature(h, "FileCaps", "4.6.1-1"); + } + if (_addDotSlash) (void) rpmlibNeedsFeature(h, "PayloadFilesHavePrefix", "4.0-1"); @@ -1274,6 +1353,7 @@ static FileListRec freeFileList(FileListRec fileList, fileList[count].diskPath = _free(fileList[count].diskPath); fileList[count].cpioPath = _free(fileList[count].cpioPath); fileList[count].langs = _free(fileList[count].langs); + fileList[count].caps = _free(fileList[count].caps); } fileList = _free(fileList); return NULL; @@ -1435,6 +1515,12 @@ static rpmRC addFile(FileList fl, const char * diskPath, flp->langs = xstrdup(""); } + if (fl->currentCaps) { + flp->caps = fl->currentCaps; + } else { + flp->caps = xstrdup(""); + } + flp->flags = fl->currentFlags; flp->specdFlags = fl->currentSpecdFlags; flp->verifyFlags = fl->currentVerifyFlags; @@ -1764,6 +1850,8 @@ static rpmRC processPackageFiles(rpmSpec spec, Package pkg, fl.defVerifyFlags = RPMVERIFY_ALL; fl.nLangs = 0; fl.currentLangs = NULL; + fl.haveCaps = 0; + fl.currentCaps = NULL; fl.currentSpecdFlags = 0; fl.defSpecdFlags = 0; @@ -1813,6 +1901,7 @@ static rpmRC processPackageFiles(rpmSpec spec, Package pkg, fl.currentLangs = _free(fl.currentLangs); } fl.nLangs = 0; + fl.currentCaps = NULL; dupAttrRec(&fl.def_ar, &fl.cur_ar); @@ -1826,6 +1915,8 @@ static rpmRC processPackageFiles(rpmSpec spec, Package pkg, continue; if (parseForLang(buf, &fl)) continue; + if (parseForCaps(buf, &fl)) + continue; if (parseForSimple(spec, pkg, buf, &fl, &fileName)) continue; if (fileName == NULL) diff --git a/lib/rpmds.c b/lib/rpmds.c index 383c21f..14c5aa5 100644 --- a/lib/rpmds.c +++ b/lib/rpmds.c @@ -1034,6 +1034,11 @@ static const struct rpmlibProvides_s rpmlibProvides[] = { { "rpmlib(FileDigests)", "4.4.90-1", ( RPMSENSE_EQUAL), N_("file checksum digest algorithm is per package configurable") }, +#ifdef WITH_CAP + { "rpmlib(FileCaps)", "4.6.1-1", + ( RPMSENSE_EQUAL), + N_("support for POSIX.1e file capabilities") }, +#endif { NULL, NULL, 0, NULL } }; diff --git a/lib/rpmtag.h b/lib/rpmtag.h index b66cbab..efcbd00 100644 --- a/lib/rpmtag.h +++ b/lib/rpmtag.h @@ -280,6 +280,7 @@ typedef enum rpmTag_e { RPMTAG_ORIGFILENAMES = 5007, /* s[] extension */ RPMTAG_LONGFILESIZES = 5008, /* l[] */ RPMTAG_LONGSIZE = 5009, /* l */ + RPMTAG_FILECAPS = 5010, /* s[] */ RPMTAG_FIRSTFREE_TAG /*!< internal */ } rpmTag; -- 2.7.4