# 機能設計書 69-init / rc

## 概要

本ドキュメントは、FreeBSDのシステム初期化プロセス（init）およびRCスクリプトフレームワークの機能設計を記述する。initはカーネルが起動後に最初に実行されるユーザランドプロセス（PID 1）であり、RCスクリプトフレームワークはシステムサービスの起動・停止を管理する。

### 本機能の処理概要

**業務上の目的・背景**：OSの起動プロセスにおいて、カーネルが起動した後のユーザランド初期化を管理する仕組みが必要である。initはPID 1として全プロセスの親となり、システム状態の遷移（シングルユーザ→マルチユーザ→シャットダウン）を制御する。RCスクリプトフレームワークはサービスの依存関係を解決し、正しい順序で起動・停止を行う。

**機能の利用シーン**：システム起動時の自動的なサービス初期化、シングルユーザモードでの保守作業、サービスの手動起動/停止/再起動（serviceコマンド）、システムシャットダウン/再起動時のサービス停止処理に使用される。

**主要な処理内容**：
1. initによるシステム状態管理（シングルユーザ、マルチユーザ、シャットダウン）
2. /etc/rc スクリプトの実行（マルチユーザ遷移時）
3. /etc/rc.shutdown スクリプトの実行（シャットダウン時）
4. /etc/ttys に基づくgetty（ログインプロンプト）の起動管理
5. rcorderによるRCスクリプトの依存関係解決と実行順序決定
6. rc.subr による共通RCスクリプトフレームワーク
7. rc.conf による設定値管理
8. シグナルによるシステム状態遷移（SIGTERM→シングルユーザ、SIGINT→再起動等）

**関連システム・外部連携**：カーネルがinit(8)を最初のユーザプロセスとして起動する。initは/etc/ttysを読み取りgetty(8)を起動する。rcスクリプトは/etc/rc.dディレクトリ配下のスクリプト群とrc.confの設定に基づいてサービスを管理する。

**権限による制御**：initはPID 1でroot権限で動作する。RCスクリプトもroot権限で実行される。initの直接操作にはroot権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | サービス選択画面 | 主機能 | sshd・ntpd・powerd等のRC起動サービスの有効/無効をrc.confに設定する処理 |
| 26 | セキュリティ強化設定画面 | 補助機能 | rc.confへのclear_tmp_enable・syslogd_flags設定 |
| 30 | 最終設定メニュー画面 | 遷移先機能 | Services選択時のサービス選択画面への遷移 |

## 機能種別

システム初期化 / サービス管理フレームワーク

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -s | flag | No | シングルユーザモードで起動 | なし |
| -f | flag | No | ファストブート（fsck省略） | なし |
| -r | flag | No | reroot（ルートFS再マウント） | なし |
| -d | flag | No | devfsマウント | なし |
| シグナル | signal | No | SIGTERM（シングルユーザ）、SIGINT（再起動）、SIGHUP（ttys再読込）等 | 有効なシグナル |

### 入力データソース

- /etc/ttys: ターミナルデバイスとgetty設定
- /etc/rc: マルチユーザ初期化スクリプト
- /etc/rc.d/: サービススクリプト群
- /etc/rc.conf: サービス設定ファイル
- /etc/defaults/rc.conf: デフォルト設定
- /etc/rc.shutdown: シャットダウンスクリプト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| gettyプロセス | pid_t | 各TTYのgettyプロセスID |
| RCスクリプト実行結果 | int | 各サービスの起動/停止結果 |
| syslogメッセージ | string | 状態遷移ログ |

### 出力先

- syslog: 状態遷移ログ（LOG_AUTH facility）
- コンソール: 起動メッセージ
- /var/run/: 各サービスのPIDファイル

## 処理フロー

### 処理シーケンス

```
1. init起動（PID 1）
   └─ setsid(), setlogin("root"), シグナルハンドラ設定
2. ブートモード判定
   └─ -s: シングルユーザ、-f: ファストブート、デフォルト: runcom
3. runcom状態（/etc/rc実行）
   └─ /etc/rc スクリプト実行 → rcorderによる依存関係解決 → rc.d/スクリプト順次実行
4. マルチユーザ状態
   └─ /etc/ttys読み込み → getty起動 → ログインプロンプト提供
5. getty管理ループ
   └─ gettyプロセスの監視、クラッシュ時の再起動（スロットリング付き）
6. 状態遷移
   └─ シグナル受信による状態変更（シャットダウン、リブート等）
7. シャットダウン
   └─ /etc/rc.shutdown実行 → プロセスSIGTERM → SIGKILL → reboot()
```

