# バッチ設計書 9-221.backup-gpart

## 概要

本ドキュメントは、FreeBSD periodicフレームワークにおける日次ディスクパーティションバックアップバッチ `221.backup-gpart` の設計を記述する。本バッチはディスクパーティションレイアウト、ブートパーティション、MBR、およびEFIパーティションのバックアップを行う。

### 本バッチの処理概要

本バッチは、`gpart(8)` を使用してシステムのディスクパーティション構成情報をバックアップし、前回バックアップとの差分を検出・管理する処理を行う。

**業務上の目的・背景**：ディスクのパーティションレイアウト情報は、ディスク障害時やシステム復旧時に不可欠である。パーティションテーブルが破損した場合、`gpart restore` コマンドでバックアップから復元できる。また、ブートパーティションやMBRの内容もバックアップすることで、ブートローダの復旧にも対応できる。本バッチにより、これらの情報を日次で自動バックアップし、災害復旧への備えを強化する。

**バッチの実行タイミング**：日次（daily）。FreeBSD periodicフレームワークにより実行される。

**主要な処理内容**：
1. `/etc/defaults/periodic.conf` および上書き設定ファイルの読み込み
2. `daily_backup_gpart_enable` 変数による有効/無効判定
3. `kern.geom.conftxt` のバックアップ（カーネルGEOM設定テキスト）
4. `gpart show` でディスクデバイスを列挙し、各デバイスの `gpart backup` を実行
5. bios-boot / freebsd-boot パーティションの内容を `dd` でバックアップ
6. MBRレコードの内容を `dd` でバックアップ
7. `daily_backup_efi_enable` が有効な場合、EFIパーティションの内容をバックアップ
8. 各バックアップについて前回との差分を検出し、ローテーション管理

**前後の処理との関連**：daily periodicのバックアップカテゴリ（200番台）に属する。`210.backup-aliases` に続いて実行される。後続の `222.backup-gmirror` と同じストレージバックアップグループに属する。

**影響範囲**：`/var/backups` ディレクトリ内のバックアップファイル。ディスクデバイスからの読み取りのみで、ディスク内容の変更は行わない。

## バッチ種別

データ連携（ストレージレイアウトバックアップ）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次 |
| 実行時刻 | periodic(8)のcron設定に依存 |
| 実行曜日 | 毎日 |
| 実行日 | 毎日 |
| トリガー | cron経由でperiodic(8)から起動 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| periodic.confの存在 | `/etc/defaults/periodic.conf` が読み取り可能であること |
| daily_backup_gpart_enable=YES | jail外ではデフォルト有効 |
| gpart(8)の存在 | gpart コマンドが利用可能であること |
| 非jail環境 | jail内ではデフォルト無効（security.jail.jailed=0 の場合のみデフォルト有効） |

### 実行可否判定

