# 画面設計書 20-配布ファイル展開画面

## 概要

本ドキュメントは、FreeBSD bsdinstallインストーラにおける配布ファイル展開画面の設計書である。配布ファイル（tar.xz形式）をインストール先ディレクトリに展開し、進捗をプログレスバーで表示するC言語実装の画面について記述する。

### 本画面の処理概要

この画面では、チェックサム検証済みの配布ファイルをlibarchive(3)を使用してインストール先（$BSDINSTALL_CHROOT）に展開する。bsddialogのprogressviewウィジェットを使用して、ファイル単位の展開進捗をリアルタイムに表示する。

**業務上の目的・背景**：FreeBSDのベースシステムは配布ファイル（base.txz、kernel.txz等）としてtar.xz形式で圧縮されている。これらをインストール先のルートファイルシステムに正しいパーミッション、タイムスタンプ、ACL、拡張属性を維持しながら展開する必要がある。本画面はその展開処理を実行し、進捗をユーザに表示する。

**画面へのアクセス方法**：autoスクリプトのインストール実行フロー内で、チェックサム検証完了後に `bsdinstall distextract` コマンドで自動的に呼び出される。

**主要な操作・処理内容**：
1. DISTRIBUTIONS環境変数から配布ファイル一覧をパースする
2. 各ファイルのエントリ数をMANIFESTファイルまたはarchive(3)で事前カウントする
3. BSDINSTALL_CHROOTディレクトリにchdirする
4. bsddialog_progressviewで展開処理をコールバック形式で実行する
5. 各アーカイブエントリについてarchive_read_extractで展開する（パーミッション、オーナー、ACL、拡張属性、ファイルフラグを保持）
6. 展開速度（files/sec）と進捗率をリアルタイムに表示する

**画面遷移**：
- 遷移元：チェックサム検証画面（No.19）完了後
- 遷移先（成功）：ブートローダ設定処理後、rootパスワード設定画面（No.21）へ
- 遷移先（失敗）：エラーメッセージ表示後、インストーラエラーハンドリングへ

**権限による表示制御**：権限による表示制御はない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 92 | libarchive | 主機能 | libarchiveを使用した配布ファイル（tar.xz）の展開・進捗表示 |
| 74 | パッケージ管理支援 | 補助機能 | 展開先ディレクトリ管理とDISTRIBUTIONS変数の処理 |

## 画面種別

進捗表示（progressview）

## URL/ルーティング

TUIベースのbsddialogインターフェース。URLは存在しない。
- 呼び出し：`bsdinstall distextract`
- 実体バイナリ：`usr.sbin/bsdinstall/distextract/distextract.c` からコンパイル

## 入出力項目

本画面にユーザ入力項目はない。進捗表示のみ。

| 項目名 | 入出力 | 型 | 必須 | 初期値 | 説明 |
|--------|--------|------|------|--------|------|
| DISTRIBUTIONS | 入力（環境変数） | 文字列 | はい | - | 展開対象の配布ファイル一覧 |
| BSDINSTALL_DISTDIR | 入力（環境変数） | 文字列 | はい | - | 配布ファイルのソースディレクトリ |
| BSDINSTALL_CHROOT | 入力（環境変数） | 文字列 | はい | - | 展開先ディレクトリ |

## 表示項目

| 項目名 | 表示位置 | 説明 |
|--------|----------|------|
| バックタイトル | 画面上部 | "$OSNAME Installer" |
| タイトル | ダイアログタイトル | "Archive Extraction" |
| メッセージ | progressview内 | "Extracting distribution files..." |
| 全体進捗バー | progressview | 全ファイルの展開進捗率 |
| 個別ファイル進捗 | progressviewミニバー | 各配布ファイルの展開進捗（ファイル数ベース） |
| 統計情報 | progressview下部 | "{展開ファイル数} files read @ {速度} files/sec." |
| 初期メッセージ | infobox | "Checking distribution archives. Please wait..." |

## イベント仕様

### 1-展開処理（自動実行・コールバック形式）

bsddialog_progressview が extract_files コールバック関数を繰り返し呼び出す：

1. コールバック初回呼び出し時にarchive_read_newでアーカイブを開く（行263-285）
2. archive_read_next_headerで次のエントリを読み取る（行289）
3. archive_read_extractでエントリを展開する（行293-296）。展開時のフラグ：
   - ARCHIVE_EXTRACT_TIME：タイムスタンプ保持
   - ARCHIVE_EXTRACT_OWNER：オーナー保持
   - ARCHIVE_EXTRACT_PERM：パーミッション保持
   - ARCHIVE_EXTRACT_ACL：ACL保持
   - ARCHIVE_EXTRACT_XATTR：拡張属性保持
   - ARCHIVE_EXTRACT_FFLAGS：ファイルフラグ保持
4. EOF到達時にarchive_read_freeでアーカイブを閉じ、DONEステータスを返す（行299-302）
5. エラー発生時にFAILEDステータスを設定し、bsddialog_abortprogviewをtrueにする（行304-320）
6. 展開ファイル数をインクリメントし、進捗率を返す（行323-328）

### 2-Ctrl-C（SIGINT）

sig_intハンドラでbsddialog_interruptprogviewをtrueに設定し、進捗表示を中断する（行164-168）。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 展開処理 | $BSDINSTALL_CHROOT以下 | WRITE | 配布ファイル内の全ファイルを展開・書き込み |

