web-dev-qa-db-ja.com

Linuxでは、initプロセスをシェルスクリプトにすることはできますか?

私は カスタムinitramfsの設定に関するチュートリアル を実行していました:

不足しているのは/ initだけです。これは、ロードされるとカーネルによって実行されるinitramfsのルートにある実行可能ファイルです。 sys-apps/busyboxには完全に機能するシェルが含まれているため、/ initバイナリを単純なシェルスクリプトとして記述できます(アセンブラーまたはCでコンパイルする必要のある複雑なアプリケーションにする必要はありません)。

#!/bin/busybox shで始まるシェルスクリプトとしてのinitの例を示します

これまでのところ、私はinitが起動されるメインプロセスであり、他のすべてのユーザー空間プロセスは最終的にinitの子であるという印象を受けました。ただし、この例では、最初のプロセスは実際にはbin/busybox/ shであり、そこから後でinitが生成されます。

これは正しい解釈ですか?たとえば、その時点で利用可能なインタープリターがあった場合、Pythonスクリプトなどとしてinitを書くことができますか?

15

initは(子プロセスとして)「生成」されるのではなく、execは次のようになります。

# Boot the real thing.
exec switch_root /mnt/root /sbin/init

execは所定のプロセス全体を置き換えます。 Initramfsのプロセスが先行していたとしても、最後のinitはまだ最初のプロセス(pid 1)です。

Initramfs /init、これはpid 1、execsをBusybox switch_rootに変換したBusyboxシェルスクリプトです(したがって、switch_rootはpid 1)。このプログラムは、/mnt/rootが新しい/になるようにマウントポイントを変更します。

switch_root次に、実際のルートファイルシステムのexecsから/sbin/initへ。これにより、実際のinitシステムがpid 1の最初のプロセスになり、任意の数の子プロセスが生成されます。

確かに、Pythonスクリプトを使用して、PythonをInitramfsに焼き付けた場合、とにかくbusyboxを含めると、その機能の一部(switch_rootなど、通常は単純なコマンドで実行するすべてのこと)を入念に再実装する必要があります。

ただし、スクリプトバイナリ(CONFIG_BINFMT_SCRIPT=y)を許可しないカーネルでは機能しません。そのような場合は、インタープリターを直接起動して、なんらかの方法でスクリプトをロードする必要があります。

13
frostschutz

Linuxカーネルのex​​ec syscallはネイティブでシバンを過小評価します

実行されたファイルがマジックバイト#!で始まる場合、カーネルは#!/bin/shを次のように使用するように指示します。

  • doおよびexecシステムコール
  • 実行可能ファイル/bin/sh
  • そしてCLI引数付き:現在のスクリプトへのパス

これは、通常のユーザーランドシェルスクリプトを次のように実行した場合とまったく同じです。

./myscript.sh

ファイルが.ELFではなくマジックバイト#!で始まっていた場合、カーネルは代わりにELFローダーを選択して実行します。

詳細: なぜ人々は#!/ usr/bin/env python ShebangをPythonスクリプトの最初の行に書くのですか? |スタックオーバーフロー

これを頭に入れておくと、/initは、シェルスクリプトを含め、カーネルが実行できるすべてのものであり、/bin/shがその場合の最初の実行可能ファイルになる理由を簡単に受け入れることができます。

試してみたい人のための最小限の実行可能な例を次に示します。 https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init