Linuxディストリビューションを作成していますが、今はinitプログラムが必要です。私はcで非常にうまくコーディングでき、linuxについてはかなり知っています(ただし、開発にArch Linuxを4年間使用しています)。したがって、Cで独自の基本的なinitスクリプトを作成する必要があると考えました。疑問に思って、単純なシェル用にシステムをセットアップするためにinitが実行するタスクは何ですか? (「initの機能は何ですか?」
コードは必要ありませんし、基本的なコマンドすら必要ないかもしれませんが、doが実行される順序が必要です。
init
は、ストーリーのほんの一部しか伝えません。Linuxの世界に影響を与える一種の近視があります。人々は、「システム5 init
」というものを使用していると考えています。これが伝統的であり、開始するのに最適な場所です。どちらも実際にはそうではありません。
手始めに、伝統は実際にそのような人々がそれがそうであると言うものではありません。 System 5 init
とSystem 5 rc
は、AT&T UNIX System 5の日付です。これは、最初のバージョンのLinux-Mandrakeの後(現在のところ)と同じくらい、最初のUNIXのあとです。
1st Edition UNIXにはinit
しかありませんでした。 rc
がありませんでした。第1版のアセンブリ言語init
( そのコード は Warren Toomeyらによって復元され、利用可能になりました )12のgetty
プロセスを直接生成および再生成し、3つのハードワイヤードファイルシステムを組み込みテーブルを使用して、mel
という名前のユーザーのホームディレクトリから直接プログラムを実行しました。 getty
テーブルも直接プログラムイメージにありました。
いわゆる「伝統的な」Linux initシステムが登場したのは、UNIXシステム5の次の10年でした。 1992年に、Miquel van SmoorenburgはLinux init
+ rc
とそれに関連するツールを(再)作成しました。これは、実際にはUNIX System 5のソフトウェアではありませんが、「System 5 init
」と呼ばれています( 「init
」だけではありません)。
System 5 init
/rc
は、開始するのに最適な場所ではありません。また、systemdの知識を追加しても、知っていることの半分をカバーしていません。 initシステム設計(LinuxおよびBSDの場合)の分野では、過去20年間だけで多くの作業が行われてきました。あらゆる種類の工学的決定が議論され、行われ、設計され、実装され、実践されてきました。商業Unicesも多くのことを行いました。
以下に、主要な初期システム以外のいくつかの不完全なリストを示しますそれらの2つと、それらの(いくつかの)特徴点の1つまたは2つ:
init
が開始するもの間の起動/停止の依存関係に取り組みました。getty
の生成とゾンビの刈り取りを含む)を個別のサービスマネージャーにプッシュすること、およびjustオペレーティングシステム固有の「API」デバイス/シンボリックリンク/ディレクトリおよびシステムイベントの処理。/bin/rc.init
_を実行します。このためには、 minirc のようなものを使用できます。さらに、約10年前、daemontoolsのユーザーと他の人の間で、プロセス#1としてsvscan
を使用することについての議論があり、 Paul Jarcのsvscan as process 1 study 、 Gerrit Papeのアイデア) 、および Laurent Bercotのプロセス1としてのsvscan 。
これにより、#1プログラムが実行するプロセスがわかります。
どのプロセス#1が「想定される」かという概念は、その性質上主観的なものです。意味のある目的設計基準は、プロセス#1で最低限実行する必要があるです。カーネルはいくつかの要件を課しています。また、オペレーティングシステム固有のさまざまな処理が常に行われています。プロセス#1が伝統的に行ったことについては、その最低限ではなく、実際に行われたことはありません。
さまざまなオペレーティングシステムカーネルや他のプログラムがプロセス#1に要求するいくつかのことがあり、それを回避することはできません。
人々はfork()
ingを行い、孤立したプロセスの親として機能することがプロセス#1の主要な機能であると言うでしょう。皮肉なことに、これは正しくありません。孤立したプロセスの処理は(最近のLinuxカーネルでは https://unix.stackexchange.com/a/177361/5132 で説明されているように)プロセスの大部分をファクタリングできるシステムの一部です#専用サービスマネージャなどの他のプロセスに1。これらはすべて、プロセス#1で実行されるサービスマネージャーです。
srcmstr
プログラム、 システムリソースコントローラーrunsvdir
from runitsvscan
from daemontools、Adam Sampsonのsvscan
from freedt 、Bruce Guenter's svscan
from daemontools-encore、およびLaurent Bercot's _s6-svscan
_ s6からperpd
from perpservice-manager
_同様に、 https://superuser.com/a/888936/38062 で説明されているように、_/dev/initctl
_のアイデア全体がプロセス#1の近くにある必要はありません。皮肉なことに、高度に集中化されたsystemdは、プロセス#1の外に移動できることを示しています。
逆に、人々が最初から頭の設計で忘れているinit
の必須事項は、カーネルから送信されたSIGINT
、SIGPWR
、SIGWINCH
などの処理やさまざまなシステムの制定などです。 #1を処理する特定のシグナルが特定のことを意味することを「知っている」プログラムから送信される状態変更要求。 (例: https://unix.stackexchange.com/a/196471/5132 で説明されているように、BSDツールセットは_SIGUSR1
_が特定の意味を持つことを「認識」しています。)
"API" filesystems をマウントしたり、ファイルシステムキャッシュをフラッシュしたりするなど、1回限りの初期化タスクとファイナライズタスクがあり、エスケープできないか、実行しないと大幅に影響を受けます。
「API」ファイルシステムの処理の基本は、init
rom 1st Edition UNIXの操作と少し異なります。1つはプログラムに組み込まれた情報のリストを持ち、もう1つはリストのすべてのエントリを単にmount()
sします。このメカニズムは、BSD(sic!)init
からnosh _system-manager
_を介してsystemdまで、さまざまなシステムで見つかります。
あなたが観察したように、_init=/bin/sh
_は「API」ファイルシステムをマウントせず、exit
( https://unix.stackexchange.com/a/ 195978/5132 )、そして一般に、システムを最小限にしか使用できないようにするアクションを手動で実行する(スーパー)ユーザーに任せます。
プロセス#1プログラムで実際に行う以外に選択肢がないことを確認し、指定された設計目標に適したコースに設定するには、Gerrit Papeのrunit、Felix vonの操作の重複を確認するのが最善の方法です。 Leitnerのminit、およびnoshパッケージの_system-manager
_プログラム。前者の2つは、ミニマリストになるための2つの試みを示していますが、それでも避けられないものを処理しています。
後者は、_system-manager
_プログラムの広範な手動エントリに役立ちます。これは、どの「API」ファイルシステムがマウントされ、どの初期化タスクが実行され、どのシグナルが処理されるかを正確に示します。 設計によってシステムマネージャーがシステムマネージャーに他の3つのもの(サービスマネージャー、付随するロガー、および状態変更を実行するプログラム)を生成するシステム)そして、プロセス#1で避けられないことのみを実行します。
DebianのSystem V init(他のバリアントとバリエーションがあります)は次のことを行います:
/etc/rcX.d/S*
のスクリプトを英数字順に呼び出します。ここで、X
はランレベルです。これらのスクリプトは、ランレベルを設定する必要があります。典型的なセットアップは、デーモンの開始であり、その実行レベルのセットアップタスクを実行します。これは、ランレベルに入るときに一度だけ行われることです。/etc/inittab
にリストされているデーモンを起動します。このデーモンは、その実行レベル中にアクティブである必要があります。これらのデーモンが実行を停止すると、再起動されます。 init
で管理するデーモンはどれでも構いませんが、少なくともいくつかのgetty
が必要なので、ログインできます。getty
は、ログインが完了すると終了します。次に、init
が再起動し、新しいログインプロンプトを表示します。init
が自動的に実行を継続しようとするわけではありません。 /etc/inittab
で個別に指定する必要があります。/etc/rcX.d/K*
のスクリプトを英数字順に呼び出します。ここで、X
はランレベルです。シャットダウンまたは再起動を実装する方法は、それらのイベントのランレベルを定義し、最後のタスクがhalt
またはreboot
コマンドを実行するようにすることです。したがって、必要に応じてinit
を基本的なサービスマネージャーとして使用できますが、最近の主なタスクは、ユーザーがログインしてランレベルの移行を開始できるようにgetty
を利用できるようにすることです。
私はただ疑問に思っていました、単純なシェル用にシステムをセットアップするためにinitはどのようなタスクを行うのですか?
あなたが望むものなら、なんでも。 Debianでは、各/etc/rcX.d
ディレクトリには/etc/init.d
内のスクリプトへのシンボリックリンクがあり、これらのスクリプトを完全にカスタマイズまたは削除できます。順序は、各スクリプトの前に00
、01
などを付けることで確立されます。
init
にシェルを生成させたいだけの場合は、init
に-b
オプションを指定することもできます(つまり、カーネルコマンドラインを介して)。シェルを終了すると、init
が終了し、init
が終了すると、カーネルがパニックになります。
Initが行う必要のある最低限のことは、少なくとも1つの他のプログラムを実行し、終了しないことです。 initが終了すると、システムがクラッシュします。他の1つのプログラムを実行することさえも厳密には必要ではないと思いますが、そうしないと、initはシステムが実行することが期待されるすべてのことを実行する責任を負う必要があるか、またはあまり役に立ちません。
init
はあなたがやりたいことを何でもできます
initは、ブートプロセスの最後にLinuxカーネルによって呼び出される任意の実行可能ファイルです(そのような実行可能ファイルは1つだけです)。
通常はELF実行可能ファイルとして実装されますが、chmod +x
を使用したシェルスクリプトにすることもできます。 シェルスクリプトとして初期化
Sysemdのような一般的な実装では、構成ファイルofen /etc/initrc
を読み取り、それらの構成に基づいて一連のユーザーランドプロセスを分岐し、システムのさまざまな側面を実装します。
ただし、これは完全に実装固有であるため、特定の実装を指定せずに質問に答えることはできません。たとえば、私は教育目的で単に init
syscall を実行するreboot
プロセスで遊んでいます。
Linuxカーネルは、デフォルトでパス/init
で実行可能ファイルを探すだけですが、これはinit=
Linuxカーネルコマンドラインパラメータで上書きできます。
init
をいじる優れた方法の1つは、QEMUを使用することです。これは、カーネルコマンドラインパラメーターを-append
オプションを使用してQEMUコマンドラインからQEMUに渡すことができるため、デスクトップ。
これが私の 最小限の完全に自動化されたBuildroot + QEMUセットアップ です。これにより、問題をわかりやすく説明するために、自分のinitを非常に簡単に操作できます。
モジュール化された「1つのことをうまく実行する」という原則に取り組んでいる場合、init
プログラムがプロセスを開始するはずです。
カーネルが正常に解凍されたら、システムの動作に必要なすべての初期プロセスの初期化に関連するすべての基本的なタスク(/ etc/fstabにあるドライブのマウント、ネットワークインターフェイスの起動など)に注意して実行する必要があります。など)。
起動とシャットダウンのプロセスは本質的に互いに逆であるため、initコマンドがシャットダウンコマンドでプロセスが確実に停止されるようにすることも一般的です。
つまり、そのプロセスのmanページに従ってプロセスを停止し(つまり、露骨なkill -9
ではなく、プロセスを停止したい方法で停止させる)、ドライブをアンマウントして、最終的に発行する必要があります。最後の電源切断コマンド。
これが他の人によってどのように行われるかについての良い参照は、 Slackwareの/etc/rc.dスクリプト と、 ninit のようなすでに存在する単純なinitシステムを調べることです。 (minitの後継)。プロセスの監視(プロセスが停止すると再起動されることを意味します)があり、それは間違いなくinitの仕事ではありませんが、特に作成者のサンプルスクリプトを通して、それは非常に基本的で理解が簡単です。