翻译

Translate to EnglishÜbersetzen Sie zum Deutsch/GermanΜεταφράστε στα ελληνικά/GreekПереведите к русскому/RussianOversetter til Norsk/NorwegianÖversätta till Svensk/Swedishहिन्दी अनुवाद करने के लिए/Hindi
Tradueix al català/CatalanTulkot uz latviešu/LatvianPreložiť do slovenčiny/SlovakVertaal aan het Nederlands/Dutchترجمة الى العربية/ArabicTraduzca al Español/SpanishTraduisez au Français/French
Traduca ad Italiano/ItalianTraduza ao Português/Portuguese日本語に翻訳しなさい /Japanese한국어에게 번역하십시오/Korean中文翻译/Chinese Simplified中文翻译/Chinese TraditionalПереклад на українську/Ukrainian
机器人无线应用开发的图象
开始Google Maps的图象API 3
操作系统的概念的图象
Linux仁发展(第3编辑)的图象

Programmatically检索RPM包裹细节

最近,我需要检索关于使用RPM包裹经理,分布他们的软件包在浅顶软呢帽15,红色帽子企业Linux、CentOS和其他发行安装的 软件包的细节。 对于我的意外,什么应该是在过去几年结果的一项相对地简单的任务是相当杂乱的由于在RPM图书馆APIs和内部格式上的变化。 使用C和Python,在这个岗位,我展示如何检索关于RPM包裹的信息。

RPM是命令线或API被驾驶的包裹管理系统能够安装,卸载,核实,询问和更新Linux或Unix软件包。 每个软件包与关于包裹的信息一起包括文件档案例如它的版本号、总结和描述和附庸信息。 也有使开发商的图书馆API处理从编写编程语言例如C或写电影脚本的语言的这样交易这样Python。 包裹文件把写到盘按网络字节顺序。 如果需要,当包裹文件读时, RPM自动地转换数据成主人字节顺序。

RPM在1997年最初被开发了由Erik ・ Troan和Marc Ewing用于Red Hat Linux发行。 许多年它是没有受到爱或注意的opensource项目。 那张图片 2007年初改变了,当二个不同(和竞争)时发展共同体被发射了。

是由红色帽子带领的 更加著名的RPM发展共同体是rpm.org。 根据他们的网站:

在一个长的发展断裂rpm.org在2007年被重新开办以目标索还位置作为向上游在家RPM之后。 首先在不同的发行堆了的补丁集成了代码基地尽可能的。 我们要RPM不是一家公司省或者小套开发商。 它在一个开放社区需要被开发,被消耗和造成由许多公司、用户、发行和开发商。 因此我们欢迎任意贡献者。
….
RPM将停留向后兼容到4.4.2在相当很长时间。 特别是对企业发行是重要的第三方包裹可以被安装,不用需要重新编译他们-。

在5月2007日红色帽子聘用 Panu Matilainen 研究RPM项目。 第一个主要代码修正是在2007年7月; 版本4.8在2010年1月被发布了和4.9在2011年3月。 这个版本由发行使用例如浅顶软呢帽、红色帽子企业Linux、openSUSE、SUSE Linux企业和CentOS。

是主角由杰夫・约翰逊 是RPM维护员,红色帽子的雇员的另一个RPM发展共同体是rpm5.org。 RPM版本5.0在2007年5月被发布了。 他们的最新的版本是约会的5.3.11 026月2011。 为某一其他提供包裹Unix象平台的OpenPKG项目使用RPM的这个版本由发行例如团结Linux和cAos Linux,并且。 表面上 Mandriva也最近换成它,虽然看起来似乎关于 那个 特殊决定的一些争论。

RPM包裹的格式二进制并且包括在下列顺序的三个部分:

  • 主角部分辨认文件, RPM文件。 它包含在RPM的早先老版本被用于存储RPM内部地使用的信息的一定数量的过时倒栽跳水。 今天,然而,主角部分的唯一的目的将使它容易辨认RPM包裹文件。
  • 署名部分包含可以被用于核实正直的信息,和随意地,包裹的多数的真实性。 这个部分被实施使用倒栽跳水结构(如下所示)。
  • 倒栽跳水部分包含包裹变数据例如名字,版本,建筑学,类似的文件名单包括和。 它也被实施作为倒栽跳水结构。
  • Th最后的部分包含实际文件档案,通常以cpio格式,压缩与gzip,但是RPM的较新版本能也使用bzip2, lzma或(XML档案) RPM支持xz压缩和xar 5.0。

这什么主角包含。 不要使用什么从除了主要数字和署名类型的主角。

struct rpmlead_s {
    unsigned char magic[4];
    unsigned char major;
    unsigned char minor;
    short type;
    short archnum;
    char name[66];
    short osnum;
    short signature_type;       /*!< Signature header type (RPMSIG_HEADERSIG) */
    char reserved[16];          /*!< Pad to 96 bytes -- 8 byte aligned! */
};


倒栽跳水结构概念是RPM的解答对容易操作信息的问题用一个规范化的方式。 倒栽跳水结构的目的将包含数据零个或更多片断。 有三个部分对每个倒栽跳水结构。 第一个部分叫作倒栽跳水结构倒栽跳水。 倒栽跳水结构倒栽跳水被用于辨认它包含倒栽跳水结构、它的大小和数据项的数量的开始。 在倒栽跳水结构以后倒栽跳水是称索引的区域。

