Plan 9とGo言語のブログ

主にPlan 9やGo言語の日々気づいたことを書きます。

Gitで9legacyのパッチを管理する

9legacyは「ベル研Plan 9最終版からのパッチ集」という位置付けです。更新がある場合、基本的には新しいパッチが追加されていきますが、パッチにバグがあった場合などはパッチ自体が更新されることもあります。そのため、手元の環境にパッチを適用したあと、次の更新を手元に適用するためには、過去に適用したパッチを元に戻してから再適用するなどの仕草が必要です。そのため現在は、直接パッチを手元の環境に適用するのではなく、9legacyが配布しているCDイメージを使って replica/pull する方法が推奨されています。

とはいえ自分自身でもPlan 9に手を入れているので、replica/pull で書き戻ってしまうと都合が悪いなどの事情があって、今はGitで差分を管理しています。この記事では、そのための手順をまとめます。

前提

事前に、以下2つのQEMUディスクイメージを用意しておきます。

disk1.rawベル研Plan 9を9legacyの安定版にアップデートするで、

インストールが終わったら、あとで使うためにインストール直後のdisk0.rawをバックアップしておきましょう。ここでは disk0-orig.raw とします。

と書いているところでバックアップしたディスクイメージです。この記事では説明の都合上 disk1.raw と呼称します。このディスクイメージは何度もインストール直後へ戻すことになるので、バックアップは残しておきましょう。

必要なツールのインストール

disk0.raw で起動して、Gitをインストールします。

$ ./start.bash -v
qemu-system-x86_64 -m 1G -smp 2 \
    -device virtio-scsi-pci,id=scsi \
    -device scsi-hd,drive=hd0 \
    -drive file=disk0.raw,format=raw,cache=writethrough,id=hd0,if=none,index=0 \
    -device virtio-net-pci,netdev=ether0 \
    -netdev user,id=ether0,net=10.0.2.0/24 \
    -machine type=pc,accel=hvf

386環境で使えるGitのバイナリは以下からダウンロードできるので、$home/bin/386 以下などに展開しておきましょう。

  • lufia.org/git-386.tgz

また、パッチの管理を簡単にするため、9legacy-toolもインストールしておくと便利だと思います。

9legacyの差分をGitリポジトリに書き出す

準備ができたら、disk0.rawdisk1.raw を接続した状態で仮想マシンを起動します。

$ ./start.bash -v -a disk1.raw 
qemu-system-x86_64 -m 1G -smp 2 \
    -device virtio-scsi-pci,id=scsi \
    -device scsi-hd,drive=hd0 \
    -drive file=disk0.raw,format=raw,cache=writethrough,id=hd0,if=none,index=0 \
    -device scsi-hd,drive=hd1 \
    -drive file=disk1.raw,format=raw,cache=writethrough,id=hd1,if=none,index=1 \
    -device virtio-net-pci,netdev=ether0 \
    -netdev user,id=ether0,net=10.0.2.0/24 \
    -machine type=pc,accel=hvf

起動直後は disk1.raw をマウントしていないので、disk1.raw/n/other にマウントします。

% con -l /srv/fscons
prompt: fsys other config /dev/sd01/fossil # virtioが無効な場合はsd01をsdC1に読み替える
prompt: fsys other open -AWPV
prompt: srv fossil
prompt: (ctl+\)
>>> q

% mount -n -c /srv/fossil /n/other other/active

これでインストール直後のPlan 9ファイルツリーを /n/other でアクセスできるようになります。以降は、このファイルツリーにパッチを適用していきます。

Gitリポジトリの準備(最初だけ)

ここで用意するもの

まずリポジトリを作成します。Gitのワーキングツリーは /n/other をそのまま使うので、Gitディレクトリ(ベアリポジトリ)だけ必要です。

% cd $home/lib
% mkdir dist.git
% git -C dist.git init --bare

# 必要なら
% git remote add origin https://github.com/xxx/xxx

dist.gitignore を準備します。ファイルの内容はgithub.com/lufia/plan9:.gitignoreです。/n/other は9legacyの更新があるたびにリセットするので、ここではまだ/n/other/.gitignore には置きません。

9legacyパッチの適用

9legacyのパッチを、/n/other 以下のファイルツリーに適用します。

% mkdir /tmp/20211208 # 作業用ディレクトリなので、どこでもいい
% cd /tmp/20211208
% 9legacy/init -r `{pwd}
% bind -c /n/other plan9
% 9legacy/update -r `{pwd}
% 9legacy/stable -r `{pwd} >o
% 9legacy/installall -n -r `{pwd} o
% cp $home/lib/dist.gitignore plan9/.gitignore