`daily_backup_gpart_enable` が `YES` の場合に実行する。デフォルトは `sysctl -n security.jail.jailed` の値に基づき、jail外ではYES、jail内ではNO。`gpart show` でディスクが検出されない場合はrc=2。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| daily_backup_gpart_enable | 文字列 | Yes | YES（jail外）/ NO（jail内） | バッチの有効/無効フラグ |
| daily_backup_gpart_verbose | 文字列 | No | NO | 差分がある場合の詳細出力 |
| daily_backup_gpart_exclude | 文字列 | No | （空） | 除外するデバイスの正規表現パターン |
| daily_backup_efi_enable | 文字列 | No | NO | EFIパーティションバックアップの有効/無効 |
| daily_diff_flags | 文字列 | No | -b -U 0 | diff コマンドのフラグ |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| /etc/defaults/periodic.conf | シェル変数定義 | デフォルト設定値 |
| kern.geom.conftxt | sysctl出力 | カーネルGEOM設定テキスト |
| gpart show | コマンド出力 | パーティションレイアウト |
| gpart backup | コマンド出力 | パーティションバックアップデータ |
| /dev/* | ブロックデバイス | ブート/MBR/EFIパーティションの内容 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| /var/backups/kern.geom.conftxt.bak | テキスト | GEOM設定のバックアップ |
| /var/backups/gpart.{デバイス名}.bak | テキスト | 各デバイスのパーティションバックアップ |
| /var/backups/boot.{パーティション名}.bak | バイナリ | ブートパーティションの内容 |
| /var/backups/boot.{デバイス名}.bak | バイナリ | MBRレコードの内容 |
| /var/backups/efi.{パーティション名}.bak | バイナリ | EFIパーティションの内容 |
| 標準出力 | テキスト | 処理メッセージおよび差分情報 |
| 終了コード | 数値 | 0:変更なし、1:変更あり、2:設定不備/ディスクなし、3:実行エラー |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | kern.geom.conftxt.bak / gpart.*.bak / boot.*.bak / efi.*.bak（各.bak2も） |
| 出力先 | /var/backups/ |
| 文字コード | テキストファイルはシステムデフォルト、バイナリファイルは生データ |
| 区切り文字 | N/A |

## 処理フロー

### 処理シーケンス

```
1. 設定ファイル読み込み
   └─ periodic.conf を source
2. gpartバックアップの有効/無効判定
   └─ daily_backup_gpart_enable が YES かどうか判定
3. kern.geom.conftxt バックアップ
   └─ sysctl -n kern.geom.conftxt の出力を .tmp に保存
   └─ rotate 関数で .bak と比較・ローテーション
4. gpart デバイス列挙
   └─ gpart show | awk で => 行からデバイス名を抽出
   └─ daily_backup_gpart_exclude で除外パターンを適用
5. 各デバイスの gpart backup
   └─ gpart backup $d の出力を .tmp に保存
   └─ rotate 関数でバックアップ管理
6. ブートパーティションのバックアップ
   └─ gpart show -p で bios-boot/freebsd-boot パーティションを検出
   └─ dd で内容をバックアップ
7. MBRレコードのバックアップ
   └─ MBRスキームのデバイスを検出
   └─ dd bs=512 count=1 で先頭セクタをバックアップ
8. EFIパーティションバックアップ（daily_backup_efi_enable=YES時）
   └─ efi パーティションを検出
   └─ dd で内容をバックアップ
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[periodic.conf読み込み]
    B --> C{daily_backup_gpart_enable=YES?}
    C -->|No| Z[rc=0で終了]
    C -->|Yes| D[kern.geom.conftxtバックアップ]
    D --> E[gpart showでデバイス列挙]
    E --> F{デバイスあり?}
    F -->|No| G[rc=2]
    F -->|Yes| H[各デバイスのgpart backup]
    H --> I[ブートパーティションバックアップ]
    I --> J[MBRバックアップ]
    J --> K{daily_backup_efi_enable=YES?}
    K -->|Yes| L[EFIパーティションバックアップ]
    K -->|No| M[終了]
    L --> M
    G --> M
```

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

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

本バッチはデータベースを使用しない。

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| N/A | N/A | N/A | データベース操作なし |

### テーブル別操作詳細

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| rc=2 | 環境不備 | gpartでディスクが検出されない | NFS disklessクライアント等では正常 |
| rc=3 | 実行エラー | mv コマンドの失敗 | /var/backups のパーミッションを確認する |
| rc=1 | 情報通知 | 前回との差分が検出された | パーティション変更の妥当性を確認する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

### 障害時対応

リトライ機構はない。次回のdaily実行時に再度実行される。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（ファイルシステム操作） |
| コミットタイミング | 各バックアップは即時書き込み |
| ロールバック条件 | ロールバック機構なし。.bak2 に前回バックアップ保持 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | ディスクデバイス数に依存（通常数個） |
| 目標処理時間 | 数秒〜数十秒（EFIバックアップを含む場合はディスクI/O依存） |
| メモリ使用量上限 | dd/gpart コマンドの使用量（低い） |

## 排他制御

排他制御の仕組みは実装されていない。`rotate` 関数内で .tmp -> .bak のリネームをアトミックに行うが、同時実行に対する排他制御はない。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | 処理開始時 | "Dump of kern.geom.conftxt:" / "Backup of partitions information for:" |
| 進捗ログ | 各デバイス処理時 | デバイス名の出力 |
| 差分ログ | verbose有効・差分検出時 | diff出力または新規バックアップの内容 |
| エラーログ | ディスク未検出時 | "no disk probed by kernel" メッセージ |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 終了コード | rc=1 | periodic(8)の出力先（変更検出通知） |
| 終了コード | rc >= 2 | periodic(8)の出力先（エラー通知） |

## 備考

- jail外ではデフォルト有効、jail内ではデフォルト無効
- `daily_backup_gpart_verbose` はデフォルトNO。有効にすると差分が報告される
- `daily_backup_efi_enable` はデフォルトNO。EFIパーティションのバックアップは別途有効化が必要
- `daily_backup_gpart_exclude` で特定デバイスの除外が可能（正規表現パターン）
- デバイス名に含まれる特殊文字は `tr -cs ".[:alnum:]\n" "_"` でアンダースコアに変換される
- `rotate` 関数は内部関数として定義され、.tmp -> .bak のローテーション管理を行う
- バックアップデータは `gpart restore` で復元可能
- Created by: Miroslav Lachman