倒栽跳水结构的索引由零个或更多目录记录做成。 每个词条长是十六个字节。 前四个字节包含一个标记-辨认的一个数值什么样的数据指向由词条。 有在rpmtag.h.定义的很大数量的倒栽跳水标记 这一些他们:

typedef enum rpmTag_e {
    ....
    RPMTAG_NAME                 = 1000, /* s */
    RPMTAG_VERSION              = 1001, /* s */
    RPMTAG_RELEASE              = 1002, /* s */
    RPMTAG_EPOCH                = 1003, /* i */
    RPMTAG_SUMMARY              = 1004, /* s{} */
    RPMTAG_DESCRIPTION          = 1005, /* s{} */
    RPMTAG_BUILDTIME            = 1006, /* i */
    RPMTAG_BUILDHOST            = 1007, /* s */
    RPMTAG_INSTALLTIME          = 1008, /* i */
    RPMTAG_SIZE                 = 1009, /* i */
    RPMTAG_DISTRIBUTION         = 1010, /* s */
    RPMTAG_VENDOR               = 1011, /* s */
    .....
   /* tags 1997-4999 reserved */
    RPMTAG_FILENAMES            = 5000, /* s[] extension */
    RPMTAG_FILEPROVIDE          = 5001, /* s[] extension */
    RPMTAG_FILEREQUIRE          = 5002, /* s[] extension */
    RPMTAG_FSNAMES              = 5003, /* s[] (unimplemented) */
    RPMTAG_FSSIZES              = 5004, /* l[] (unimplemented) */
    RPMTAG_TRIGGERCONDS         = 5005, /* s[] extension */
    RPMTAG_TRIGGERTYPE          = 5006, /* s[] extension */
    RPMTAG_ORIGFILENAMES        = 5007, /* s[] extension */
    RPMTAG_LONGFILESIZES        = 5008, /* l[] */
    RPMTAG_LONGSIZE             = 5009, /* l */
} rpmTag;


在每个标记以后,是一个四字节的类型,是一个数值描述数据格式指向由词条。 这在rpmtag.h定义的类型当前名单:

typedef enum rpmTagType_e {
    RPM_NULL_TYPE               =  0,
    RPM_CHAR_TYPE               =  1,
    RPM_INT8_TYPE               =  2,
    RPM_INT16_TYPE              =  3,
    RPM_INT32_TYPE              =  4,
    RPM_INT64_TYPE              =  5,
    RPM_STRING_TYPE             =  6,
    RPM_BIN_TYPE                =  7,
    RPM_STRING_ARRAY_TYPE       =  8,
    RPM_I18NSTRING_TYPE         =  9,
} rpmTagType;


大多这些类型应该是明显的。 在串类型和STRING_ARRAY类型之间的区别是前是规则空被终止的串,而后者是串的一汇集。 RPM_I18NSTRING_TYPE贬值。

其次包含数据的实际位置的4字节偏移值,相对商店的起点。 终于,有包含数据项的数量指向由目录记录的四字节的计数。 而STRING_ARRAY数据有计数相等与在商店,包含的串的数量串数据总是有一计数1。

在索引来商店之后。 是在商店实际数据项被保留。 数据在商店按网络字节顺序,即最高有效字节越紧密越好一起被包装首先。 串数据终止与一个空字节。 整数数据被存放在它的类型的天然分界线,即32位整数在4字节界限被存放。

好,时刻谈论如何programmatically访问RPM包裹。 然而,在您开始使用RPM图书馆之前,您需要推测RPM图书馆的什么版本您使用。 如果您写着shell script程序,这是容易做。 例如在浅顶软呢帽15 :

$ /usr/lib/rpm/rpmdeps --version
RPM version 4.9.0


从rpm5.org的RPM图书馆有可以被用于检索图书馆版本的rpmlibVersion API或您能访问RPMVERSION串如下所示。

#include <stdio.h>
#include <rpm/rpmlib.h>

int
main()
{
    fprintf(stderr, "RPM Version: %s\n", RPMVERSION);
}


不幸地从rpm.org的RPM图书馆没有相似的什么。 注意对rpm.org开发商! 请增加rpmlibVersion API到支持的公开APIs您的名单,以便需要programmatically访问RPM包裹,并且数据库可能容易地推测他们处理的调味RPM图书馆的应用和发行和相应地调整他们的代码。

在浅顶软呢帽15,返回的版本串是表明RPM的版本在2011年3月被发布的4.9.0。 在CentOS 5.6,返回的版本串是表明在2008年4月发布的RPM的一个显着更旧的版本的4.4.2.3。 有这些版本之间的重大和主要区别。 特别是为这两个特殊RPM版本之一写的C代码不会为另一个版本大概运作没有修改。

变得坏,顺便说一句,作为浅顶软呢帽15和红色帽子企业Linux 6用途也包括一个新的格式和SHA回锅碎肉的更新的 RPM 图书馆。 这引起问题,当您在一个更旧的平台的这些平台之一设法安装RPM被修造例如不了解新的格式和回锅碎肉的CentOS 5.6时。 结果, CentOS 5.6抱怨它不可能证实RPM包裹的正直。