# libmemdraw-9kはalloc.cが1つのパッチで2回更新されるので、patchのテストが落ちる
# そのためテストを無視して適用する
% 9legacy/install -n -r `{pwd} -f libmemdraw-9k

# 残りのパッチを適用
% 9legacy/installall -n -r `{pwd} o

次に9kカーネルのパッチを当てます。

% 9legacy/9k -r `{pwd} >o
% 9legacy/installall -n -r `{pwd} o

必要なら、9legacyのページでOptionalとされているパッチを当てます。

% 9legacy/install -n -r `{pwd} libmux
% 9legacy/install -n -r `{pwd} libworker

ここまで終われば、/tmp/20211208 の作業ディレクトリは不要なので消しても問題ありません。

% unmount plan9 # unmountせずrmするとdisk1.rawのファイルツリーが消えてしまうので注意

差分をリポジトリにコミット

Gitディレクトリ(ベアリポジトリ)とワークツリーを分けた関係で、--git-dir--work-tree オプションを与えてあげる必要があります。何度も入力するのは面倒なのでシェル関数を作っておきます。

% fn x { git --git-dir $home/lib/dist.git --work-tree /n/other $* }

オプションの代わりに環境変数でも代用できます。

GIT_DIR=$home/lib/dist.git
GIT_WORK_TREE=/n/other

これで、前回のリポジトリ状態と /n/other の差分を扱えるようになるので、必要な変更をGitリポジトリに追加しましょう。

% cd /n/other
% x status
% x add path/to/file # 内容をみてgit addする
% x commit -m '2021-12-08'

# 必要なら
% x push

全部終わったら片付け。

% unmount /n/other

次回以降、9legacyのパッチが更新されたときは、disk1.raw をインストール直後のディスクイメージに戻して上記の手順を繰り返すと、差分だけをGitで管理できます。以下リポジトリstable ブランチに、9legacyの変更をpushしているので必要なら使ってください。

github.com

リポジトリの内容をPlan 9へ反映する

これで、9legacyのパッチを戻さなくても必要な差分を扱えるようになったので、次にGitリポジトリを使って手元の環境を更新する手順を紹介します。ここでは、アップデートしたいPlan 9のディスクを disk2.raw とします。

disk2.raw を起動ディスクとしてブートした後、上記で作成したリポジトリをcloneします。当然ですがGitコマンドが必要なので、disk1.raw の時と同様にインストールしておいてください。

//memo: rc; rfork ne; bind -a /usr/lufia/bin/386 /bin

% cd $home/lib
% git clone -b stable https://github.com/lufia/plan9.git

2回目以降はpullで更新します。

% cd $home/lib/plan9
% git pull origin stable

次に、Plan 9のルートディレクトリには、実行中にしか存在しない仮想的なファイル*1が含まれるので、それらを除いた disk2.raw の実態を /n/boot から参照できるようにします。

% echo 'srv -AWP replica' >>/srv/fscons # -Vオプションは不要

# 少し待ってからマウントする
% mount -c /srv/replica /n/boot

これで以下の準備ができました。

  • $home/lib/plan9
    • 最新の9legacyパッチを適用したリポジトリ(上の手順で作ったもの)
  • /n/boot
    • disk2.raw に保存されている素のファイルツリー

あとは git を使って、変更のあるファイルをリポジトリの状態にリストアしていけば、最終的には最新の9legacyファイルツリーへ更新できます。

% fn x { git --git-dir $home/lib/plan9/.git --work-tree /n/boot $* }
% cd /n/boot
% x status
% x restore .gitignore
% x restore path/to/file # 必要なだけ繰り返す

最後に片付けして終わり。

% unmount /n/boot
% rm /srv/replica

新しいソースコードでリビルド

あとは以下の記事と同じです。「ソースコードのリビルド」から先を参照してください。

blog.lufia.org

気になる人のためのメモ

Gitでリストアしたファイルのオーナーやグループは、リストアしたユーザーのものに切り替わります。一般的に、/sys 以下のオーナーは sys ユーザーなので、この差が気になる人は chgrp -u などで個別に変更するといいです。

うまくいかない場合

2021年末の時点で、Plan 9に移植したGitコマンドは(特にpull/pushでハングするなど)やや不安定です。そういった場合、以下の環境変数をセットしておくとトレースログとそれぞれの実行にかかった時間などを表示するので原因の調査に役立ちます。

*1:/mnt/dev など