# 帳票設計書 13-quot - ディスク使用量ユーザー別レポート

## 概要

本ドキュメントは、FreeBSD の `quot` コマンドが出力するディスク使用量ユーザー別レポートの設計仕様を記述する。

### 本帳票の処理概要

quot は、UFSファイルシステム上の各ユーザーが占有するディスク空間をレポートするユーティリティである。ファイルシステムのiノードを直接走査し、ユーザー別のディスク使用量を集計して出力する。

**業務上の目的・背景**：ファイルシステムの容量管理において、ユーザー別のディスク使用量を詳細に把握するために使用される。repquota がクォータ設定値との比較に重点を置くのに対し、quot は実際のiノードレベルでの使用量集計に特化している。ファイルサイズの分布分析や、30/60/90日間未使用ファイルの特定も可能である。

**帳票の利用シーン**：ディスク容量の詳細分析、ユーザー別使用量ランキング、未使用ファイルの特定、ファイルサイズ分布の分析などの場面で利用される。

**主要な出力内容**：
1. ユーザー別ディスク使用量（ブロック数）
2. ファイル数（-f オプション時）
3. ユーザー名
4. 30/60/90日間未使用量（-v オプション時）
5. ファイルサイズ分布（-c オプション時）

**帳票の出力タイミング**：管理者がコマンドラインから `quot` コマンドを実行した際に標準出力に出力される。

**帳票の利用者**：システム管理者、ストレージ管理者

## 帳票種別

集計表（ユーザー別ディスク使用量集計）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | コマンドラインインターフェース | N/A | `quot` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（標準出力） |
| 出力方法 | 標準出力（stdout） |
| 文字コード | ロケール依存 |

## 帳票レイアウト

### レイアウト概要

モードに応じて3種類のレイアウトが存在する。

#### douser モード（デフォルト）
```
{device}: ({mountpoint})
 使用量  [ファイル数]  ユーザー名  [30日未使用  60日未使用  90日未使用]
```

#### dofsizes モード（-c オプション）
```
{device}: ({mountpoint})
サイズ(KB)  ファイル数  累積ブロック数
```

#### donames モード（-n オプション）
```
{device}: ({mountpoint})
ユーザー名  ファイル情報
```

### 明細部（douser モード）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | ディスク使用量 | ユーザーの総ブロック使用量 | user.space | "%5d"形式 | 5文字 |
| 2 | ファイル数 | ユーザーのファイル数（-f時） | user.count | "%5ld"形式 | 5文字 |
| 3 | ユーザー名 | UID対応名またはID番号 | user.name | "%-8s"形式 | 8文字 |
| 4 | 30日未使用量 | 30日以上未アクセスファイルのブロック数 | user.spc30 | "%5d"形式 | 5文字 |
| 5 | 60日未使用量 | 60日以上未アクセスファイルのブロック数 | user.spc60 | "%5d"形式 | 5文字 |
| 6 | 90日未使用量 | 90日以上未アクセスファイルのブロック数 | user.spc90 | "%5d"形式 | 5文字 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ファイルシステム指定 | 対象UFSファイルシステム（-a で全マウント済みUFS） | Yes |
| 動作モード | -c（サイズ分布）、-n（名前モード）、デフォルト（ユーザー集計） | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | ディスク使用量（douser） | 降順（qsortによるcmpusers） |
| 1 | ファイルサイズ（dofsizes） | 昇順 |

### 改ページ条件

ファイルシステムごとにセクション分け

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| UFSファイルシステム（raw device） | iノード直接読み取り | ファイルシステムのスーパーブロック情報 |
| パスワードデータベース | UID→ユーザー名変換 | di_uid |
| /etc/fstab, getmntinfo | ファイルシステム列挙 | UFS型のみ |

### テーブル別参照項目詳細