您也需要能确定什么特点RPM的一种特殊版本支持。 这一种方式做它:

#include <stdio.h>
#include <stdlib.h>

#include <rpm/rpmlib.h>
#include <rpm/rpmds.h>

int
main(int argc, char *argv[])
{
    const char *DNEVR;
    rpmds ds = NULL;
    int rc;

    rpmReadConfigFiles(NULL, NULL);

    rc = rpmdsRpmlib(&ds, NULL);
    ds = rpmdsInit(ds);

    fprintf(stdout, "Supported features:\n");
    while (rpmdsNext(ds) >= 0) {
        if ((DNEVR = rpmdsDNEVR(ds)) != NULL)
            fprintf(stdout, "%s\n", DNEVR + 2);
    }
    ds = rpmdsFree(ds);

    exit(0);
}


您必须安排RPM发展包裹(rpmdevel)被安装为了能编写上述代码。

这个代码印支持的RPM特点集合。 这什么为浅顶软呢帽的15 RPM图书馆outputted :

Supported features:
rpmlib(BuiltinLuaScripts) = 4.2.2-1
rpmlib(CompressedFileNames) = 3.0.4-1
rpmlib(ConcurrentAccess) = 4.1-1
rpmlib(ExplicitPackageProvide) = 4.0-1
rpmlib(FileCaps) = 4.6.1-1
rpmlib(FileDigests) = 4.6.0-1
rpmlib(HeaderLoadSortsTags) = 4.0.1-1
rpmlib(PartialHardlinkSets) = 4.0.4-1
rpmlib(PayloadFilesHavePrefix) = 4.0-1
rpmlib(PayloadIsBzip2) = 3.0.5-1
rpmlib(PayloadIsLzma) = 4.4.2-1
rpmlib(PayloadIsXz) = 5.2-1
rpmlib(ScriptletExpansion) = 4.9.0-1
rpmlib(ScriptletInterpreterArgs) = 4.0.3-1
rpmlib(VersionedDependencies) = 3.0.3-1


顺便说一句,有一个RPM指南的 草稿文献 在浅顶软呢帽项目网站上。 我什么时候不知道这个指南被生产了(大概2003),但是最新的版权告示包括2010年。 我不可能为其余这个指南讲话,但是在编程RPM 与C和编程 RPM的 本章与Python 坦率地是垃圾和完全误引。

例如,列出16-1 (rpm1.c),如下所示,甚而不会编写在浅顶软呢帽15甚至在Centos 5.6哪些有RPM的一个更旧的版本。

#include <stdio.h>
#include <stdlib.h>
#include <rpmlib.h>

int
main(int argc, char * argv[])
{
   int status = rpmReadConfigFiles( (const char*) NULL, (const char*) NULL);
   if (status != 0) {
      printf("Error reading RC files.\n");
      exit(-1);
   } else {
      printf("Read RC OK\n");
   }

   rpmSetVerbosity(RPMMESS_NORMAL);
   rpmShowRC( stdout );

   exit(0);
}


在指南不是甚而俏丽的格式化的目录。 上述格式化是所有矿。 在2007年RPMMESS_*定义了回来被去除的方式。 作为旁,大会用途何处退出了(- 1)来自? 那看更多象某事从微软视窗世界! 编辑指示也是古怪的。

$ cc -I/usr/include/rpm -o rpm1 rpm1.c -lrpm -lrpmdb -lrpmio –lpopt


为什么需要参考lrpmdblibpopt ? 从的惯例这些图书馆没有用于上述代码。

这被重写的上述例子在浅顶软呢帽15工作:

#include <stdio.h>
#include <stdlib.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmlog.h>

int
main(int argc, char * argv[])
{
    int status;

    if ((status = rpmReadConfigFiles( (const char*) NULL, (const char*) NULL))) {
       printf("ERROR: reading RC files\n");
       exit(1);
    }

    rpmSetVerbosity(RPMLOG_NOTICE);
    rpmShowRC(stdout);

    exit(0);
}


您能编写上述代码使用gcc - o rpm1 rpm1.c - lrpm - lrpmio

以下例子显示您在系统将传统上看使用引起安装的RPM包裹名单的方法,如果您做一次查寻在互联网的这样代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

#include <rpm/rpmlib.h>
#include <rpm/header.h>
#include <rpm/rpmdb.h>

int
main(int argc, char *argv[])
{
    rpmdbMatchIterator mi;
    int type, count;
    char *name;
    rpmdb db;
    Header h;

    rpmReadConfigFiles( NULL, NULL );
    if (rpmdbOpen( "", &db, O_RDONLY, 0644 ) != 0) {
        fprintf( stderr, "ERROR: Cannot open RPM database\n");
        exit(1);
    }

    mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
    while ((h = rpmdbNextIterator(mi))) {
        headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
        printf("%s\n", name);
    }

    rpmdbFreeIterator(mi);
    rpmdbClose(db);

    exit(0);
}


它使用rpmdbOpenrpmdbClose打开和关闭RPM数据库和rpmdbMatchInterator通过寻找RPMTAG_NAME的RPM数据库重复配比的词条。

