sysupgradeのシーケンス
https://openwrt.org/docs/techref/sysupgrade#how_it_works
sysupgradeプロセスは、/sbin/sysupgradeの実行から始まります。以下に、その動作について説明します。
1. コマンドラインを解析し、互いに排他的なオプションが渡されていないことを確認します。
2. この時点で、sysupgradeは include /lib/upgradeを呼び出します。これは/lib/functions.sh内の関数で、指定されたディレクトリ内のすべての *.sh ファイルをソースにします。
注意: オプションとして、プラットフォーム固有の/lib/upgrade/platform.shが動作を上書きすることがあるため、完全に理解するにはこのファイルを確認する必要があります。(ソースツリー内ではtarget/linux/<arch>/<sub-arch>/base-files/lib/upgrade/platform.shを参照してください。)
リストの最後には、オプションの関数としてplatform_copy_configとplatform_do_upgradeが存在します。
3. 保存するファイルのリストを作成し、/tmp/sysupgrade.tgzに保存します(-fオプションが指定されていない場合)。
4. もし指定されたイメージがhttpまたはhttpsのURLである場合は、wgetを使用して取得します。
5. ファームウェアイメージは(URLの場合)保存されるか、/tmp/sysupgrade.imgにコピーされます。
6. ファームウェアイメージが検証され、デバイスツリーファイル内のルート compatible ノードが、既存のファームウェアのデバイスツリーからの/sys/firmware/devicetree/base/compatibleの値と一致するか確認されます(-Fで上書き可能)。
7. /sbin/upgraded が/tmpにコピーされます。
8. JSONメッセージを作成し、ubus経由でprocdにメッセージを送信し、アップグレードを開始します。メッセージには以下の内容が含まれます:
path: /tmp/sysupgrade.img
backup: 保存するファイルがある場合は/tmp/sysupgrade.tgz、ない場合は未設定
force: -Fが指定されている場合
command: /lib/upgrade/do_stage2
9. procd内のsysupgrade関数はメッセージを展開し、ファームウェアイメージなどを検証します。
10. 注目すべきは、ここでprocdはサービスを終了しない点です。
11. ここから事態が変わります! すべてが正常であれば、sysupgrade_exec_upgradedが呼び出され、元のJSONをさらに解析し、execvpを介して/sbin/upgradedに制御を渡します。
ブート時に、カーネルは/sbin/initをPID=1として実行し、そこから/sbin/procdを実行(exec)します。このため、/tmp/upgradedが新しいPID=1("init")プロセスになります。
この時点では、サービス管理はもはや可能ではありません。
12. /sbin/upgradedは、渡されたコマンド(/lib/upgrade/stage2)を実行します。残りの手順は、このシェルスクリプトから実行されます。
/bin/sh /lib/upgrade/stage2はfork/execを通じて実行されるため、PID1ではありません。
13. すべてのtelnet、ash、およびdropbearプロセスを終了します(SIGKILL)。
14. 残りのすべてのプロセスに対して、TERMシグナルを送信します。
15. 残りのすべてのプロセスに対して、KILLシグナルを送信します。
16. 新しいRAMファイルシステムを作成し、それをマウントし、少数のバイナリをそこにコピーします。
17. 新しいRAMファイルシステムにルートを変更します。
18. /overlayを読み取り専用で再マウントし、遅延アンマウントします。
19. 新しいファームウェアをディスクに書き込みます。platform_do_upgradeが定義されていればそれを実行します。定義されていない場合、default_do_upgradeを使用してmtdでファームウェアをフラッシュします。
20. 保存するファイルがある場合、tarballはmtdの-jオプションを使用して渡されます。これにより、mtdはraw jffs2 inode(id=1)とファイルデータを書き込み、jffs2ファイルシステムがマウントされると/sysupgrade.tgzとしてtarballが表示されます。
この結果、mtdのソースはjffs2実装と密接に結びついており、カーネルのjffs2に変更が加えられると問題が発生する可能性があります(おそらくソースツリーにコピーする代わりに、カーネルのmake headers_installで生成されるuapiヘッダーを使用すべきです)。
再起動後、このファイルは/lib/preinit/80_mount_rootによって展開されます(preinitの最中の/sbin/init→ /bin/sh /etc/preinit → /lib/preinit/80_mount_root)。
最終的に/etc/rc.d/S95doneによって削除されます(/sbin/procd → STATE_INIT→ procd_inittab_run("sysinit"); → /etc/inittab)。
21. platform_copy_configが実装されている場合、この時点で実行されます。
22. 残りのファイルシステムをアンマウントします。
23. 再起動します。