Start adding POSIX 1.e draft file capability support for real
authorPanu Matilainen <pmatilai@redhat.com>
Wed, 29 Oct 2008 08:49:25 +0000 (10:49 +0200)
committerPanu Matilainen <pmatilai@redhat.com>
Wed, 29 Oct 2008 08:49:25 +0000 (10:49 +0200)
- 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
lib/rpmds.c
lib/rpmtag.h

index f4b2014..433bc15 100644 (file)
@@ -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)
index 383c21f..14c5aa5 100644 (file)
@@ -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 }
 };
 
index b66cbab..efcbd00 100644 (file)
@@ -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;