为CentOS 5.6运作,但是浅顶软呢帽15不支持这。 在RPM 4.9.0,几乎包括半新的rpmdbOpenrpmdbCloserpmdbMatchInterator惯例以上去除了所有低级rpmdb操作作用或向内了。 看见RPM 4.9.0 发行说明 关于全面详细。

以下例子在浅顶软呢帽15运作并且输出名字(RPMTAG_NAME)和大小(RPMTAG_SIZE)名单的每个安装的包裹。

#include <stdio.h>
#include <stdlib.h>

#include <rpm/rpmlib.h>
#include <rpm/header.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>

int
main()
{
    rpmts ts = NULL;
    Header h;
    rpmdbMatchIterator mi;
    rpmtd td, tn;
    char time_buffer[512];
    int rc1, rc2;

    td = rpmtdNew();
    tn = rpmtdNew();
    ts = rpmtsCreate();

    rpmReadConfigFiles( NULL, NULL );

   mi = rpmtsInitIterator( ts, RPMDBI_PACKAGES, NULL, 0);
    while (NULL != (h = rpmdbNextIterator(mi))) {

        h = headerLink(h);
        rc1 = headerGet(h, RPMTAG_NAME, tn, HEADERGET_EXT);
        rc2 = headerGet(h, RPMTAG_SIZE, td, HEADERGET_EXT);

        // output installed package name and size
        fprintf(stdout, "%s (%llu)\n", rpmtdGetString(tn), rpmtdGetNumber(td));

        rpmtdReset(td);
        rpmtdReset(tn);
        headerFree(h);
    }

    rpmdbFreeIterator(mi);
    rpmtsFree(ts);

    exit(0);
}


以下例子在您的系统显示如何打印出来关于安装的包裹的更多信息。

#include <stdio.h>
#include <stdlib.h>

#include <rpm/rpmlib.h>
#include <rpm/header.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>

int
main(int argc, char *argv[])
{
    rpmts ts = NULL;
    Header h;
    rpmdbMatchIterator mi;
    char *n, *v, *r, *g, *a;

    ts = rpmtsCreate();
    rpmReadConfigFiles( NULL, NULL );

    mi = rpmtsInitIterator( ts, RPMDBI_PACKAGES, NULL, 0);
    while (NULL != (h = rpmdbNextIterator(mi))) {
        h = headerLink( h );
        headerGetEntry( h, RPMTAG_NAME, NULL, (void**)&n, NULL);
        headerGetEntry( h, RPMTAG_VERSION, NULL, (void**)&v, NULL);
        headerGetEntry( h, RPMTAG_RELEASE, NULL, (void**)&r, NULL);
        headerGetEntry( h, RPMTAG_GROUP, NULL, (void**)&g, NULL);
        headerGetEntry( h, RPMTAG_ARCH, NULL, (void**)&a, NULL);

        fprintf(stdout, "%s-%s-%s.%s\n", n, v, r, a);

        headerFree(h);
    }
    rpmdbFreeIterator(mi);
    rpmtsFree(ts);

    exit(0);
}


这个例子在CentOS 5.6和浅顶软呢帽15运作。 这一些样本输出:

iso-codes-0.53-1.noarch
zlib-1.2.3-3.x86_64
libstdc++-4.1.2-50.el5.x86_64
db4-4.3.29-10.el5_5.2.x86_64
info-4.8-14.el5.x86_64
gawk-3.1.5-14.el5.x86_64
libgcrypt-1.4.4-5.el5.x86_64
libfontenc-1.0.2-2.2.el5.x86_64
libieee1284-0.2.9-4.el5.x86_64
grep-2.5.1-55.el5.x86_64
....


顺便说一句, RPM有Python、Perl和 Lua 支持。 这在Python写的等效代码:

#!/usr/bin/python

import rpm

ts=rpm.ts()

mi=ts.dbMatch()
for hdr in mi:
    print "%s-%s-%s.%s" % (hdr['name'], hdr['version'], hdr['release'], hdr['arch'])


您能看到Python能很大地简化事,当您希望与RPM包裹一起使用时。

以下例子在每个安装的包裹的XML格式展示如何打印出来一定数量的标记。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include <rpm/rpmlib.h>
#include <rpm/header.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>

struct tag {
   int  tagno;
   char *element;
};

truct tag tags[] = {
   { RPMTAG_NAME, "Name"},
   { RPMTAG_VERSION, "Version" },
   { RPMTAG_RELEASE, "Release" },
   { RPMTAG_SUMMARY, "Summary" },
   { RPMTAG_BUILDTIME, "BuildTime"},
   { RPMTAG_BUILDHOST, "BuildHost" },
   { RPMTAG_INSTALLTIME, "InstallTime" },
   { RPMTAG_SIZE, "Size" },
   { RPMTAG_LICENSE, "License"},
   { RPMTAG_URL, "SourceUrl" },
   { RPMTAG_PAYLOADFORMAT, "PayloadFormat" },
   { RPMTAG_PAYLOADCOMPRESSOR, "PayloadCompressor" }
};

#define NTAGS (sizeof(tags)/sizeof(struct tag))

