翻訳しなさい

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
RHCEの赤い帽子のイメージは証明したエンジニアのLinuxの調査ガイド(検査RH302) (証明の出版物)を
UNIX環境の高度プログラミング、第2版(Addison-Wesleyの専門家の計算シリーズ)のイメージ
オペレーティングシステムの概念のイメージ
Linuxの穀粒の開発(第3版)のイメージ

ProgrammaticallyはRPMのパッケージの細部を取り出す

最近、私はソフト帽15、赤い帽子企業のLinux、CentOSおよび他の配分に取付けられているRPMのパッケージのマネージャーを使用してソフトウエアパッケージを配るソフトウエアパッケージについての 細部を取り出す必要があった。 私の驚きに、RPMの図書館のAPIsおよび内部フォーマットの変更のためにかなりきたないためにここ数年にわたってなる比較的簡単な仕事べきである何が。 このポストではCおよび大蛇を使用してRPMのパッケージについての情報を取り出す方法を、私は示す。

RPMはLinuxまたはUnixの取付け、アンインストールし、確認し、ただし、そして更新することができる命令ラインまたはAPIによって運転されるパッケージの管理システムソフトウエアパッケージである。 各ソフトウエアパッケージはバージョン・ナンバーのようなパッケージについての情報とともにファイルのアーカイブから、概要および記述および依存情報成っている。 またCのような編集されたプログラミング言語または台本を書く言語からのそのようなトランザクションを管理することを開発者が可能にする図書館APIがそのような大蛇ある。 パッケージファイルはネットワークバイトの順序にディスクに書かれる。 必要ならば、RPMはホストバイトの順序に自動的にパッケージファイルが読まれるときデータを変える。

RPMはエリックTroanおよびRed Hat Linuxの配分の使用のためのMarc Ewingによって1997年に最初に開発された。 多くの年のために多くの愛か関心を引かなかったのはopensourceのプロジェクトだった。 その映像は 2の別々の(および競う)開発者コミュニティが進水した早い2007年に変わり。

赤い帽子によって導かれる より顕著なRPMの開発者コミュニティはrpm.orgである。 ウェブサイトに従って:

RPMの上流にとして位置を開拓するために長い開発の壊れ目rpm.orgが目的との2007年に家に再開された後。 手始めとして異なった配分で積んだパッチはコード基盤にできる限り統合された。 私達はRPMか小さい一組の開発者に1つの会社の地域でなくてほしい。 それは開いたコミュニティで開発され、多くの会社によって、ユーザー、配分および開発者に消費され、貢献される必要がある。 従って私達はありとあらゆる貢献者を歓迎する。
….
RPMはかなり長い時間の間4.4.2に下位互換にとどまる。 第三者のパッケージがそれらをリコンパイルする必要性なしに取付けることができることは企業の配分のために必要-特にである。

5月2007日の赤で帽子は RPMのプロジェクト で動作するためにPanu Matilainenを雇った。 最初の主要なコード修正は2007年7月にあった; 版4.8、および2011年3月の4.9は2010年1月に解放された。 この版はソフト帽、赤い帽子企業のLinux、openSUSE、SUSEのLinux企業およびCentOSのような配分によって使用される。

RPMの支持者 赤い帽子の従業員のジェフジョンソンによって鉛行う他のRPMの開発者コミュニティはrpm5.orgである。 RPM版5.0は2007年5月に解放された。 最新バージョンは5.3.11日付がついた2011年6月2日である。 RPMのこの版は単一性のLinuxおよびcAosのLinuxのような配分とまたプラットホームUnixのように他のにパッケージを提供するOpenPKGのプロジェクトによって使用される。 おそらく Mandrivaはそれに最近そこにその特定の決定についての論争の ようであるがまた転換した。

