背景
私自身のinitramfsを組み立てる必要があり、initスクリプトを書く前に必要なすべての作業を手動で(つまりインタラクティブシェルで)実行したいと思います。私の選択は、すべてのタスクに対してbusyboxを静的にリンクすることです。
私がすること
initramfs /bin にはビジボックス実行可能ファイルがあり、/bin: 'sh' -> /bin/busybox にあるシェルへのシンボリックリンクがあり、initramfs ルートに /bin/sh への init シンボリックリンクがあります。
私が得るもの
busyboxは名前が次のようになると思いinit
、Enterキーを押した後にプロンプトを表示しますPlease press Enter to activate this console.
。シェルに入りますが、PIDは1ではありません。 PID = 1のプロセスはですinit
。そのため、手動で行うことはできず、switch_root
メインシステムの起動を続行できません。
initramfsでbashをシェルとして正常に実行してみました。 PID = 1で実行され、実行が許可されましたswitch_root
。
質問
initramfsでPID = 1のインタラクティブなbusyboxシェルをどのように実行しますか?
答え1
TLDRの答え
init
すでに見つけたように、プログラムを選択したシェル(initramfsから)に単純にシンボリックリンクすることでこれを行うことができます。
「Busy Box」の問題
直面している問題はbusybox「機能」です。 Busybox は、コンパイル時に含めることを選択したすべてのユーティリティを単一の汎用実行可能ファイルとしてパッケージ化します。次に、シンボリックリンク名(ベクトルなど)に基づいてargv[0]
実行時に「サブユーティリティ」を起動します。
このテクノロジを使用すると、すべてのユーティリティを静的にリンクできます(DLLとも呼ばれるdylibは不要 - 非常に強力です)。破損したlibc(glibcなど)が原因でBusinessBoxが機能しないことは決してありません。ただし、コンパイルされたコードを共有できます。すべてのユーティリティが単一の実行可能ファイルにあるため、すべてのユーティリティは同じ共有関数(実行可能ファイルなどstrlen
)を直接呼び出すことができますprintf
。つまり、実行可能ファイルサブユーティリティの関数コードは互いに共有されます。すべてのユーティリティをDLLにあるように保存し、保存スペースを節約します(すべてのユーティリティ/コマンドを1つのファイルに含む1つのビジボックスバイナリのみが必要です。)機能 - 数十の個々の実行可能ファイルと同様に、全体の結果を小さくします。
ls
busyboxは、実行時にargvベクトルの0番目の位置を確認または["busybox", "ls"...]
確認して、["ls",..]
実行するサブユーティリティを決定します。
以前のシンボリックリンクが正しく(つまり$ PATHに)配置されている場合、つまり実行するのと同じです。実行するのは実行するのと同じですln -s busybox ls ; ./ls
。busybox ls
ls
シンボリックリンク名がに指定されている場合、カーネルによってinit
busyboxのベクトルに渡されます。これは、busyboxが呼び出されることを「確認」して実際のプログラムサブユーティリティで始まる名前です。argv[0]
init
解決策
問題を解決するには、次のようにします。
- テキストファイルの生成
/bin/init
- 実行可能としてマーク
- 次のようにコードを記述します。
#!/bin/sh
exec /bin/sh # this should replace current init process which is the sh interpreter from shebang above but with arg[0] of `init` with sh interpreter with argv[0] of `sh` - and this should be enough, to make busybox believe it should run `sh` sub-utility, which will end as PID1 because of `exec` in front.
sh
簡単に言えば、ビジボックスが自分の名前の付いたプロセスとして実行され、シェルのように動作するように説得する必要があります。
私の経験によれば、一時的なinitramfsesとinitのシナリオを開発するときは、/bin/init
実際のinitの実装を指し、2つのブートローダメニューを定義する方が効率的です。
- メニュー項目1:私の初期化から始める
init=/bin/sh
メニュー項目2:カーネルコマンドラインにLASTパラメータを追加してシェルの使用を開始します。
これにより、bootloader / qemuなどで目的のメニュー項目を選択するだけで、ブートモード(テスト実行、手動)を選択できます。