int
main(int argc, char *argv[])
{
    rpmdbMatchIterator mi;
    rpmts ts = NULL;
    rpmtd td;
    Header h;
    int i;

    td = rpmtdNew();
    ts = rpmtsCreate();
    rpmReadConfigFiles(NULL, NULL);

    printf("<InstalledPackages>\n");
    mi = rpmtsInitIterator( ts, RPMDBI_PACKAGES, NULL, 0);
    while (NULL != (h = rpmdbNextIterator(mi))) {
        h = headerLink(h);
        printf("   <Package>\n");
        for ( i = 0; i < NTAGS; i++) {
            headerGet(h, (rpm_tag_t)tags[i].tagno, td, HEADERGET_ALLOC | HEADERGET_EXT);
            if (td->data) {
                switch(td->type) {
                    case RPM_NULL_TYPE:
                        break;
                    case RPM_CHAR_TYPE:
                        printf("      <%s>%s</%s>\n", tags[i].element, td->data, tags[i].element);
                        break;
                    case RPM_INT8_TYPE:
                    case RPM_INT16_TYPE:
                        printf("      <%s>%d</%s>\n", tags[i].element, td->data, tags[i].element);
                        break;
                    case RPM_INT32_TYPE:
                        if ((tags[i].tagno == RPMTAG_BUILDTIME) ||
                           (tags[i].tagno == RPMTAG_INSTALLTIME)) {
                             printf("      <%s>%s</%s>\n", tags[i].element, rpmtdFormat(td, RPMTD_FORMAT_DATE , NULL), tags[i].element);
                        } else if (tags[i].tagno == RPMTAG_SIZE) {
                             printf("      <%s>%" PRIu64 "<%s>\n", tags[i].element, rpmtdGetNumber(td), tags[i].element);
                        } else {
                             printf("      <%s>%u</%s>\n", tags[i].element, td->data, tags[i].element);
                        }
                        break;
                    case RPM_INT64_TYPE:
                        printf("      <%s>%" PRIu64 "</%s>\n", tags[i].element, rpmtdGetNumber(td), tags[i].element);
                        break;
                    case RPM_STRING_TYPE:
                        printf("      <%s>%s</%s>\n", tags[i].element, rpmtdGetString(td), tags[i].element);
                        break;
                    case RPM_BIN_TYPE:
                        printf("      <%s>%x</%s>\n", tags[i].element, td->data, tags[i].element);
                        break;
                    case RPM_STRING_ARRAY_TYPE:
                    default:
                        break;
                }
            }

            rpmtdReset(td);
        }
        headerFree(h);

        printf("   </Package>\n");
    }
    printf("</InstalledPackages>\n");

    rpmdbFreeIterator(mi);
    rpmtsFree(ts);

    exit(0);
}


这在浅顶软呢帽15运作。 这输出例子:

<InstalledPackages>
   <Package>
      <Name>file-roller</Name>
      <Version>3.0.2</Version>
      <Release>1.fc15</Release>
      <Summary>Tool for viewing and creating archives</Summary>
      <BuildTime>Wed May 25 19:57:10 2011</BuildTime>
      <BuildHost>x86-06.phx2.fedoraproject.org</BuildHost>
      <InstallTime>Thu Jun  2 17:45:29 2011</InstallTime>
      <Size>5928015<Size>
      <License>GPLv2+</License>
      <SourceUrl>http://download.gnome.org/sources/file-roller/</SourceUrl>
      <PayloadFormat>cpio</PayloadFormat>
      <PayloadCompressor>xz</PayloadCompressor>
   </Package>
   <Package>
      <Name>expect</Name>
      <Version>5.45</Version>
      <Release>3.fc15</Release>
      <Summary>A program-script interaction and testing utility</Summary>
      <BuildTime>Wed Mar 16 09:58:49 2011</BuildTime>
      <BuildHost>x86-12.phx2.fedoraproject.org</BuildHost>
      <InstallTime>Mon Jun 13 10:24:25 2011</InstallTime>
      <Size>559676<Size>
      <License>Public Domain</License>
      <SourceUrl>http://expect.nist.gov/</SourceUrl>
      <PayloadFormat>cpio</PayloadFormat>
      <PayloadCompressor>xz</PayloadCompressor>
   </Package>
   .....
   <Package>
      <Name>libxkbfile-devel</Name>
      <Version>1.0.7</Version>
      <Release>2.fc15</Release>
      <Summary>X.Org X11 libxkbfile development package</Summary>
      <BuildTime>Tue Feb  8 08:03:57 2011</BuildTime>
      <BuildHost>x86-13.phx2.fedoraproject.org</BuildHost>
      <InstallTime>Thu Jun  2 17:56:48 2011</InstallTime>
      <Size>38055<Size>
      <License>MIT</License>
      <SourceUrl>http://www.x.org</SourceUrl>
      <PayloadFormat>cpio</PayloadFormat>
      <PayloadCompressor>xz</PayloadCompressor>
   </Package>
</InstalledPackages>


注意RPM的版本在CentOS 5.6的不支持RPM_INT64_TYPE。 结果约会,并且类似在RPM_INT32_TYPE被存放。

现在转向怎样审查各自的RPM包裹。 以下简单例子展示您如何询问包裹文件:

