# 帳票設計書 11-lastcomm - 最終実行コマンドレポート

## 概要

本ドキュメントは、FreeBSD の `lastcomm` コマンドが出力する最終実行コマンドレポートの設計仕様を記述する。

### 本帳票の処理概要

lastcomm は、プロセスアカウンティングファイルから最後に実行されたコマンドの一覧を逆順（最新順）に表示するレポートを生成するユーティリティである。

**業務上の目的・背景**：システム管理者がユーザーのコマンド実行履歴を監査・追跡するために使用される。セキュリティ監査、リソース使用量の把握、不正アクセスの検出、障害発生時の操作履歴確認などの業務課題を解決する。プロセスアカウンティングが有効化されたシステムにおいて、過去に実行されたコマンドの詳細情報を提供する。

**帳票の利用シーン**：セキュリティインシデント発生時の操作履歴調査、ユーザーの作業内容確認、システムリソース使用状況の監査、定期的なシステム利用状況レビューなどの場面で利用される。

**主要な出力内容**：
1. コマンド名（最大AC_COMM_LEN文字）
2. フラグビット（スーパーユーザー実行、フォーク、互換モード、コアダンプ、シグナル終了）
3. ユーザー名（UIDから変換）
4. 端末デバイス名（ttyデバイス）
5. CPU時間（ユーザー時間+システム時間、個別表示も可）
6. 経過時間
7. 開始時刻、終了時刻

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

**帳票の利用者**：システム管理者、セキュリティ監査担当者

## 帳票種別

一覧表（プロセスアカウンティングレコードの時系列一覧）

## 利用画面

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

## 出力形式

### 基本仕様

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

## 帳票レイアウト

### レイアウト概要

1行1レコード形式で、各フィールドがスペース区切りで出力される。ヘッダー行はなく、デフォルトではファイル末尾（最新）から先頭（最古）の順に表示される。

```
┌──────────────────────────────────────────────────────────────┐
│ コマンド名  フラグ  ユーザー名  端末名  時間情報  開始時刻   │
│ (繰り返し)                                                   │
└──────────────────────────────────────────────────────────────┘
```

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | コマンド名 | 実行されたコマンド名 | acctv3.ac_comm | 左寄せ、AC_COMM_LEN幅 | 最大16文字 |
| 2 | フラグ | プロセスフラグ（S/F/C/D/X） | acctv3.ac_flagx | "-"接頭辞付きフラグ文字列 | 最大7文字 |
| 3 | ユーザー名 | 実行ユーザー名 | acctv3.ac_uid（user_from_uid変換） | 左寄せ、MAXLOGNAME-1幅 | 最大15文字 |
| 4 | 端末デバイス | 制御端末名 | acctv3.ac_tty（devname変換） | 左寄せ | 8文字 |
| 5 | CPU時間 | ユーザー+システム時間 | ac_utime + ac_stime | "%6.3f secs"形式 | 可変 |
| 6 | ユーザー時間 | ユーザーCPU時間（-uオプション） | acctv3.ac_utime | "%6.3f us"形式 | 可変 |
| 7 | システム時間 | システムCPU時間（-sオプション） | acctv3.ac_stime | "%6.3f sy"形式 | 可変 |
| 8 | 経過時間 | 壁時計時間（-eオプション） | acctv3.ac_etime | "%8.3f es"形式 | 可変 |
| 9 | 開始時刻 | コマンド開始時刻（-Sオプション） | acctv3.ac_btime | "%.19s"形式（ctime） | 19文字 |
| 10 | 終了時刻 | コマンド終了時刻（-Eオプション） | ac_btime + ac_etime | "%.19s"形式（ctime） | 19文字 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| コマンド名フィルタ | 指定コマンド名に一致するレコードのみ出力 | No |
| ユーザー名フィルタ | 指定ユーザー名に一致するレコードのみ出力 | No |
| 端末名フィルタ | 指定端末名に一致するレコードのみ出力 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | レコード順（ファイル内位置） | 降順（最新が先頭、ファイル末尾から読み取り） |

### 改ページ条件

改ページなし（連続的にレコードを出力）

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| プロセスアカウンティングファイル（/var/account/acct） | コマンド実行レコード | ファイル全体を逆順に読み取り |
| パスワードデータベース | UID→ユーザー名変換 | ac_uid |
| デバイスデータベース | dev_t→デバイス名変換 | ac_tty |

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