#### UFSファイルシステム（union dinode）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| di_blocks | ディスク使用量 | get_inode()で取得 | SIZE()マクロでブロックサイズ変換 |
| di_uid | ユーザー識別 | get_inode()で取得 | user()関数でuser構造体に集計 |
| di_atime | 最終アクセス時刻 | get_inode()で取得 | 30/60/90日間未使用判定 |
| di_mode | ファイル種別 | get_inode()で取得 | isfree()でフリーiノード判定 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| ディスク使用量(KB) | SIZE(n) = (n * 512 + blocksize - 1) / blocksize | 切り上げ | 行92のSIZEマクロ |
| 30日未使用量 | today - di_atime > 30*24*60*60 の場合にspc30に加算 | N/A | 行276-277 |
| 60日未使用量 | today - di_atime > 60*24*60*60 の場合にspc60に加算 | N/A | 行278-279 |
| 90日未使用量 | today - di_atime > 90*24*60*60 の場合にspc90に加算 | N/A | 行280-281 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[quotコマンド実行] --> B[オプション解析]
    B --> C{-a指定?}
    C -->|Yes| D[全マウント済みUFS走査]
    C -->|No| E[指定ファイルシステム]
    D --> F[quot関数呼び出し]
    E --> F
    F --> G[スーパーブロック読み取り]
    G --> H[iノード全走査]
    H --> I{動作モード}
    I -->|douser| J[ユーザー別使用量集計]
    I -->|dofsizes| K[ファイルサイズ分布集計]
    I -->|donames| L[iノード名前解決]
    J --> M[ソート・出力]
    K --> M
    L --> M
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| デバイスオープン失敗 | rawデバイスにアクセスできない | warn("%s") | 次のFSに進む |
| スーパーブロック読み取り失敗 | UFS SBが見つからない | "Cannot find file system superblock" | 次のFSに進む |
| メモリ不足 | malloc/calloc失敗 | "allocate users" / "allocate inodes" | errx(1,...) で終了 |
| 不正iノード | 不明なIFMT | "unknown IFMT 0%o" | errx(1,...) で終了 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ファイルシステム内の全iノード数（数万〜数百万） |
| 目標出力時間 | ファイルシステムサイズに比例 |
| 同時出力数上限 | 制限なし |

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

- rawデバイスへの直接アクセスが必要なためroot権限が必須
- ファイルシステム全体のiノード走査を行うため、全ユーザーのファイル情報にアクセス

## 備考

- UFS1とUFS2の両方をサポート（DIPマクロで抽象化、行99-101）
- -k オプションでブロックサイズを1024に固定可能
- -N オプションでUID数値表示
- get_inode()にはiノードバッファキャッシュ機構がある（行106-151）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | quot.c | `usr.sbin/quot/quot.c` | struct user（行173-181）：ユーザー別集計構造体、struct fsizes（行285-290）：サイズ分布構造体 |
| 1-2 | dinode.h | `ufs/ufs/dinode.h` | union dinode、struct ufs1_dinode / ufs2_dinode |
| 1-3 | fs.h | `ufs/ffs/fs.h` | struct fs（スーパーブロック構造体） |

**読解のコツ**: DIPマクロ（行99-101）でUFS1/UFS2のフィールドアクセスを抽象化している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | quot.c | `usr.sbin/quot/quot.c` | main()（行476-532）：オプション解析、ファイルシステム走査 |

**主要処理フロー**:
1. **行481**: デフォルト動作関数をdouserに設定
2. **行483-512**: getoptによるオプション解析（-a, -c, -f, -k, -N, -n, -v）
3. **行519-523**: -a時はgetmntinfo()で全マウント済みUFSを走査
4. **行524-530**: 指定ファイルシステムをquot()で処理

#### Step 3: ファイルシステム処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | quot.c | `usr.sbin/quot/quot.c` | quot()（行441-473）：デバイスオープン、スーパーブロック読取り、動作関数呼出し |
| 3-2 | quot.c | `usr.sbin/quot/quot.c` | get_inode()（行103-151）：iノードキャッシュ付き読取り、isfree()（行153-171） |
| 3-3 | quot.c | `usr.sbin/quot/quot.c` | douser()（行355-389）、dofsizes()（行307-352）、donames()（行392-431） |

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

```
main() [quot.c:476]
    |
    +-- getopt() [オプション解析]
    |
    +-- getmntinfo() / getmntpoint() [FS列挙]
    |
    +-- quot() [quot.c:441]
            |
            +-- get_inode(-1,...) [キャッシュフラッシュ]
            +-- inituser() / initfsizes()
            +-- sbget() [スーパーブロック読取り]
            |
            +-- douser() / dofsizes() / donames()
                    |
                    +-- get_inode() [iノード読取り]
                    +-- isfree() [フリー判定]
                    +-- uses() [集計]
                    +-- user() [ユーザー解決]
                    +-- sortusers() [qsort]
```

### データフロー図

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

raw device ──────────> sbget(): SB読取り ──────────> stdout
(UFS iノード)          get_inode(): iノード読取り       (テキスト)
                       douser(): ユーザー別集計
/etc/passwd ─────────> user(): UID→名前変換
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| quot.c | `usr.sbin/quot/quot.c` | ソース | メインプログラム全体（単一ファイル） |
| dinode.h | `ufs/ufs/dinode.h` | ヘッダ | iノード構造体定義 |
| fs.h | `ufs/ffs/fs.h` | ヘッダ | スーパーブロック構造体定義 |
| Makefile | `usr.sbin/quot/Makefile` | ビルド | ビルド設定 |