#include <stdio.h>
#include <stdlib.h>

#include <rpm/rpmlib.h>
#include <rpm/header.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>
#include <rpm/rpmlog.h>

int
main(int argc, char *argv[])
{
    int i;
    rpmts ts;

    FD_t fd;
    rpmRC rc;
    Header hdr;
    char *pkg_name, *pkg_version, *pkg_release;
    rpmVSFlags vsflags = 0;

    rc = rpmReadConfigFiles(NULL, NULL);
    if (rc != RPMRC_OK) {
        rpmlog(RPMLOG_NOTICE, "Unable to read RPM configuration.\n");
        exit(1);
    }

    fd = Fopen(argv[1], "r.ufdio");
    if ((!fd) || Ferror(fd)) {
       rpmlog(RPMLOG_NOTICE, "Failed to open package file (%s)\n", Fstrerror(fd));
       if (fd) {
           Fclose(fd);
       }
       exit(1);
    }

    ts = rpmtsCreate();

    vsflags |= _RPMVSF_NODIGESTS;
    vsflags |= _RPMVSF_NOSIGNATURES;
    vsflags |= RPMVSF_NOHDRCHK;
    (void) rpmtsSetVSFlags(ts, vsflags);

    rc = rpmReadPackageFile(ts, fd, argv[1], &hdr);
    if (rc != RPMRC_OK) {
       rpmlog(RPMLOG_NOTICE, "Could not read package file\n");
        Fclose(fd);
        exit(1);
     }
     Fclose(fd);

    if (headerNVR(hdr, (const char **) &pkg_name,
                       (const char **) &pkg_version,
                       (const char **) &pkg_release))
    {
         rpmlog(RPMLOG_NOTICE, "Header read failed\n");
    } else {
         printf("Package is: %s-%s-%s\n", pkg_name, pkg_version, pkg_release);
         headerFreeData(pkg_name, RPM_STRING_TYPE);
         headerFreeData(pkg_version, RPM_STRING_TYPE);
         headerFreeData(pkg_release, RPM_STRING_TYPE);
    }

    headerFree(hdr);
    rpmtsFree(ts);

    exit(0);
}


您能编写上述例子使用gcc - o例子example.c - lrpm - lrpmio。 这编写没有错误或警告在CentOS 5.6,但是发出警告headerNVR在浅顶软呢帽15贬值。

假设您想要发现特殊性安装的RPM包裹有要求的名单。 一种方式将使用rpm - qR 。 另一个方式将使用发现要求rpmdeps如下所示:

$ rpm -ql rpm-devel | /usr/lib/rpm/find-requires
libacl.so.1()(64bit)
libbz2.so.1()(64bit)
libcap.so.2()(64bit)
libc.so.6()(64bit)
libc.so.6(GLIBC_2.14)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libdb-4.8.so()(64bit)
libdl.so.2()(64bit)
libelf.so.1()(64bit)
liblua-5.1.so()(64bit)
liblzma.so.5()(64bit)
libm.so.6()(64bit)
libnss3.so()(64bit)
libpopt.so.0()(64bit)
libpthread.so.0()(64bit)
librpmio.so.2()(64bit)
librpm.so.2()(64bit)
librt.so.1()(64bit)
libselinux.so.1()(64bit)
libz.so.1()(64bit)

$ rpm -ql rpm-devel | /usr/lib/rpm/rpmdeps -R
/usr/bin/pkg-config
libacl.so.1()(64bit)
libbz2.so.1()(64bit)
libc.so.6()(64bit)
libc.so.6(GLIBC_2.14)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libcap.so.2()(64bit)
libdb-4.8.so()(64bit)
libdl.so.2()(64bit)
libelf.so.1()(64bit)
liblua-5.1.so()(64bit)
liblzma.so.5()(64bit)
libm.so.6()(64bit)
libnss3.so()(64bit)
libpopt.so.0()(64bit)
libpopt.so.0(LIBPOPT_0)(64bit)
libpthread.so.0()(64bit)
librpm.so.2()(64bit)
librpmbuild.so.2()(64bit)
librpmio.so.2()(64bit)
librpmsign.so.0()(64bit)
librt.so.1()(64bit)
libselinux.so.1()(64bit)
libz.so.1()(64bit)
rtld(GNU_HASH)


这与安装的文件、冲突和obsoletes一起将打印出来等效信息C程序的例子:

#include <stdio.h>
#include <stdlib.h>

#include <rpm/rpmlib.h>
#include <rpm/rpmds.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>