#### プロセスアカウンティングファイル（struct acctv3）

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| ac_comm | コマンド名 | 全レコード | 非印字文字は'?'に置換（行141-142） |
| ac_flagx | フラグ | 全レコード | ASU/AFORK/ACOMPAT/ACORE/AXSIGビット |
| ac_uid | ユーザー名 | 全レコード | user_from_uid()で変換 |
| ac_tty | 端末デバイス | 全レコード | devname()で変換、NODEVは"__" |
| ac_utime | ユーザーCPU時間 | フラグ依存 | マイクロ秒単位、1000000で除算 |
| ac_stime | システムCPU時間 | フラグ依存 | マイクロ秒単位、1000000で除算 |
| ac_etime | 経過時間 | フラグ依存 | マイクロ秒単位、1000000で除算 |
| ac_btime | 開始時刻 | フラグ依存 | time_t型（エポック秒） |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| CPU時間（秒） | (ac_utime + ac_stime) / 1000000 | 小数点以下3桁 | デフォルト表示 |
| ユーザー時間（秒） | ac_utime / 1000000 | 小数点以下3桁 | -uオプション時 |
| システム時間（秒） | ac_stime / 1000000 | 小数点以下3桁 | -sオプション時 |
| 経過時間（秒） | ac_etime / 1000000 | 小数点以下3桁 | -eオプション時 |
| 終了時刻 | ac_btime + (time_t)(ac_etime / 1000000) | 秒単位切り捨て | -Eオプション時 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[lastcommコマンド実行] --> B[オプション解析]
    B --> C{入力ソース判定}
    C -->|ファイル| D[ファイルオープン・末尾シーク]
    C -->|標準入力| E[標準入力読み取り準備]
    D --> F[レコード逆順読み取りループ]
    E --> G[レコード順方向読み取りループ]
    F --> H[非印字文字の置換]
    G --> H
    H --> I{フィルタ条件一致?}
    I -->|No| F
    I -->|Yes| J[フォーマット出力]
    J --> K{次レコードあり?}
    K -->|Yes| F
    K -->|No| L[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ファイルオープン失敗 | アカウンティングファイルが存在しない | "could not open %s" | err(1,...) で終了 |
| シーク失敗 | ファイル末尾へのシークが失敗 | "seek to end of %s failed" | err(1,...) で終了 |
| レコード読み取り失敗 | ファイル読み取りエラー | "read record from %s failed" | err(1,...) で終了 |
| stdout書き込み失敗 | 出力先への書き込みエラー | "stdout" | err(1,...) で終了 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | アカウンティングファイルサイズに依存（数万〜数百万レコード） |
| 目標出力時間 | ファイルI/O速度に依存 |
| 同時出力数上限 | 制限なし |

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

- アカウンティングファイル（/var/account/acct）は通常root権限でのみ読み取り可能
- ユーザーIDからユーザー名への変換にパスワードデータベースを参照
- 出力にはコマンド実行履歴が含まれるため、機密情報を含む可能性がある

## 備考

- デフォルトのアカウンティングファイルパスは `_PATH_ACCT`（`/var/account/acct`）で定義される（pathnames.h）
- `-f` オプションでアカウンティングファイルを指定可能（`-` で標準入力）
- 標準入力からの読み取り時は順方向（readrec_forward）、ファイルからは逆方向（readrec_backward）で読み取る
- `+format` 引数で時刻のカスタムフォーマットを strftime 形式で指定可能

---

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

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

### 推奨読解順序

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

プロセスアカウンティングレコードの構造体 `acctv3` を理解することが最も重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | acct.h | `sys/sys/acct.h` | struct acctv3 の定義、フラグ定数（ASU, AFORK, ACOMPAT, ACORE, AXSIG）、AC_COMM_LEN の値 |
| 1-2 | pathnames.h | `usr.bin/lastcomm/pathnames.h` | _PATH_ACCT の定義（デフォルトアカウンティングファイルパス） |

**読解のコツ**: acctv3 は v1/v2 との後方互換構造を持つ。ac_utime, ac_stime, ac_etime はマイクロ秒単位の浮動小数点数である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lastcomm.c | `usr.bin/lastcomm/lastcomm.c` | main() 関数のオプション解析（行80-110）、読み取り方向の決定（行126-136）、メインループ（行138-197） |

**主要処理フロー**:
1. **行78**: デフォルトアカウンティングファイルパス設定
2. **行80-110**: getopt によるオプション解析（-f, -u, -s, -e, -c, -S, -E）
3. **行113-115**: デフォルトフラグ設定（AC_CTIME | AC_BTIME）
4. **行126-136**: 入力ソース判定と読み取り関数の選択
5. **行138-197**: レコード読み取り・フィルタ・出力のメインループ

#### Step 3: レコード読み取り層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | readrec.c | `usr.bin/lastcomm/readrec.c` | readrec_forward() と readrec_backward() の実装、acctv2/v3 変換ロジック |

**主要処理フロー**:
- readrec_backward: ファイル末尾から逆順にレコードを読み取る
- readrec_forward: 標準入力等から順方向にレコードを読み取る

#### Step 4: ユーティリティ関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | lastcomm.c | `usr.bin/lastcomm/lastcomm.c` | flagbits()（行206-222）: フラグビットの文字列化、getdev()（行241-254）: デバイス番号の名前変換、requested()（行224-238）: フィルタ条件一致判定 |

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

```
main() [lastcomm.c:66]
    |
    +-- getopt() [オプション解析]
    |
    +-- fopen() / stdin [入力ソース]
    |
    +-- readrec_backward() / readrec_forward() [readrec.c]
    |       |
    |       +-- fread() [レコード読み取り]
    |       +-- fseek() [逆順シーク]
    |
    +-- requested() [lastcomm.c:224]
    |       |
    |       +-- user_from_uid() [UID変換]
    |       +-- getdev() [デバイス名変換]
    |
    +-- flagbits() [lastcomm.c:206]
    |
    +-- printf() [フォーマット出力]
    |
    +-- ctime() / strftime() [時刻フォーマット]
```

### データフロー図

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

/var/account/acct ──────> readrec_backward() ──> フィルタ判定 ──> stdout
(acctv3 レコード)           readrec_forward()     requested()    (テキスト)
                                |                    |
                           レコード変換           UID/tty変換
                           (v2->v3)           user_from_uid()
                                              devname()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lastcomm.c | `usr.bin/lastcomm/lastcomm.c` | ソース | メインプログラム、オプション解析、出力フォーマット |
| readrec.c | `usr.bin/lastcomm/readrec.c` | ソース | レコード読み取り（順方向・逆方向） |
| pathnames.h | `usr.bin/lastcomm/pathnames.h` | ヘッダ | デフォルトアカウンティングファイルパス定義 |
| acct.h | `sys/sys/acct.h` | ヘッダ | acctv3 構造体、フラグ定数定義 |
| Makefile | `usr.bin/lastcomm/Makefile` | ビルド | ビルド設定 |
