既存のDebianパッケージをカスタマイズする

# 初めに

必要に迫られて既存のDebianパッケージをカスタマイズしたものを作成してみたので、その際の手順をまとめてみました。

# 背景

そもそものきっかけはDebian 11 (コードネーム bullseye)でpyspf-milterを利用しようとしたことでした。Bullseyeのpyspf-milterのバージョンは2.9.2なのですが、このバージョンには起動するとランタイムエラーが発生して異常終了するというバグがあります。この問題はDebianのバグ追跡システム(BTS)に[報告されていて](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1008828)、そこでこのパッケージのメンテナは

* この問題はtesting(とunstable)では修正済
* stableでも修正する予定である

と回答していますが、この記事を書いている時点ではまだstableは修正されていません。

またこれとは別に、設定ファイルに特定のオプションを指定するとエラーが発生して異常終了するというバグがあります。これはupstreamの最新バージョンである2.9.3にもあるバグで、upstreamのバグ追跡システムに[報告されていて](https://bugs.launchpad.net/spf-engine/+bug/1939598)、そこにこの問題を修正するためのパッチも添付されているのですが、まだ修正されていません。

そのためbullseyeでこの二つの問題を回避するためには

1. 前者の問題が修正されているtesting/unstableのパッケージのソースを取得する
1. 取得したソースに後者の問題を修正するパッチを追加する
1. 変更したソースからbullseye用のパッケージを作成する
1. 作成したパッケージをインストールして利用する

という手順が必要となるのですが、この記事では三番目のパッケージを作成するまでの手順を説明します。なお以下の説明では、全てはamd64なbullseyeの環境で行うものとします。

# 準備

自前でDebianパッケージを作成するには以下の3つの準備が必要となります。

* パッケージの作成に必要なDebianパッケージのインストール
* 作成したパッケージに署名するために用いるGnuPGの鍵の作成
* 環境設定

以下順に説明します。

## パッケージの作成に必要なDebianパッケージのインストール

パッケージの作成には以下の4つパッケージをインストールする必要があります。

* build-essential
* devscripts
* git
* wget

### build-essential

Debianパッケージに限らず、一般的にソフトウェアをビルドするにはコンパイラ、ライブラリ、ユーティリティなど様々なツールが必要になります。そして何が必要かはビルドするソフトウェアによって異なりますが、そのうちほとんどのDebianパッケージを作成する際に必要となるツールをインストールするためのパッケージがこのbuild-essentialです。Debianパッケージのソースには、そのパッケージを作成する際にインストールすべきパッケージを記述したファイルがあるのですが、build-essentialに含まれるパッケージについては、既にインストールされているものとみなして記述しなくてよいこととなっています。従ってDebianパッケージをし前で作成する際には、必ずこのパッケージをインストールする必要があります。

### devscripts

名前が示すように、このパッケージにはDebianパッケージの開発(既存のパッケージのカスタマイズだけでなく新規にパッケージを作成する場合も含む)を行うのに便利なツールが含まれています。

### git

既存のDebianパッケージをビルドするにはそのパッケージのソースを取得する必要があります。単純にそのままビルドするだけなら、`/etc/apt/sources.list`に

```
deb-src http://deb.debian.org/debian/ bullseye main non-free contrib
```

のような行を追加したうえで

```shell
apt source (パッケージ名)
```

を実行すれば、カレントディレクトリの下に必要なすべてのソースがダウンロードされます。しかしながら今回はソースを変更する必要があり、そしてその変更内容を保存しておきたいので、gitを利用してDebianパッケージのソースのリポジトリからソースを取得することとしました。

### wget

ソフトウェアのオリジナルのソースコードのアーカイブファイルを取得するのに使います。ファイルをダウンロードできるものなら、curlなどの別のツールやウェブブラウザでも構いません。

## GnuPGの鍵の作成

パッケージに署名するのに必要なGnuPGの鍵を作成します。作成したパッケージを`dpkg`コマンドを使って直接インストールするのなら必ずしも署名する必要はないのですが、今回は作成したパッケージを`apt install`でリポジトリからインストール出来るようにしたいので、そうなるとセキュリティの観点からパッケージに署名することにしました。

署名にはGnuPGを用いるので、GnuPGの鍵が必要となります。既に自分用の鍵があるのならそれを用いることも出来ますが、なければ以下のコマンドを実行して作成します。

```shell
gpg --generate-key
```

実行すると名前とメールアドレスを尋ねられます。以後の説明では名前が*Taro Yamada*でメールアドレスが*taro@examle.org*であるとします。名前とメールアドレスを入力すると確認を求められます。その後鍵のパスフレーズの入力が完了すると鍵が生成されます。

## 環境設定

パッケージの作成に用いるツールに必要な環境設定を行います。

### 環境変数

環境変数DEBEMAILにメールアドレスを、DEBFULLNAMEにフルネームを設定します。私はログインシェルとしてzshを使っているので、`~/.zshenv`に以下の行を追加しました。

```shell
export DEBEMAIL="taro@example.org"
export DEBFULLNAME="Taro Yamada"
```

他のシェルを使っている場合は、そのシェルに応じた設定を行ってください。

### devscripts

devscirpts関連の設定は`~/.devscripts`で行います。以下の3行からなる`~/.devscripts`を作成します。

```shell
DEBUILD_DPKG_BUILDPACKAGE_OPTS="-i -I -sa"
DEBUILD_LINTIAN_OPTS="-i -I --show-overrides"
DEBSIGN_KEYID="(署名に用いるGnuPGの鍵のIDの値)"
```

署名に用いるGnuPGの鍵のIDの値は、`gpg --list-keys --keyid-format long`を実行して確認します。例えば出力が以下の通りだったとします。

```
ppub   rsa3072/7F4DBC5AFC3010FF 2022-11-16 [SC] [expires: 2024-11-15]
      F954C7608427047664E784FC7F4DBC5AFC3010FF
uid                 [ultimate] Taro Yamada <taro@example.org>
sub   rsa3072/49AB5A578599DCA8 2022-11-16 [E] [expires: 2024-11-15]
```

この場合一行目の`7F4DBC5AFC3010FF`が鍵のIDの値となるので、これを指定します。

### git

コミットメッセージで用いられるメールアドレスとフルネームを設定します。

```shell
git config --global user.name "Taro Yamada"
git config --global user.email taro@example.com
```

# ソースの取得と確認

## ソースの取得

準備のところで説明した通り、今回はGitを使ってpyspf-milterのソースパッケージであるspf-engineのリポジトリからソースを取得します。作業を行うディレクトリに移動して以下のコマンドを実行します。

```shell
git clone https://salsa.debian.org/python-team/packages/spf-engine.git
```

完了するとカレントディレクトリの下の`spf-engine`というディレクトリにソースがダウンロードされます。ソースはデフォルトのブランチである`debian/master`の最新のコミットが取得されますが、現時点でこのコミットはtesting/unstableのpyspf-milterパッケージの最新バージョンである2.9.3-1より新しくなっています。なので2.9.3-1を基準にして新しいブランチを作成して、以降はそのブランチで作業をすることにします。

```shell
cd spf-engine
git switch -c custom debian/2.9.3-1
```

パッケージをビルドするにはこの他にSPF Engineのオリジナルのソースコードを含んだアーカイブファイルが必要なので、それをダウンロードします。

```shell
wget https://deb.debian.org/debian/pool/main/s/spf-engine/spf-engine_2.9.3.orig.tar.gz
```

結果として作業ディレクトリの下は以下のようになります。

```shell
% ls -F
spf-engine/  spf-engine_2.9.3.orig.tar.gz
%
``` 

これでソースの取得は完了です。

## ソースがビルド出来るかの確認

今回取得したのは現時点でのtesting及びunstableのバージョンである2.9.3をビルドするためのソースですが、一般的に言ってtestingやunstabeのためのソースがstableの環境で正常にビルド出来る保証はありません。そこでまずその確認を行います。ソースをビルドするには以下のコマンドを実行します。

```shell
cd spf-engine
debuild
```

初めてこれを実行した際には、大抵の場合ビルドに必要なパッケージがインストールされていないというエラーメッセージが表示されてビルドは失敗します。何をインストールする必要があるかはビルドする環境によって変わりますが、エラーメッセージで不足しているパッケージが表示されるので、それらをインストールしたうえで再度コマンドを実行すると、今度は特に問題なく正常にビルドが完了します。ソースがstable環境でビルドできることが確認できたのでソースのディレクトリを元の状態に戻します。

```shell
rm -rf *.deb spf-engine_2.9.3-1*
cd spf-engine
git clean -dfx
git restore .
```

# パッケージのカスタマイズ

## パッチの追加

背景で説明した通り、stable(2.9.2-1)のpyspf-milterパッケージの二つのバグのうち、一つはtesting/unstable(2.9.3-1)で修正されていますが、もう一つはまだ修正されていません。そこで後者を修正するパッチを追加します。これも背景で説明した通り、この件に関するupstreamのバグ追跡システムへのバグ報告には問題を修正するパッチが添付されているのですが、Debianのspf-engineのソースには直接適用できないので、オリジナルを参考にして以下のようなパッチを作成しました。

```diff
diff --git a/spf_engine/policydspfsupp.py b/spf_engine/policydspfsupp.py
index 8ba8e6c..4ebca3f 100644
--- a/spf_engine/policydspfsupp.py
+++ b/spf_engine/policydspfsupp.py
@@ -153,9 +153,9 @@ def _readConfigFile(path, configData = None, configGlobal = {}):
             'Socket': str,
             'PidFile': str,
             'UserID': str,
-            'UMask': 'int',
+            'UMask': int,
             'InternalHosts': str,
-            'IntHosts': 'bool',
+            'IntHosts': bool,
             'MacroListVerify': str,
             }
```

これを`spf-engine/debian/patches`の下に`0901-fix-runtime-error.patch`というファイル名で置きます。

パッケージをビルドする際に適用するパッチの一覧は`spf-engine/debian/patches/series`というファイルで管理されています。現時点でのこのファイルの内容は

```
0001-install-conf-fix.patch
```

となっているので、ここに追加したパッチのファイル名を

```
0001-install-conf-fix.patch
0901-fix-runtime-error.patch
```

のように追加します。

## 変更履歴の更新

次にDebianパッケージの変更履歴を管理しているファイルである`spf-engine/debian/changelog`を更新します。更新には専用のコマンドである`dch`を使用します。私はspf-engineパッケージのメンテナではないので、今回の更新はNMU(Non Maintainer Upload)に相当します。そこで

```shell
cd spf-engine
dch --nmu
```

のように、`spf-engine`ディレクトリに移動した後に`dch`を`--nmu`オプションを指定して実行します。するとエディタが起動されてファイルの先頭に以下のような行が追加されます。

```
spf-engine (2.9.3-2.1) UNRELEASED; urgency=medium

  * Non-maintainer upload.
  *  

 -- Taro Yamada <taro@example.org>  Thu, 17 Nov 2022 15:13:59 +0900
```

これを例えば以下のようにしてエディタを終了します。

```
spf-engine (2.9.3-2.1) UNRELEASED; urgency=medium

  * Non-maintainer upload.
  * Add patch to fix runtime error of pyspf-milter. 

 -- Taro Yamada <taro@example.org>  Thu, 17 Nov 2022 15:13:59 +0900
```

## パッケージのビルド

ビルドの確認の時と同様に

```shell
cd spf-engine
debuild
```

とするとビルドが正常に完了して、作業ディレクトリにカスタマイズされたパッケージが生成されます。

```shell
% ls -1F
pyspf-milter_2.9.3-1.1_all.deb
python3-spf-engine_2.9.3-1.1_all.deb
spf-engine/
spf-engine_2.9.3-1.1.debian.tar.xz
spf-engine_2.9.3-1.1.dsc
spf-engine_2.9.3-1.1_amd64.build
spf-engine_2.9.3-1.1_amd64.buildinfo
spf-engine_2.9.3-1.1_amd64.changes
spf-engine_2.9.3.orig.tar.gz
%
```

## 変更内容の保存

変更が正しく動作されることが確認されたので、変更内容をコミットします。

```shell
cd spf-engine
git add debian/changelog debian/patches/0901-fix-runtime-error.patch debian/patches/series
git commit
```

# パッケージのバックポート

作成されたパッケージをそのまま利用しても問題ないのですが、testing/unstableのバージョンをstableに移植したことを明確にするために、バックポートの処理を行います。ソースがstableでビルド出来るかを確認した後と同じ手順で作業ディレクトリを片付けた後に以下のコマンドを実行します。

```shell
cd spf-engine
dch --bpo
```

するとエディタが起動されてファイルの先頭に以下のような行が追加されます。

```
spf-engine (2.9.3-1.1~bpo11+1) bullseye-backports; urgency=medium

  * Rebuild for bullseye-backports.
  * 

 -- Taro Yamada <taro@example.org>  Thu, 17 Nov 2022 16:35:19 +0900
```

今回は単純にビルドしなおすだけなので、以下のように編集します。

```
spf-engine (2.9.3-1.1~bpo11+1) bullseye-backports; urgency=medium

  * Rebuild for bullseye-backports.

 -- Taro Yamada <taro@example.org>  Thu, 17 Nov 2022 16:35:19 +0900
```

エディタを終了して再度`debuild`を実行してパッケージをビルドします。ビルドが完了すると作業ディレクトリの下にバックポートされたパッケージが生成されます。

```shell
% ls -1F
postfix-policyd-spf-python_2.9.3-1.1~bpo11+1_all.deb
pyspf-milter_2.9.3-1.1~bpo11+1_all.deb
python3-spf-engine_2.9.3-1.1~bpo11+1_all.deb
spf-engine/
spf-engine_2.9.3-1.1~bpo11+1.debian.tar.xz
spf-engine_2.9.3-1.1~bpo11+1.dsc
spf-engine_2.9.3-1.1~bpo11+1_amd64.build
spf-engine_2.9.3-1.1~bpo11+1_amd64.buildinfo
spf-engine_2.9.3-1.1~bpo11+1_amd64.changes
spf-engine_2.9.3.orig.tar.gz
```

生成されたパッケージが2.9.3-1.1~bpo11+1となっているので、バックポートされたものであることがわかります。

バックポートに成功したので、変更内容の更新をコミットしておきます。

```shell
cd spf-engine
git add git add debian/changelog
git commit
```

# まとめ

既存のDebianパッケージをカスタマイズする方法についてまとめました。これから同様のことを行おうとする方の参考になれば幸いです。

# 参考文献

1. [Debian メンテナー用ガイド](https://www.debian.org/doc/manuals/debmake-doc/ "Debian メンテナー用ガイド")
1. [Debian パッケージングチュートリアル](https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial.ja.pdf "Debian パッケージングチュートリアル")
1. [第150回 東京エリア Debian 勉強会資料](https://tokyodebian-team.pages.debian.net/pdf2017/debianmeetingresume201704.pdf "第150回 東京エリア Debian 勉強会資料")