int
main(int argc, char *argv[])
{
    const char *DNEVR;
    rpmdbMatchIterator mi;
    rpmds ds = NULL;
    Header h;
    rpmtd td_name, td_version, td_release, td_size, td_group, td_installtime;
    rpmts ts = NULL;
    rpmfi fi;

    if (argc != 2) {
        fprintf(stderr, "ERROR: No RPM specified on command line.\n");
        exit(1);
    }

    td_name = rpmtdNew();
    td_version = rpmtdNew();
    td_release = rpmtdNew();
    td_size = rpmtdNew();
    td_group = rpmtdNew();
    td_installtime = rpmtdNew();

   ts = rpmtsCreate();

    rpmReadConfigFiles(NULL, NULL);

    mi = rpmtsInitIterator(ts, RPMTAG_NAME, argv[1], 0);
    if (NULL != (h = rpmdbNextIterator(mi))) {
        h = headerLink(h);
        headerGet(h, RPMTAG_NAME, td_name, HEADERGET_EXT);
        headerGet(h, RPMTAG_VERSION, td_version, HEADERGET_EXT);
        headerGet(h, RPMTAG_RELEASE, td_release, HEADERGET_EXT);
        headerGet(h, RPMTAG_SIZE, td_size, HEADERGET_EXT);
        headerGet(h, RPMTAG_GROUP, td_group, HEADERGET_EXT);
        headerGet(h, RPMTAG_INSTALLTIME, td_installtime, HEADERGET_EXT);

        printf("%-20s: %s-%s-%s\n", "Package", rpmtdGetString(td_name), rpmtdGetString(td_version), rpmtdGetString(td_release));
        printf("%-20s: %s\n", "Group", rpmtdGetString(td_group));
        printf("%-20s: %llu\n", "Size", rpmtdGetNumber(td_size));
        printf("%-20s: %s\n", "Installed on", rpmtdFormat(td_installtime, RPMTD_FORMAT_DATE, NULL));

        fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
        if (fi) {
            fprintf(stdout, "\nFiles Provided:\n");
            while (rpmfiNext(fi) != -1)
                 fprintf(stdout, "  %s\n", rpmfiFN(fi));
            fi = rpmfiFree(fi);
        }

#if EXTRA
        ds = rpmdsNew(h, RPMTAG_PROVIDENAME, 0);
        if (ds) {
            fprintf(stdout, "\nProvides:\n");
            while (rpmdsNext(ds) >= 0) {
                 if ((DNEVR = rpmdsDNEVR(ds)) != NULL)
                    fprintf(stdout, "  %s\n", DNEVR + 1);
            }
            ds = rpmdsFree(ds);
        }
#endif

        ds = rpmdsNew(h, RPMTAG_REQUIRENAME, 0);
        if (ds) {
            fprintf(stdout, "\nRequires:\n");
            while (rpmdsNext(ds) >= 0) {
                 if ((DNEVR = rpmdsDNEVR(ds)) != NULL)
                    fprintf(stdout, "  %s\n", DNEVR + 1);
            }
            ds = rpmdsFree(ds);
        }

        ds = rpmdsNew(h, RPMTAG_OBSOLETENAME, 0);
        if (ds) {
            fprintf(stdout, "\nObsoletes:\n");
            while (rpmdsNext(ds) >= 0) {
                 if ((DNEVR = rpmdsDNEVR(ds)) != NULL)
                    fprintf(stdout, "  %s\n", DNEVR + 1);
            }
            ds = rpmdsFree(ds);
        }

        ds = rpmdsNew(h, RPMTAG_CONFLICTNAME, 0);
        if (ds) {
            fprintf(stdout, "\nConflicts:\n");
            while (rpmdsNext(ds) >= 0) {
                 if ((DNEVR = rpmdsDNEVR(ds)) != NULL)
                    fprintf(stdout, "  %s\n", DNEVR + 1);
            }
            ds = rpmdsFree(ds);
        }

        headerFree(h);
    }

    rpmdbFreeIterator(mi);
    rpmtsFree(ts);

    exit(0);
}


这运作在浅顶软呢帽15,但是不在CentOS 5.6。 然而,修改得到它在CentOS 5.6运作是相对地容易的,并且我将因而离开作为您的一锻炼。 主要变动与使用rpmtd类型关连。 这些需要被消灭作为RPM的版本在CentOS 5.6的不支持rpmtd类型。

这什么为xorg-x11-xkb-utils包裹outputted :

./rpminfo.py xorg-x11-xkb-utils
Package             : xorg-x11-xkb-utils-7.5-3.fc15
Group               : User Interface/X
Size                : 199629
Installed on        : Thu Jun  2 17:39:31 2011

Files Provided:
  /usr/bin/setxkbmap
  /usr/bin/xkbcomp
  /usr/share/man/man1/setxkbmap.1.gz
  /usr/share/man/man1/xkbcomp.1.gz

Requires:
   libX11.so.6()(64bit)
   libc.so.6()(64bit)
   libc.so.6(GLIBC_2.2.5)(64bit)
   libc.so.6(GLIBC_2.3)(64bit)
   libc.so.6(GLIBC_2.3.4)(64bit)
   libc.so.6(GLIBC_2.4)(64bit)
   libc.so.6(GLIBC_2.7)(64bit)
   libxkbfile.so.1()(64bit)
   rpmlib(CompressedFileNames) <= 3.0.4-1
   rpmlib(FileDigests) <= 4.6.0-1
   rpmlib(PayloadFilesHavePrefix) <= 4.0-1
   rtld(GNU_HASH)
   rpmlib(PayloadIsXz) <= 5.2-1

Obsoletes:
   XFree86
   xorg-x11


使用Python,这如何做同一件事。 它根据在顺便说一句,不工作亦不的浅顶软呢帽项目RPM指南的目录举的例子宽松地17-3,我怀疑,工作! 这个剧本导致的产品比那稍微全面C版本,即使剧本有少量代码行。