## メッセージ仕様

| 種別 | 条件 | メッセージ |
|------|------|-----------|
| 情報 | 初期表示 | "Checking distribution archives. Please wait..." |
| 情報 | 展開中 | "Extracting distribution files..." |
| エラー | アーカイブ作成失敗 | "Error: {エラー文字列}" |
| エラー | アーカイブオープン失敗 | "Error opening {ファイル名}: {エラー文字列}" |
| エラー | 展開中エラー | "Error while extracting {ファイル名}: {エラー文字列}" |

## 例外処理

| 条件 | 動作 |
|------|------|
| DISTRIBUTIONS環境変数未設定 | errxで即座に終了 |
| BSDINSTALL_CHROOTへのchdir失敗 | エラーメッセージ表示後EXIT_FAILURE |
| アーカイブオープン失敗 | FAILEDステータス設定、bsddialog_abortprogview=trueで中断 |
| 展開中エラー（重大） | FAILEDステータス設定、bsddialog_abortprogview=trueで中断 |
| 展開中警告（"Can't restore time"） | 無視して続行（行306） |
| SIGINT受信 | bsddialog_interruptprogview=trueで中断 |

## 備考

- C言語実装でlibarchive(3)ライブラリを使用している
- bsddialog_progressviewウィジェットのコールバック形式で実装されており、コールバックは1秒ごとにリフレッシュされる（行143: pvconf.refresh = 1）
- エントリ数の事前カウントはMANIFESTファイルの3列目から取得を試み、不在の場合はarchive(3)で全エントリをカウントする（行174-249）
- 「Can't restore time」警告は無視される（libarchiveのオプションではなくコード側で判定）
- progressview下部に展開速度（files/sec）が表示される（行144のfmtbottomstr）
- archive_read_support_format_all/archive_read_support_filter_allで全アーカイブ形式に対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | distextract.c | `usr.sbin/bsdinstall/distextract/distextract.c` | bsddialog_fileminibar構造体（path, label, size, status, read）とbsddialog_progviewconf構造体（callback, refresh, fmtbottomstr）を理解する |

**読解のコツ**: bsddialog_progressviewはコールバック関数を繰り返し呼び出し、返り値が0-100の進捗率を表す。負の値はエラー、100はファイル完了を意味する。bsddialog_total_progviewグローバル変数で全体の展開ファイル数を追跡する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | distextract.c | `usr.sbin/bsdinstall/distextract/distextract.c` | 行58-162のmain関数。DISTRIBUTIONS解析、エントリ数カウント、chdir、progressview起動 |

**主要処理フロー**:
1. **行73-78**: DISTRIBUTIONS/BSDINSTALL_DISTDIR環境変数の取得
2. **行88-122**: DISTRIBUTIONSのパースとdists配列の構築。各ファイルのcount_filesでエントリ数を事前カウント
3. **行125-134**: BSDINSTALL_CHROOTへのchdir
4. **行140-149**: progressview設定（コールバック、リフレッシュ間隔、フォーマット文字列）
5. **行147-149**: bsddialog_progressviewの起動（展開処理のメインループ）

#### Step 3: 展開コールバックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | distextract.c | `usr.sbin/bsdinstall/distextract/distextract.c` | 行251-331のextract_files関数。アーカイブのオープン、エントリの読み取りと展開、EOF/エラー処理 |

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

```
bsdinstall distextract (usr.sbin/bsdinstall/distextract/distextract.c)
    |
    +-- main()
           |
           +-- bsddialog_init() / bsddialog_backtitle()
           +-- DISTRIBUTIONS解析 → dists配列構築
           +-- count_files() (各ファイルのエントリ数カウント)
           |      +-- MANIFESTからの取得、またはarchive(3)でカウント
           +-- chdir(BSDINSTALL_CHROOT)
           |
           +-- bsddialog_progressview()
                  |
                  +-- [コールバックループ: extract_files()]
                         +-- archive_read_new() (初回のみ)
                         +-- archive_read_next_header()
                         +-- archive_read_extract()
                         |      (TIME|OWNER|PERM|ACL|XATTR|FFLAGS)
                         +-- [EOF] archive_read_free() → DONE
                         +-- [エラー] FAILED → abort
```

### データフロー図

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

$BSDINSTALL_DISTDIR/
  {dist}.txz ---------> archive_read_open_filename
                              |
                              v
                        archive_read_next_header
                              |
                              v
                        archive_read_extract ------> $BSDINSTALL_CHROOT/
                              |                        (展開されたファイル群)
                              v
                        bsddialog_progressview
                              |
                              v
                        TUI進捗表示
                        (files/sec統計付き)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| distextract.c | `usr.sbin/bsdinstall/distextract/distextract.c` | ソース | 配布ファイル展開のメインプログラム（332行） |
| opt_osname.h | `usr.sbin/bsdinstall/distextract/opt_osname.h` | ヘッダ | OSNAMEマクロ定義（ビルド時生成） |
| auto | `usr.sbin/bsdinstall/scripts/auto` | ソース | distextractの呼び出し元 |
| MANIFEST | `$BSDINSTALL_DISTDIR/MANIFEST` | データ | エントリ数事前取得用マニフェスト |