### フローチャート

```mermaid
flowchart TD
    A[カーネルがinitを起動] --> B{ブートモード}
    B -->|シングルユーザ -s| C[single_user: シェル起動]
    B -->|通常| D[runcom: /etc/rc実行]
    D --> E[read_ttys: /etc/ttys読み込み]
    E --> F[multi_user: getty起動]
    F --> G{シグナル待機}
    G -->|SIGTERM| C
    G -->|SIGINT| H[再起動]
    G -->|SIGHUP| I[/etc/ttys再読込]
    G -->|SIGUSR2| J[シャットダウン]
    G -->|SIGEMT| K[reroot]
    G -->|子プロセス終了| L[getty再起動]
    C --> M{シェル終了}
    M -->|正常| D
    M -->|異常| C
    H --> N[death: rc.shutdown]
    J --> N
    N --> O[reboot() / halt()]
    I --> F
    L --> F
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-69-01 | PID 1検証 | getpid() != 1の場合はSysV互換モードまたはエラー | init起動時 |
| BR-69-02 | gettyスロットリング | 5秒以内の再起動を3回検出した場合、30秒待機 | getty再起動時 |
| BR-69-03 | シャットダウンタイムアウト | rc.shutdownは120秒で強制終了 | シャットダウン時 |
| BR-69-04 | プロセス終了待機 | SIGTERMの後10秒待機してSIGKILL | death状態 |
| BR-69-05 | rcorder依存関係 | REQUIRE/PROVIDE/BEFORE/KEYWORDコメントで依存関係を定義 | RCスクリプト実行順序決定時 |

### 計算ロジック

特になし。

## データベース操作仕様

### 操作別データベース影響一覧

init内部でBerkeleyDB形式のセッションデータベースを使用してgettyセッションを管理する。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| gettyセッション管理 | session_db | INSERT/DELETE/SELECT | PIDをキーとしたセッション情報の管理 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EPERM | 権限不足 | root以外のユーザがinit実行 | errx(1, "Permission denied") |
| - | rc.shutdown失敗 | シャットダウンスクリプトのエラー | タイムアウト後に強制終了 |
| - | gettyクラッシュ | ログインプロセスの異常終了 | スロットリング付きで再起動 |
| - | disaster | SIGABRT等の致命的シグナル | コンソールに警告出力 |

### リトライ仕様

gettyプロセスのクラッシュ時はスロットリング（GETTY_SPACING=5秒、GETTY_SLEEP=30秒、GETTY_NSPACE=3回）で再起動する。

## トランザクション仕様

トランザクション管理は不要。セッションDBはBerkeleyDB APIで管理。

## パフォーマンス要件

- rcorderによる依存関係解決は起動スクリプト数に対してDAGのトポロジカルソートで効率的
- gettyの再起動はスロットリングにより無限ループを防止

## セキュリティ考慮事項

- initはPID 1としてシステム全体の制御権を持つ
- シングルユーザモードではroot権限のシェルが提供されるため、物理アクセス制御が重要
- securelevelの設定・管理もinitが担当（getsecuritylevel/setsecuritylevel）
- SECURE定義時はシングルユーザモードでもrootパスワードを要求

## 備考

- SysV互換モード（COMPAT_SYSV_INIT定義時）ではrunlevel引数（0,1,6等）をシグナルに変換
- reroot機能（-r, SIGEMT）はルートファイルシステムの再マウントを実現
- BOOTTRACE()マクロでブートトレースイベントを記録

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | init.c | `sbin/init/init.c` | init_session構造体（141-160行目）、state_func_t型定義（107-108行目） |
| 1-2 | pathnames.h | `sbin/init/pathnames.h` | パス定数定義 |

**読解のコツ**: initの状態遷移はstate_func_t関数ポインタで管理される。各状態（single_user, runcom, read_ttys, multi_user, clean_ttys, catatonia, death, reroot）は関数として実装され、次の状態を返す。この状態マシンパターンを理解することがinit全体の理解の鍵。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | init.c | `sbin/init/init.c` | main()関数（189-299行目） |

**主要処理フロー**:
1. **78-88行目**: 定数定義（GETTY_SPACING=5, GETTY_SLEEP=30, DEATH_WATCH=10, DEATH_SCRIPT=120）
2. **107-108行目**: state_func_t/state_t型定義
3. **110-118行目**: 状態関数宣言（single_user, runcom, read_ttys, multi_user, clean_ttys, catatonia, death, reroot等）
4. **123行目**: runcom_mode変数（AUTOBOOT/FASTBOOT）
5. **141-160行目**: init_session構造体（se_process, se_device, se_getty等）
6. **189-243行目**: main() - PID 1検証、SysV互換、setsid(), setlogin()
7. **272-289行目**: オプション解析（-d, -s, -f, -r）
8. **298-299行目**: シグナルハンドラ設定（disaster, transition_handler等）

#### Step 3: rcorderを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rcorder.c | `sbin/rcorder/rcorder.c` | RCスクリプト依存関係解決 |

**主要処理フロー**:
1. **65-78行目**: REQUIRE/PROVIDE/BEFORE/KEYWORDコメントのパターン定義
2. RCスクリプトヘッダのパース、DAG構築、トポロジカルソートの実行

#### Step 4: RCフレームワークを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | rc | `libexec/rc/rc` | マルチユーザ初期化メインスクリプト |
| 4-2 | rc.subr | `libexec/rc/rc.subr` | RC共通ライブラリ（run_rc_command等） |
| 4-3 | rc.conf | `libexec/rc/rc.conf` | デフォルト設定値 |
| 4-4 | rc.shutdown | `libexec/rc/rc.shutdown` | シャットダウンスクリプト |

### プログラム呼び出し階層図

```
カーネル → init (PID 1) [sbin/init/init.c]
    |
    +-- main() → transition(initial_transition)
    |
    +-- runcom() → /etc/rc [libexec/rc/rc]
    |       +-- rcorder [sbin/rcorder/rcorder.c]
    |       |       └─ REQUIRE/PROVIDE/BEFOREパース → トポロジカルソート
    |       +-- /etc/rc.d/* スクリプト群
    |               └─ rc.subr [libexec/rc/rc.subr]
    |                       └─ run_rc_command()
    |
    +-- read_ttys() → /etc/ttys 読み込み
    |
    +-- multi_user() → getty群管理ループ
    |       +-- start_getty() → fork/exec getty
    |       +-- collect_child() → セッション管理
    |
    +-- death() → rc.shutdown [libexec/rc/rc.shutdown]
            +-- SIGTERM → SIGKILL → reboot()
```

### データフロー図

```
[入力]                        [処理]                        [出力]

カーネルブート ──────────▶ init main() ─────────────▶ 状態遷移開始
/etc/rc.conf ────────────▶ rc スクリプト ────────────▶ サービス起動
/etc/rc.d/*.sh ──────────▶ rcorder → 順次実行 ──────▶ デーモンプロセス
/etc/ttys ───────────────▶ read_ttys() ─────────────▶ gettyプロセス
シグナル ────────────────▶ transition_handler() ────▶ 状態遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| init.c | `sbin/init/init.c` | ソース | initプロセス実装 |
| pathnames.h | `sbin/init/pathnames.h` | ヘッダ | パス定数 |
| rcorder.c | `sbin/rcorder/rcorder.c` | ソース | RC依存関係解決 |
| rc | `libexec/rc/rc` | スクリプト | マルチユーザ初期化 |
| rc.subr | `libexec/rc/rc.subr` | スクリプト | RC共通ライブラリ |
| rc.conf | `libexec/rc/rc.conf` | 設定 | デフォルトRC設定 |
| rc.shutdown | `libexec/rc/rc.shutdown` | スクリプト | シャットダウン処理 |
| rc.d/ | `libexec/rc/rc.d/` | スクリプト | 個別サービススクリプト群 |
| network.subr | `libexec/rc/network.subr` | スクリプト | ネットワーク共通関数 |
| init.8 | `sbin/init/init.8` | マニュアル | initマニュアルページ |
| rcorder.8 | `sbin/rcorder/rcorder.8` | マニュアル | rcorderマニュアル |
