Init(systemd)が起動してからXが出てくるまでの道のり

あまり触れられることのない、OSとしてのLinuxの起動プロセスを見てみます。

結構間違っているところがある気がするので、遠慮なくマサカリを投げてください、待ってます。

# プロローグ：ブートローダーがinitを起動する

BIOSから起動された、GRUBなどのブートローダーは、ディスクとvmlinuz、initramfsを発見します。


ext4やBtrfsなどの対応するハードウェアを読み込み、ファイルが無事発見されると、その後のCPUの特権モードで実行したまま、vmlinuzが読み込まれたメモリにジャンプします。
また、そのときにinitramfsがメモリにロードされ、いくつかの処理が実行されます。

これは、Linuxを起動するための簡易Linuxで、/etcや/binなどが存在し、必要最低限のバイナリが保管されているものです。通常はここで、Linuxを起動するための最低限のカーネルモジュール、つまりハードウェアに対応するドライバの読み込みや、ファイルシステムのfsckや、暗号化の解除などを行います。

準備ができると、initramfsから/usr/lib/systemd/systemdが実行され、通常のLinuxユーザーランドが起動します。

# systemd (init)

昔はInitと呼ばれるプロセスがPID=1で起動し、シェルスクリプトを実行しましたが、現在では主なディストリビューションではsystemdに置き換えられています。

systemdは、Unitと呼ばれるファイルを読み込み、各プロセスを起動します。
ここからは、起動されるUnitを解説します。

## systemd-journald

最初のほうでは、journaldが起動します。
journaldは、ジャーナル、つまりログを管理するプロセスです。journalctlコマンドで表示ができます。
主に、各Unitが表示するエラーメッセージや情報を、集約し、ユーザーが見やすく整形します。

## systemd-vconsole-setup

これは、ttyと呼ばれる、Linux OSが外部と会話する窓口を準備するものです。
Xが起動する前に起動ログが表示される画面がありますが、あれを提供しています。
他にも、パラレルポートなどの古いハードウェアでttyを提供することも可能です。

## udev

udevは、主に/dev以下に配置される仮想ファイルシステムを提供するものです。
マシンに新しい機器が接続されると、カーネルがudevを叩き起こします。udevは、そのマシンに適合するドライバやカーネルモジュールを見つけてきて読み込み、適切な仮想ファイルを/dev以下に配置します。

PCIe機器の認識や、NICの初期化などはここで行われます。

## systemd-networkd
これらは、ネットワークに接続するためのUnitです。systemd-networkdは一例で、大体の場合はここでNetworkManagerやnetctlが起動します。

systemd-networkd/NetworkManager/netctlは、NICのリンクアップ、ネゴシエーション、アクセスポイントの検索、接続などを担当します。
その後、DHCPを取得する場合は、dhcpcdやdhclientをさらに呼び出します。
Wifiなどを使う場合は、暗号化などのためにwpa_supplicantが起動されます。

## systemd-logind

systemd-logindは、ログイン画面や、ユーザー管理を担当するUnitです。
無事ユーザーランドが起動しきったあとに、ログイン画面を表示したり、マシンのttyでそれぞれどのユーザーがログインしているかを把握したり、X Window systemを使う場合には、ユーザーがttyが起動しているデバイスで自由にピクセル描画できるかどうかの許可なども行います。

また、gettyと呼ばれる、キー入力や文字のやり取りをするttyのプロセスも起動します。

## upowerd / acpid

これらは、電源系統の管理を行います。内部にある充電系統のマイコンと会話したり、電源プラグの状態を取得したり、電源ランプを光らせたりなどを担当します。

## polkit

polkitは認可デーモンです。sudoは完全な管理者権限を要求しますが、polkitはrootで動作するデーモンに対してユーザーが起動したプロセスが動作を委託したりする場合に使われます。AWSのAPI Gatewayみたいな役割です。

## PAM

PAMはUnitではありませんが、パスワードの検証や、ログイン許可などの認証時に利用されるサービスです。

# X Window System / Wayland

これらは、ディスプレイサーバと呼ばれます。ディスプレイのピクセルに、何を表示するか、つまりGUIでの動作を司る役割をします。
ウィンドウの概念を理解したり、キーボードやタッチパッドと会話したりするものがこれになります。

また、X Window Systemは、サーバーとクライアントが起動します。
クライアントが実際に画面を表示するデーモン、サーバーは画面のバッファや文字列を管理するデーモンです。
通常は、両方が同じマシンで起動しますが、場合によればSSHでX転送などをすることで分割することができます。
また、ディスプレイとキーボードとマウスをそれぞれ2つづつ接続し、複数起動することで、2人のユーザーが同時に1つのマシンを利用することも可能です。

## GTK / Qt

これらは、画面上のパーツや、描画API、コンポーネントを提供します。
アプリケーションは、主に彼らと対話し、実際にX Window Systemに命令を出すのはこれになります。

具体的には、テキストフォームや、ボタン、ウィンドウの装飾などを担当します。

## Mesa / Nvidia Driver / Intel Driver ...

これらは、ドライバです。GTKやQtは、描画する内容が決定すると、このドライバを利用し、GPUやCPU内蔵グラフィックに演算命令を下します。

## OpenGL / Vulkan 

これらは、上のドライバで共通で使われる描画APIです。3D空間の座標の計算や、光の幻影などを演算します。

# シェル / ディスプレイマネージャ

無事に起動が完了すると、CUIのログイン画面と、GUIのログイン画面のどちらかが実行されます。後者はディスプレイマネージャと呼ばれます。

CUIの場合は、ログイン後にシェルを、GUIの場合はウィンドウマネージャが起動します。

# ウィンドウマネージャ  ( デスクトップ環境 )

これらは、ウィンドウの重ね合わせの管理や移動を担当します。
デスクトップ環境の場合は、ウィンドウマネージャ以外にも、ドック、コンポジットマネージャ、パネル、アプレットなどが同時に起動されます。

## コンポジットマネージャ

コンポジットマネージャは、ブラーや影、透過、アニメーションを担当します。場合によりウィンドウマネージャに内蔵されている場合もあります。
同時に有効にできるコンポジットマネージャは1つまでです。

# D-bus

D-busは、ウィンドウマネージャやデスクトップ環境が起動するときに同時に起動されます。
アプリケーション間の通信に使われます。

デーモンが常に起動しており、アプリケーションはUnix Domain Socket（特殊ファイル）を使ってD-busにデータを渡したり、受け取ったりします。

デスクトップ環境の通知（Notification）の仕組みや、音量を管理するサービス、画面の明るさを管理するサービス、ネットワークを管理するサービス（Network Managerなど）と通常のアプリケーションの対話によく使われます。

# Pulseaudio / Jack / ALSA

これらは、サウンド管理をするプロセスです。複数のアプリケーションが出す音を、一つにまとめて、しかるべきスピーカーに出力します。
ALSAは、一部カーネルに含まれています。

# インプットマネージャ

Ibusやfcitxなどがこれにあたります。文字変換を担う役割です。
日本語の場合はMozcなどの変換ライブラリを使用します。