#navi_header|技術| RPMパッケージを作成する時の注意点とか、RPMで"/"(root)ディレクトリを変更してRPMの使うDBの構築やパッケージのインストールを行う場合の自分用メモ。 なお動作検証は CentOS 5.2, RPM 4.4.2 で行っている。 #more|| #outline|| 参考資料: - RPM Guide (Fedora Project) (rpm.orgのTracから"Packager Documentation"のリンク先がここになっている) -- http://docs.fedoraproject.org/drafts/rpm-guide-en/ - CentOS 5.2, RPM 4.4.2 のmanページ ---- * RPMパッケージ作成の注意点(ユーザ環境の準備作業周辺) CentOS 5.2 の場合、"/usr/src/redhat" 以下にRPMパッケージの作成やSRPMからのビルドに必要なディレクトリツリーが準備されている。 RPMパッケージを作成する場合は、誤ってシステム本体のファイルシステムやRPMデータベースに書き込んでしまわないよう、ユーザ環境でディレクトリツリーを準備する事が推奨されている。 そのための準備作業としては大まかに、以下のようになる。 + ユーザ環境でディレクトリツリーを準備 + "$HOME/.rpmmacros" に "%_topdir" マクロを登録し、ユーザ環境で用意したディレクトリを設定する。 実際にやってみる。まずディレクトリツリーの準備だが、幸いシステムのディレクトリツリーが空の状態だったので cpio を使ってごっそりコピーする。 $ pwd /usr/src/redhat $ find . -depth -print | cpio -pvd ~/in_vitro/rpmbuild/ /home/msakamoto/in_vitro/rpmbuild//./BUILD /home/msakamoto/in_vitro/rpmbuild//./SOURCES /home/msakamoto/in_vitro/rpmbuild//./RPMS/athlon /home/msakamoto/in_vitro/rpmbuild//./RPMS/i586 /home/msakamoto/in_vitro/rpmbuild//./RPMS/i686 /home/msakamoto/in_vitro/rpmbuild//./RPMS/noarch /home/msakamoto/in_vitro/rpmbuild//./RPMS/i486 /home/msakamoto/in_vitro/rpmbuild//./RPMS/i386 /home/msakamoto/in_vitro/rpmbuild//./RPMS /home/msakamoto/in_vitro/rpmbuild//./SPECS /home/msakamoto/in_vitro/rpmbuild//./SRPMS 0 blocks 続いて "$HOME/.rpmmacros"を次のように準備する。"%home"マクロについては、"/etc/rpm/macros" に入れておいても良いだろう。 $ cat .rpmmacros %home %{expand:%%(cd; pwd)} %_topdir %{home}/in_vitro/rpmbuild 確認してみる。 $ rpm --eval "%{home}" /home/msakamoto $ rpm --eval "%{_topdir}" /home/msakamoto/in_vitro/rpmbuild $ rpm --showrc | grep _topdir -14: _builddir %{_topdir}/BUILD -14: _rpmdir %{_topdir}/RPMS -14: _sourcedir %{_topdir}/SOURCES -14: _specdir %{_topdir}/SPECS -14: _srcrpmdir %{_topdir}/SRPMS -14: _topdir %{home}/in_vitro/rpmbuild 後は実際に "$HOME/in_vitro/rpmbuiild" ディレクトリの中でSPECファイルやソースファイル群を準備し、rpmbuildを実行すればよい。 なお今回検証したのはあくまでもspecファイルの作成からであり、SRPMのインストールからの作業は検証していない。SRPMのインストールでrpmコマンドを使って上記ユーザー環境にspecファイルやソースファイルを展開するのは不可能に思える。なぜなら、RPMコマンドの"--root"によりchrootして作業するのはroot権限で、一般ユーザではchroot(2)システムコールがエラーになってしまうからだ。 SRPMが手元にあり、そこからユーザー環境のディレクトリツリーでrpmbuildコマンドを実行したい場合は、一旦rpm2cpioでSPECファイルやソースファイル群を取り出した後手動で配置するべきかも知れない。 例: $ ls sample-1.0-1.src.rpm $ rpm2cpio sample-1.0-1.src.rpm | cpio -t sample-1.0.tar.gz sample.spec 531 blocks $ rpm2cpio sample-1.0-1.src.rpm | cpio -iv sample-1.0.tar.gz sample.spec 531 blocks $ ls sample-1.0-1.src.rpm sample-1.0.tar.gz sample.spec ちなみに自分は、当初勘違いして "$HOME/.rpmrc" に"%_topdir"設定を書いていて何度やってもエラーになってしまった。よくよくドキュメントを読み、"%"で始まるマクロ設定なので "$HOME/.rpmmacros" であることに気づくまで結構嵌ってしまった。 * RPMで"/"(root)ディレクトリを変更したりする場合のメモ 実験環境の構築などで、システムファイルやRPMデータベースの破壊を回避する為、一種のchroot環境を構築する場合を想定する。 rpmコマンドの "--root" オプションを使う事になるが、内部的に chroot(2) システムコールを使う為、root権限が必要になるので注意する。 基本的な流れとしては以下のようになる。なおファイル・ディレクトリパーミッション周りのトラブルを避ける為、基本的にroot権限で行う事を推奨する((そうなると「一般ユーザーで操作可能なRPM環境を準備する」というそもそもの結構ウェイトの大きい目的から外れてしまうが、chroot(2)周りで結局root権限のファイルが出来てしまうので仕方なかった。))。 + 好みの場所に "--root" オプションで指定するための chroot 用ディレクトリを作成する。 + chrootした中でさらにRPMの使うBerkeleyDB用のディレクトリを作成する。"--dbpath" で指定する事になる。 + "--root" と "--dbpath" を指定して "--initdb" によりDBを初期化する。 以降、パッケージのインストール・アップデート・削除などは "--root", "--dbpath" を指定する。 なお、"/var/lib/rpm"など元々のrpmコマンドが想定しているディレクトリをRPMのDB用に指定した場合は、"--dbpath"は不要。 以下、実際に試してみた例:"--root"が"/opt/rpmroot"で、"--dbpath"が"/var/lib/rpmtest"としてみた。 #pre||> $ su - # mkdir -p /opt/rpmroot # mkdir -p /opt/rpmroot/var/lib/rpmtest # rpm --initdb -vv --root /opt/rpmroot --dbpath /var/lib/rpmtest D: opening db environment /opt/rpmroot/var/lib/rpmtest/Packages create:cdb:mpool D: opening db index /opt/rpmroot/var/lib/rpmtest/Packages create mode=0x42 D: locked db index /opt/rpmroot/var/lib/rpmtest/Packages D: closed db index /opt/rpmroot/var/lib/rpmtest/Packages D: closed db environment /opt/rpmroot/var/lib/rpmtest/Packages D: May free Score board((nil)) # find /opt/rpmroot/var/lib /opt/rpmroot/var/lib /opt/rpmroot/var/lib/rpmtest /opt/rpmroot/var/lib/rpmtest/__db.001 /opt/rpmroot/var/lib/rpmtest/Packages /opt/rpmroot/var/lib/rpmtest/__db.000 /opt/rpmroot/var/lib/rpmtest/__db.003 /opt/rpmroot/var/lib/rpmtest/__db.002 ||< これでDBの初期化まで完了した。続いて、適当にでっち上げたRPMをインストールしてみる。 #pre||> # rpm -ivh -vv --nodeps --dbpath /var/lib/rpmtest --root /opt/rpmroot --test sample-1.0-1.i386.rpm D: ============== sample-1.0-1.i386.rpm D: Expected size: 11976 = lead(96)+sigs(180)+pad(4)+data(11696) D: Actual size: 11976 D: sample-1.0-1.i386.rpm: Header SHA1 digest: OK (6c105c09750403c748aaaa321e442518e98663a6) D: added binary package [0] D: found 0 source and 1 binary packages D: ========== recording tsort relations D: ========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth) D: 0 0 0 0 1 0 +sample-1.0-1.i386 D: installing binary packages D: opening db environment /opt/rpmroot/var/lib/rpmtest/Packages joinenv D: opening db index /opt/rpmroot/var/lib/rpmtest/Packages rdonly mode=0x0 D: locked db index /opt/rpmroot/var/lib/rpmtest/Packages D: mounted filesystems: D: i dev bsize bavail iavail mount point D: 0 0x0000fd00 4096 1212587 2269294 / D: 1 0x00000003 4096 0 -1 /proc D: 2 0x00000000 4096 0 -1 /sys D: 3 0x0000000b 4096 0 -1 /dev/pts D: 4 0x00000801 1024 72066 26060 /boot D: 5 0x00000012 4096 64436 64435 /dev/shm D: 6 0x00000013 4096 0 -1 /proc/sys/fs/binfmt_misc D: 7 0x00000014 4096 0 -1 /var/lib/nfs/rpc_pipefs D: sanity checking 1 elements D: opening db index /opt/rpmroot/var/lib/rpmtest/Name create mode=0x0 D: running pre-transaction scripts D: computing 5 file fingerprints Preparing... D: computing file dispositions D: opening db index /var/lib/rpmtest/Basenames create mode=0x0 ########################################### [100%] D: ========== +++ sample-1.0-1 i386-linux 0x1 D: Expected size: 11976 = lead(96)+sigs(180)+pad(4)+data(11696) D: Actual size: 11976 D: sample-1.0-1: Header SHA1 digest: OK (6c105c09750403c748aaaa321e442518e98663a6) D: install: sample-1.0-1 has 5 files, test = 1 D: running post-transaction scripts D: closed db index /opt/rpmroot/var/lib/rpmtest/Basenames D: closed db index /opt/rpmroot/var/lib/rpmtest/Name D: closed db index /opt/rpmroot/var/lib/rpmtest/Packages D: closed db environment /opt/rpmroot/var/lib/rpmtest/Packages D: May free Score board((nil)) ||< まだ"--test"付なので実際のインストールは行っていない。しかしこの段階でRPMデータベースディレクトリを覗いてみると、幾つかのインデックスファイルが作成されている事が分かる。 # find /opt/rpmroot/var/lib /opt/rpmroot/var/lib /opt/rpmroot/var/lib/rpmtest /opt/rpmroot/var/lib/rpmtest/__db.001 /opt/rpmroot/var/lib/rpmtest/Packages /opt/rpmroot/var/lib/rpmtest/__db.000 /opt/rpmroot/var/lib/rpmtest/__db.003 /opt/rpmroot/var/lib/rpmtest/Basenames /opt/rpmroot/var/lib/rpmtest/__db.002 /opt/rpmroot/var/lib/rpmtest/Name 実際にインストールしてみる。 #pre||> # rpm -ivh -vv --nodeps --dbpath /var/lib/rpmtest --root /opt/rpmroot sample-1.0-1.i386.rpm D: ============== sample-1.0-1.i386.rpm D: Expected size: 11976 = lead(96)+sigs(180)+pad(4)+data(11696) D: Actual size: 11976 D: sample-1.0-1.i386.rpm: Header SHA1 digest: OK (6c105c09750403c748aaaa321e442518e98663a6) D: added binary package [0] D: found 0 source and 1 binary packages D: ========== recording tsort relations D: ========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth) D: 0 0 0 0 1 0 +sample-1.0-1.i386 D: installing binary packages D: opening db environment /opt/rpmroot/var/lib/rpmtest/Packages joinenv D: opening db index /opt/rpmroot/var/lib/rpmtest/Packages create mode=0x42 D: locked db index /opt/rpmroot/var/lib/rpmtest/Packages D: mounted filesystems: D: i dev bsize bavail iavail mount point D: 0 0x0000fd00 4096 1212494 2269292 / D: 1 0x00000003 4096 0 -1 /proc D: 2 0x00000000 4096 0 -1 /sys D: 3 0x0000000b 4096 0 -1 /dev/pts D: 4 0x00000801 1024 72066 26060 /boot D: 5 0x00000012 4096 64436 64435 /dev/shm D: 6 0x00000013 4096 0 -1 /proc/sys/fs/binfmt_misc D: 7 0x00000014 4096 0 -1 /var/lib/nfs/rpc_pipefs D: sanity checking 1 elements D: opening db index /opt/rpmroot/var/lib/rpmtest/Name create mode=0x42 D: running pre-transaction scripts D: computing 5 file fingerprints Preparing... D: computing file dispositions D: opening db index /var/lib/rpmtest/Basenames create mode=0x42 ########################################### [100%] D: ========== +++ sample-1.0-1 i386-linux 0x1 D: Expected size: 11976 = lead(96)+sigs(180)+pad(4)+data(11696) D: Actual size: 11976 D: sample-1.0-1: Header SHA1 digest: OK (6c105c09750403c748aaaa321e442518e98663a6) D: install: sample-1.0-1 has 5 files, test = 0 1:sample D: ========== Directories not explicitly included in package: D: 0 /usr/bin/ D: 1 /usr/share/doc/ D: 3 /usr/share/locale/ja/LC_MESSAGES/ D: ========== D: /usr directory created with perms 0755, no context. D: /usr/bin directory created with perms 0755, no context. D: /usr/share directory created with perms 0755, no context. D: /usr/share/doc directory created with perms 0755, no context. D: /usr/share/locale directory created with perms 0755, no context. D: /usr/share/locale/ja directory created with perms 0755, no context. D: /usr/share/locale/ja/LC_MESSAGES directory created with perms 0755, no context. D: fini 100755 1 ( 0, 0) 3276 /usr/bin/sample;4b050e8d D: fini 040755 2 ( 0, 0) 0 /usr/share/doc/sample-1.0 D: fini 100644 1 ( 0, 0) 18002 /usr/share/doc/sample-1.0/COPYING;4b050e8d D: fini 100644 1 ( 0, 0) 0 /usr/share/doc/sample-1.0/README;4b050e8d ########################################### [100%] D: fini 100644 1 ( 0, 0) 618 /usr/share/locale/ja/LC_MESSAGES/sample.mo;4b050e8d GZDIO: 3 reads, 22740 total bytes in 0.002939 secs D: +++ h# 1 Header SHA1 digest: OK (6c105c09750403c748aaaa321e442518e98663a6) D: adding "sample" to Name index. D: adding 5 entries to Basenames index. D: opening db index /var/lib/rpmtest/Group create mode=0x42 D: adding "Applications/Text" to Group index. D: opening db index /var/lib/rpmtest/Requirename create mode=0x42 D: adding 5 entries to Requirename index. D: opening db index /var/lib/rpmtest/Providename create mode=0x42 D: adding "sample" to Providename index. D: opening db index /var/lib/rpmtest/Dirnames create mode=0x42 D: adding 4 entries to Dirnames index. D: opening db index /var/lib/rpmtest/Requireversion create mode=0x42 D: adding 5 entries to Requireversion index. D: opening db index /var/lib/rpmtest/Provideversion create mode=0x42 D: adding "1.0-1" to Provideversion index. D: opening db index /var/lib/rpmtest/Installtid create mode=0x42 D: adding 1 entries to Installtid index. D: opening db index /var/lib/rpmtest/Sigmd5 create mode=0x42 D: adding 1 entries to Sigmd5 index. D: opening db index /var/lib/rpmtest/Sha1header create mode=0x42 D: adding "6c105c09750403c748aaaa321e442518e98663a6" to Sha1header index. D: opening db index /var/lib/rpmtest/Filemd5s create mode=0x42 D: adding 5 entries to Filemd5s index. D: opening db index /var/lib/rpmtest/Triggername create mode=0x42 D: running post-transaction scripts D: closed db index /opt/rpmroot/var/lib/rpmtest/Filemd5s D: closed db index /opt/rpmroot/var/lib/rpmtest/Sha1header D: closed db index /opt/rpmroot/var/lib/rpmtest/Sigmd5 D: closed db index /opt/rpmroot/var/lib/rpmtest/Installtid D: closed db index /opt/rpmroot/var/lib/rpmtest/Provideversion D: closed db index /opt/rpmroot/var/lib/rpmtest/Requireversion D: closed db index /opt/rpmroot/var/lib/rpmtest/Dirnames D: closed db index /opt/rpmroot/var/lib/rpmtest/Triggername D: closed db index /opt/rpmroot/var/lib/rpmtest/Providename D: closed db index /opt/rpmroot/var/lib/rpmtest/Requirename D: closed db index /opt/rpmroot/var/lib/rpmtest/Group D: closed db index /opt/rpmroot/var/lib/rpmtest/Basenames D: closed db index /opt/rpmroot/var/lib/rpmtest/Name D: closed db index /opt/rpmroot/var/lib/rpmtest/Packages D: closed db environment /opt/rpmroot/var/lib/rpmtest/Packages D: May free Score board((nil)) ||< この段階で "/opt/rpmroot" 以下を見てみると、確かにディレクトリ階層とパッケージ中のファイルが配置された事が分かる。 #pre||> # find /opt/rpmroot /opt/rpmroot /opt/rpmroot/usr /opt/rpmroot/usr/bin /opt/rpmroot/usr/bin/sample /opt/rpmroot/usr/share /opt/rpmroot/usr/share/locale /opt/rpmroot/usr/share/locale/ja /opt/rpmroot/usr/share/locale/ja/LC_MESSAGES /opt/rpmroot/usr/share/locale/ja/LC_MESSAGES/sample.mo /opt/rpmroot/usr/share/doc /opt/rpmroot/usr/share/doc/sample-1.0 /opt/rpmroot/usr/share/doc/sample-1.0/COPYING /opt/rpmroot/usr/share/doc/sample-1.0/README /opt/rpmroot/var /opt/rpmroot/var/lib /opt/rpmroot/var/lib/rpmtest /opt/rpmroot/var/lib/rpmtest/Providename /opt/rpmroot/var/lib/rpmtest/__db.001 /opt/rpmroot/var/lib/rpmtest/Sigmd5 /opt/rpmroot/var/lib/rpmtest/Requirename /opt/rpmroot/var/lib/rpmtest/Triggername /opt/rpmroot/var/lib/rpmtest/Packages /opt/rpmroot/var/lib/rpmtest/Group /opt/rpmroot/var/lib/rpmtest/__db.000 /opt/rpmroot/var/lib/rpmtest/__db.003 /opt/rpmroot/var/lib/rpmtest/Filemd5s /opt/rpmroot/var/lib/rpmtest/Installtid /opt/rpmroot/var/lib/rpmtest/Basenames /opt/rpmroot/var/lib/rpmtest/__db.002 /opt/rpmroot/var/lib/rpmtest/Sha1header /opt/rpmroot/var/lib/rpmtest/Requireversion /opt/rpmroot/var/lib/rpmtest/Name /opt/rpmroot/var/lib/rpmtest/Dirnames /opt/rpmroot/var/lib/rpmtest/Provideversion ||< "relocatable"なRPMパッケージを作成すれば、chrootの必要性はある程度回避できるようになるが、それもパッケージの作者に依存してしまうので常に有効とは限らない。そうした場合にこのテクニックでシステムから分離してRPMを操作できるようになる。 ** 一般ユーザー権限だけで準備しようとするとchroot(2)絡みでエラーになり進めなくなる件 この記事を書こうとして"--initdb"周りの実験をやり始めた時、最初は一般ユーザでディレクトリを準備していた。 すると、どうしてもパッケージインストールのところでRPMデータベース中の "Basenames" ファイルの作成でエラーになってしまう。 #pre||> $ mkdir $HOME/rpmroot $ mkdir -p $HOME/rpmroot/var/lib/rpmtest $ rpm --initdb -vv --root $HOME/rpmroot --dbpath /var/lib/rpmtest D: opening db environment /home/msakamoto/rpmroot/var/lib/rpmtest/Packages create:cdb:mpool D: opening db index /home/msakamoto/rpmroot/var/lib/rpmtest/Packages create mode=0x42 D: locked db index /home/msakamoto/rpmroot/var/lib/rpmtest/Packages D: closed db index /home/msakamoto/rpmroot/var/lib/rpmtest/Packages D: closed db environment /home/msakamoto/rpmroot/var/lib/rpmtest/Packages D: May free Score board((nil)) $ find $HOME/rpmroot/var/lib/rpmtest /home/msakamoto/rpmroot/var/lib/rpmtest /home/msakamoto/rpmroot/var/lib/rpmtest/__db.001 /home/msakamoto/rpmroot/var/lib/rpmtest/Packages /home/msakamoto/rpmroot/var/lib/rpmtest/__db.000 /home/msakamoto/rpmroot/var/lib/rpmtest/__db.003 /home/msakamoto/rpmroot/var/lib/rpmtest/__db.002 ||< このように"--initdb"までは順調だが、実際にパッケージのインストールに進むと・・・ #pre||> $ rpm -ivh -vv --nodeps --dbpath /var/lib/rpmtest --root $HOME/rpmroot --test sample-1.0-1.i386.rpm D: ============== sample-1.0-1.i386.rpm D: Expected size: 11976 = lead(96)+sigs(180)+pad(4)+data(11696) D: Actual size: 11976 D: sample-1.0-1.i386.rpm: Header SHA1 digest: OK (6c105c09750403c748aaaa321e442518e98663a6) D: added binary package [0] D: found 0 source and 1 binary packages D: ========== recording tsort relations D: ========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth) D: 0 0 0 0 1 0 +sample-1.0-1.i386 D: installing binary packages D: opening db environment /home/msakamoto/rpmroot/var/lib/rpmtest/Packages joinenv D: opening db index /home/msakamoto/rpmroot/var/lib/rpmtest/Packages rdonly mode=0x0 D: locked db index /home/msakamoto/rpmroot/var/lib/rpmtest/Packages D: mounted filesystems: D: i dev bsize bavail iavail mount point D: 0 0x0000fd00 4096 1212504 2269294 / D: 1 0x00000003 4096 0 -1 /proc D: 2 0x00000000 4096 0 -1 /sys D: 3 0x0000000b 4096 0 -1 /dev/pts D: 4 0x00000801 1024 72066 26060 /boot D: 5 0x00000012 4096 64436 64435 /dev/shm D: 6 0x00000013 4096 0 -1 /proc/sys/fs/binfmt_misc D: 7 0x00000014 4096 0 -1 /var/lib/nfs/rpc_pipefs D: sanity checking 1 elements D: opening db index /home/msakamoto/rpmroot/var/lib/rpmtest/Name create mode=0x0 D: running pre-transaction scripts D: computing 5 file fingerprints Preparing... D: computing file dispositions D: opening db index /var/lib/rpmtest/Basenames rdonly mode=0x0 D: closed db index /var/lib/rpmtest/Basenames error: cannot open Basenames index using db3 - No such file or directory (2) セグメンテーション違反です ||< Basenamesファイルのopenで "No such file or directory" になってしまう。 ファイル名をよくよく見ると、PackagesとNameまでは "/home/..." となっており、Basenamesから "--root" で指定したchrootパスを除去したパス名になっている。 そのため最初は「RPMのバグかな?」と思っていたのだが、色々漁っている内に次の記事に突き当たった。 - http://markmail.org/thread/lalnffstoaczbeyf > Why not just run as root? ということで、「あ、chroot(2)って特権じゃないとだめ?」と今更ながらに気づいた((スミマセン、それまでchroot使った事無かったんです・・・))。 試しにstraceを使ってシステムコールとその結果を表示させてみたところ、確かにchroot(2)がEPERMを返している。 #pre||> $ strace rpm -ivh -vv --nodeps --dbpath /var/lib/rpmtest --root $HOME/rpmroot \ --test sample-1.0-1.i386.rpm 2>strace.log Preparing... $ more strace.log ... open("/home/msakamoto/rpmroot/var/lib/rpmtest/Name", O_RDONLY|O_LARGEFILE) = 4 ... chdir("/") = 0 chroot("/home/msakamoto/rpmroot/") = -1 EPERM (Operation not permitted) ... stat64("/var/lib/rpmtest/Basenames", 0xbfcb189c) = -1 ENOENT (No such file or directory) ||< これでようやく、一般ユーザ権限だけのRPM環境を準備する事は不可能で、root権限が必要だと判明した次第。 #navi_footer|技術|