scriptlet の種類
インストール/アンインストール scriptlet
%pre%post%preun%postun
引数
FIXME
トリガー scriptlet
トリガー対象のパッケージにバージョン-リリースも指定できるが、 エポックは指定しても無視される。なんでだよ、クソが。
%trigger{un|in|postun} [[-n] <subpackage>] [-p <program>] -- <trigger>
%triggerin%triggerun%triggerpostun
%triggerin は別名 %trigger でもよいらしい(要確認)。
%triggerpostin は存在しない。
引数
FIXME
$1- Number of instances of the source (or triggered) package which will remain when the trigger has completed
$2- Number of instances of the target package which will remain when the trigger has completed
scriptlet の実行順序
アップグレード
-
新パッケージの
%pretransを実行。(FIXME: 正しい?) - 新パッケージの
%preを実行。$1 == 2 - 新パッケージのファイルをインストール。
- 新パッケージの
%postを実行。$1 == 2 - 他パッケージの
%triggerin -- 新パッケージ名 [バージョン条件]を実行。 (旧パッケージの%triggerinも含む) (FIXME: What values in$1and$2?) - 新パッケージの
%triggerin -- 新パッケージ名 [バージョン条件]を実行。 (FIXME: What values in$1and$2?) - 旧パッケージの
%triggerun -- 旧パッケージ名 [バージョン条件]を実行。 (FIXME: What values in$1and$2?) - 他パッケージの
%triggerun -- 旧パッケージ名 [バージョン条件]を実行。 (新パッケージの%triggerunも含む) (FIXME: What values in$1and$2?) - 旧パッケージの
%preunを実行。$1 == 1 - 旧パッケージのファイル (かつ新パッケージに含まれていないファイル) をアンインストール。
- 旧パッケージの
%postunを実行。$1 == 1 - 旧パッケージの
%triggerpostun -- 旧パッケージ名 [バージョン条件]を実行。 (FIXME: What values in$1and$2?) -
他パッケージの
%triggerpostun -- 旧パッケージ名 [バージョン条件]を実行。 (新パッケージの%triggerpostunも含む) (FIXME: What values in$1and$2?) - 新パッケージの
%posttransを実行。(FIXME: 正しい?)
FIXME: 他パッケージの %triggerfile* <パッケージファイル> のタイミングを調査。(RHEL 8 以降の RPM)
scriptlet の例
アッググレード後にサービスを再起動する
サービスの稼働中にパッケージをアッグレード (またはダウングレード) したときは、 scriptlet でサービスを再起動し、アップグレードを適用すべきである。
RPM SPEC の慣習では、サービスの再起動は %postun 行なう。しかし、%postun
はアッグレード 元 (旧バージョン内) に存在するものが実行される。
個人的にこれは気持ち悪く、好みではない。アップグレード 先 (新バージョン内)
が実行すべきだと思う。
アップグレード先パッケージの %post のタイミングでは
アップグレード元 (旧バージョン) パッケージのファイルが
アンインストールされていないため、適切なタイミングといえない。
アップグレード先パッケージの %triggerpostun で同一パッケージの
アンインストールをトリガーにすればよいのだが、RPM にバグがあるので
利用できない。
%triggerin -- %{name} < %{version}-%{release}is always triggered on upgrade · Issue #209 · rpm-software-management/rpm
アップグレード時に設定/データファイルの位置を変更する
%pre で新版のパスに移動しておくのが簡単でよいと思われるのだが、
パッケージに含まれている設定ファイルなどは新版インストール時に上書きしてしまうため、
アップグレード前の設定が失なわれてしまう。
%install
...
## 旧パスで新パスを辿れるようにしたい場合はパッケージにシンボリックリンクを含めておく
ln -s foo/foo-xxx.conf %{buildroot}%{_sysconfdir}/foo-xxx.conf
ln -s qux %{buildroot}%{_sharedstatedir}/foo/bar
...
%pre
if [[ $1 -eq 2 ]]; then ## Upgrade
## 退避するためにサービスを停止する必要がある場合
if systemctl is-active foo.service >/dev/null; then
touch %{_rundir}/foo.need_start.rpmtmp || exit $?
systemctl stop foo.service || exit $?
fi
if [[ -f %{_sysconfdir}/foo-xxx.conf && ! -f %{_sysconfdir}/foo/foo-xxx.conf ]]; then
cp -a %{_sysconfdir}/foo-xxx.conf{,.rpmtmp} || exit $?
fi
if [[ -d %{_sharedstatedir}/foo/bar && ! -e %{_sharedstatedir}/foo/qux ]]; then
mv %{_sharedstatedir}/foo/{bar,qux} || exit $?
fi
fi
%post
if [[ $1 -eq 2 ]]; then ## Upgrade
## 退避するためにサービスを停止した場合
if [[ -f %{_sysconfdir}/foo-xxx.conf.rpmtmp ]]; then
if ! diff %{_sysconfdir}/foo-xxx.conf.rpmtmp %{_sysconfdir}/foo/foo-xxx.conf >&/dev/null; then
cp -a %{_sysconfdir}/foo/foo-xxx.conf{,.rpmnew} || exit $?
mv %{_sysconfdir}/foo-xxx.conf.rpmtmp %{_sysconfdir}/foo/foo-xxx.conf || exit $?
else
rm -f %{_sysconfdir}/foo-xxx.conf.rpmtmp || exit $?
fi
fi
fi
%posttrans
if [[ -f %{_rundir}/foo.need_start.rpmtmp ]]; then
systemctl start foo.service || exit $?
rm %{_rundir}/foo.need_start.rpmtmp
fi
アップグレード時に新版で追加した設定ファイルを無効にする
既存パッケージの RPM SPEC を更新し、新たに設定ファイルを追加したとする。 旧版からのアップグレード時は、勝手に追加設定が有効にならないようにしたいことがある。
旧版からのアップグレード時に追加設定ファイルを無効化したい場合の scriptlet の実装方法。
## 「旧版のアンインストール処理後」をトリガーとするため、%triggerpostun に
## 自パッケージ名と新版のバージョン-リリース未満を条件に指定する。
%triggerpostun -- %{name} < 1.0-2.new
## このトリガーは旧版からのアップデート時にだけ実行される。
## 新版のバージョン-リリース未満をトリガー条件にしているため、
## インスール/アンインストール前後のパッケージ数 ($1, $2) を
## 評価する必要はない。
## 旧版のとき既に同名設定ファイルが存在する場合、新版での同名設定ファイルが
## %config なら上書きはせず、*.rpmsave に保存される。その場合は旧版の
## 設定ファイルが維持されるので、対処は不要。
##
## *.rpmsave がない場合は新版の設定ファイルが新たにインストール
## されるので、無効化する必要がある。
if [[ ! -f %{_sysconfdir}/foo.conf.rpmnew ]]; then
## 新版の設定ファイルをデフォルトのまま *.rpmnew に保存する。
## RPM は、旧版でカスタマイズされている設定ファイル、かつ
## 新版で追加あるいは更新がされた設定ファイルは、
## 新版の設定ファイルで上書きせずに、*.rpmnew としてインストールする。
## 以下で無効化するので、RPM の動作に倣う。
cp -a \
%{_sysconfdir}/foo.conf \
%{_sysconfdir}/foo.conf.rpmnew \
|| exit $?
## 新版の設定ファイルを無効化する。
## この例ではファイル内容をすべてコメントアウトしている。
sed \
-e 's/^/#/' \
<%{_sysconfdir}/foo.conf.rpmnew \
>%{_sysconfdir}/foo.conf \
|| exit $?
fi