RPMのパッケージのフォーマットは二進、以下の順の3つのセクションから成っている:

  • 鉛セクションはファイルをようにRPMファイル識別する。 それはRPMによって内部的に使用された情報を貯えるのにRPMの前の前のバージョンで使用されたいくつかの時代遅れヘッダーを含んでいる。 今日しかし鉛セクションの唯一の目的はRPMのパッケージファイルを識別することを容易にすることである。
  • 署名セクションは完全性を確認するのに使用することができる任意に、パッケージの大半の信用含み情報を。 このセクションはヘッダーの構造の(下記参照)を使用して実行される。
  • ヘッダーセクションは名前、版、建築、含まれ、suchlikeファイルのリストのようなパッケージのメタデータを含んでいる。 それはヘッダーの構造として余りに実行される。
  • Thの最終的なセクションはcpioのフォーマットに通常ある実際のファイルアーカイブを含んでいる、gzipとRPMの新しいバージョンはまたbzip2のlzmaを使用できるが、圧縮されるまたはxzの圧縮およびxar RPM 5.0によって(XMLのアーカイブ)支えられる。

ここに鉛が含んでいるものがある。 主要な数および署名のタイプを除く鉛からの何も使用してはいけない。

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の解決である。 ヘッダーの構造の目的はデータのゼロのであるまたはより多くの部分を含むこと。 各ヘッダーの構造へ3つのセクションがある。 最初のセクションはヘッダーの構造ヘッダーとして知られている。 ヘッダーの構造ヘッダーが含んでいるデータ項目のヘッダーの構造、サイズおよび数の開始を識別するのに使用されている。 ヘッダーの構造の後でヘッダーは索引と呼ばれる区域である。

ヘッダーの構造の索引はゼロ成っているまたはより多くの索引記入から。 各記入項目は長く16バイトである。 最初の4バイトはどのようなデータが記入項目によってを指されるか札-識別する数値--を含んでいる。 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;


各札の後で、記入項目によってを指されるデータのフォーマットを記述する数値の4バイトタイプはある。 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バイトのオフセット値は店の始めに関連して次にある。 最後に、索引記入によってを指されるデータ項目の数を含んでいる4バイト計算がある。 STRING_ARRAYデータに店に含まれているひもの数と等しい計算があるが、ひもデータに1の計算が常にある。

索引が店来た後。 それは店に実際のデータ項目が保たれることである。 店のデータはネットワークバイトの順序、すなわち最上位のバイトで最初にできるだけ密接に一緒に詰まる。 ひもデータはブランクバイトと終わる。 整数データはタイプのための固有の境界で貯えられる、すなわち32ビット整数は4バイトの境界で貯えられる。

わかりました、programmatically RPMのパッケージにアクセスする方法述べる時間。 RPMの図書館のどんな版を使用しているかRPMの図書館を使用し始める前に把握する必要があるどんなに。 シェル・スクリプトを書けば、これはし易い。 例えばソフト帽15で:

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


rpm5.orgからのRPMの図書館に図書館版を取り出すのに使用することができるまたは下記に示されているようにRPMVERSIONのひもに単にアクセスできるrpmlibVersion APIがある。

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

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


残念ながらrpm.orgからのRPMの図書館に類似した何もない。 rpm.orgの開発者に注意しなさい! programmatically RPMのパッケージにアクセスする必要があり、風味を付けるおよびに対処しているおよびコードをそれに応じて調節するためRPMの図書館の解放データベースが容易に把握できる適用ように支えられた公共のAPIsのあなたのリストにrpmlibVersion APIを加えなさい。

ソフト帽15で、戻る版ひもは4.9.0である2011年3月に解放されたRPMの版を示す。 CentOS 5.6で、戻る版ひもは4.4.2.3である2008年4月に解放されるRPMのかなりより古い版を示す。 これらの版間に重要な、主な違いがある。 特にこれら二つの特定RPM版の1つのために書かれているCコードは修正なしでは他の版のためにおそらく働かない。

それはソフト帽15および赤い帽子企業のLinux 6の使用としてより悪く、ところで、また新しいフォーマットおよびSHAの挽肉料理を含んでいるより新しいRPMの 図書館 なる。 これは造られる新しいフォーマットおよび挽肉料理について知らないCentOS 5.6のようなより古いプラットホームのこれらのプラットホームの1つにRPMを取付けることを試みるとき問題を起こす。 その結果RPMのパッケージの完全性を確認できないことを、CentOS 5.6は不平を言う。