#!/usr/bin/python

import rpm, sys

def stringfromds(ds):
    retlist=[]
    for dataset in ds:
        t=dataset[0]
        values=t.split(" ")[1:]
        retlist.append(" ".join(values))
    return retlist

def printEntry(header, label, format, extra):
    value = header.sprintf(format).strip()
    print "%-20s: %s %s" % (label, value, extra)

def printHeader(h):
    if h[rpm.RPMTAG_SOURCEPACKAGE]:
        extra = " source package"
    else:
        extra = " binary package"

    printEntry(h, 'Package', "%{NAME}-%{VERSION}-%{RELEASE}", extra)
    printEntry(h, 'Group', "%{GROUP}", '')
    printEntry(h, 'Summary', "%{Summary}", '')
    printEntry(h, 'Arch-OS-Platform', "%{ARCH}-%{OS}-%{PLATFORM}", '')
    printEntry(h, 'Vendor', "%{Vendor}", '')
    printEntry(h, 'URL', "%{URL}", '')
    printEntry(h, 'Size', "%{Size}", '')
    printEntry(h, 'Installed on', "%{INSTALLTID:date}", '')
    print "%-20s: %s" % ("Description", h['Description'])

    print "\nFiles Provided:"
    for fi in h.fiFromHeader():
        print "  ", fi[0], "  ", fi[1], "  ", fi[12]

    ds = rpm.ds(h, 'requires')
    if ds:
        print "\nRequires:"
        for d in stringfromds(ds):
            print "  ", d

    ds = rpm.ds(h, 'obsoletes')
    if ds:
        print "\nObsoletes:"
        for d in stringfromds(ds):
            print "  ", d

    ds = rpm.ds(h, 'conflicts')
    if ds:
        print "\nConflicts:"
        for d in stringfromds(ds):
            print "  ", d

def main(argv):
    ts = rpm.TransactionSet()
    for h in ts.dbMatch( 'name', argv[1]):
        printHeader(h)

if __name__ == "__main__":
    if len(sys.argv) == 1:
        print "ERROR: No RPM specified on command line."
        sys.exit(1)
    else:
        main(sys.argv)


这什么为xorg-x11-xkb-utils包裹outputted :

$ ./rpminfo.py xorg-x11-xkb-utils
Package             : xorg-x11-xkb-utils-7.5-3.fc15  binary package
Group               : User Interface/X
Summary             : X.Org X11 xkb utilities
Arch-OS-Platform    : x86_64-linux-x86_64-redhat-linux-gnu
Vendor              : Fedora Project
URL                 : http://www.x.org
Size                : 199629
Installed on        : Thu Jun  2 17:38:11 2011
Description         : X.Org X11 xkb core utilities

Files Provided:
   /usr/bin/setxkbmap    19224    e5e5757d15ca331474c43a0319d0307920fb17b3ed9d04c041e13b56c4aa08e4
   /usr/bin/xkbcomp    176960    e6b265d05cd6432859d7a24fb8f6d6ccec3cbd668abd54afd9606322d3dd9a9e
   /usr/share/man/man1/setxkbmap.1.gz    1753    4a91c43a425699e4209880cf80a28eeae565763ece6cffaa8308a92139fd3250
   /usr/share/man/man1/xkbcomp.1.gz    1692    29d16f6c864bf62b7f3e3e0400e121def3f85e6d64676dffb6d92c54503a0c76

Requires:
   libX11.so.6()(64bit)
   libc.so.6()(64bit)
   libc.so.6(GLIBC_2.2.5)(64bit)
   libc.so.6(GLIBC_2.3)(64bit)
   libc.so.6(GLIBC_2.3.4)(64bit)
   libc.so.6(GLIBC_2.4)(64bit)
   libc.so.6(GLIBC_2.7)(64bit)
   libxkbfile.so.1()(64bit)
   rpmlib(CompressedFileNames) <= 3.0.4-1
   rpmlib(FileDigests) <= 4.6.0-1
   rpmlib(PayloadFilesHavePrefix) <= 4.0-1
   rtld(GNU_HASH)
   rpmlib(PayloadIsXz) <= 5.2-1

Obsoletes:
   XFree86
   xorg-x11


再次,您能看到使用Python比C是容易,当与RPM包裹internals一起使用时。

在我在这个岗位之前停止活动,我必须说Linux世界不在RPM附近需要二个不同发展共同体。 是,在二个转每分钟发展共同体之间的竞争有导致一些改善在RPM包裹经理,但是它也有导致知名的被提供的APIs例如rpmdbOpen和在最新发行被去除的rpmdbClose。 这两个社区应该埋没轴和合并他们的努力。 有时分叉项目的社区是好并且导致真正地有用的创新。 在这种情况下是我的看法它不是!

我必须也说文献为使用RPM图书馆APIs是坦率地惨酷的,并且两个RPM开发商社区不似乎做严肃的尝试通知用户主要变化他们的图书馆在APIs的除在变化的阴暗的参考之外在他们的各自发行说明上。 需要改正这。 在正确的方向的步将提供被去除的API用法,当介绍时新的API或老API的简单例子。

享用!

留下回复