またどんな特徴を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の特徴セットを単にプリントアウトする。 ここにoutputtedものがソフト帽15のRPMの図書館のためにある:

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年を含んでいる。 私はこのガイドの残りのために話すことができないが、CのRPMを プログラムし、大蛇との RPMを プログラムすることの章は 率直に屑および率直に誤解である。

例えばRPMのずっとより古い版があるかどれが、16-1年をリストする(rpm1.c)は、次示されていて、編集しないソフト帽15でまた更にCentos 5.6で。

#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);
}


ガイドでフォーマットされているリストはきれいではない。 上記の書式作成はすべての鉱山である。 RPMMESS_*は2007年にもどって来た取除かれた方法定義する。 傍白として、大会の使用はどこから(- 1)から来られて出たか。 そのマイクロソフト・ウインドウズの世界からの何かのような多くを見る! 蓄積の指示はまた不可解である。

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


なぜlrpmdbおよびlibpoptを参照する必要性か。 これらの図書館のからのルーチンは上記のコードで使用されない。

ソフト帽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);
}


を使用して- lrpm - lrpmio上記のコードをGCC - o rpm1 rpm1.c編集できる。

次の例はインターネットのそのようなコードの調査をすればあなたが伝統的に見る方法を示したものだシステムで設置済み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);
}


それはRPMTAG_NAMEのための一致の記入項目を捜すRPMのデータベースを通って繰り返すためにrpmdbOpen rpmdbClose RPMのデータベースを開閉するためにおよびrpmdbMatchInterator使用し。

これはCentOS 5.6のために働くが、ソフト帽15で支えられない。 RPM 4.9.0では、上で使用されたrpmdbOpenrpmdbCloseおよびrpmdbMatchInteratorルーチンを含むほとんどすべての低レベルの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に大蛇、パールおよびLua サポートが ある。 大蛇に書かれる同等のコードはここにある:

#!/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'])


見ることができるように大蛇は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>


CentOS 5.6のRPMの版がRPM_INT64_TYPEを支えないことに注目しなさい。 その結果日付を記入し、suchlike 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とともに同等の情報を印刷するa.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のタイプの使用に関連している。 これらは支えないrpmtdのタイプをCentOS 5.6のRPMの版として除去される必要がある。

ここにoutputtedものがxorg-x11-xkb-utilsのパッケージのためにある:

./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


ここに大蛇を使用して同じ事をする方法をある。 それはところで、働かせないソフト帽のプロジェクト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)


ここにoutputtedものがxorg-x11-xkb-utilsのパッケージのためにある:

$ ./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


再度RPMのパッケージのinternalsを使用するとき、大蛇を使用することはCよりずっと容易であることを見ることができる。

私がこのポストを受け入れる前に、私はLinuxの世界がRPMのまわりで2人の開発者コミュニティを必要としないと言わなければならない。 はい、2人のRPMの開発者コミュニティ間の競争はRPMのパッケージのマネージャーである改善をもたらすことを持っていたが、またrpmdbOpen最近のリリースで取除かれるrpmdbClose有名な文書化されたAPIsをのようなもたらすことを持ち。 これら二つのコミュニティは斧を埋め、彼らの努力を併合するべきである。 時々コミュニティはプロジェクトを分岐しているよく、実際に有用な革新に導く。 この場合それはそれがないこと私の意見である!

私はまたRPMの図書館のAPIsを使用するためのドキュメンテーションが率直に凶悪であり、RPMの開発者のコミュニティが両方とも彼らのそれぞれのリリースノートの変更への曖昧な参照以外APIsの重要な変更点の彼らの図書館をユーザーに知らせる深刻な試みを試みるようではないと言わなければならない。 これは訂正される必要がある。 正しい方向のステップはであるとき取除かれたAPIの使用法新しいAPIがもたらされるまたは古いAPIの簡単な例を提供すること。

楽しみなさい!

応答を残しなさい