# 帳票設計書 10-lastlogin - 最終ログイン情報レポート

## 概要

本ドキュメントは、FreeBSDシステムにおける最終ログイン情報レポート(lastlogin)の帳票設計書である。lastloginコマンドは各ユーザーの最後のログイン情報（ログイン日時、TTYデバイス、接続元ホスト）をutmpxデータベースから読み取り、テキスト形式またはlibxo形式で出力する。

### 本帳票の処理概要

**業務上の目的・背景**：システム管理者がユーザーの最終ログイン日時を確認し、長期間ログインしていないアカウントの検出やセキュリティ監査に活用するためのレポートである。アカウント管理ポリシーの適用状況確認にも利用される。

**帳票の利用シーン**：不要アカウントの洗い出し、セキュリティ監査（異常なログイン元の検出）、ユーザーアカウントの棚卸し、コンプライアンス対応。

**主要な出力内容**：
1. ユーザー名
2. TTYデバイス名
3. 接続元ホスト名
4. 最終ログイン日時

**帳票の出力タイミング**：コマンド実行で即時出力。

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

## 帳票種別

一覧表（テキスト/libxo形式の最終ログイン情報レポート）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | ターミナル/コンソール | N/A | `lastlogin [-f file] [-rt] [user ...]` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力）またはlibxo形式（JSON/XML等） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A |
| 出力方法 | 標準出力への直接出力（xo_emit使用） |
| 文字コード | ASCII |

## 帳票レイアウト

### レイアウト概要

last(1)コマンドと同様のフォーマットで各ユーザーのログイン情報を1行ずつ出力する。

```
username   ttyname  hostname                Mon DD HH:MM:SS YYYY
```

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | user | ユーザー名 | utmpx.ut_user | 左詰め文字列 | 10桁（%-10s） |
| 2 | tty | TTYデバイス名 | utmpx.ut_line | 左詰め文字列 | 8桁（%-8s） |
| 3 | from | 接続元ホスト名 | utmpx.ut_host | 左詰め文字列（最大22文字） | 22桁（%-22.22s） |
| 4 | login-time | 最終ログイン日時 | utmpx.ut_tv.tv_sec → ctime() | ctime形式（24文字） | 24桁（%.24s） |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| ユーザー指定 | コマンドライン引数でユーザー名を指定 | No（省略時は全ユーザー） |
| -fオプション | デフォルト以外のlastlogデータベースを指定 | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | ユーザー名（デフォルト） | 昇順（utcmp_user関数、61-67行目） |
| 1 | ログイン時刻（-tオプション時） | 昇順（utcmp_time関数、69-77行目） |
| N/A | -rオプションで逆順 | order変数を-1に設定 |

### 改ページ条件

改ページ機能なし

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| UTXDB_LASTLOGIN | 最終ログイン情報データベース | setutxdb(UTXDB_LASTLOGIN, file) |

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

#### utmpxレコード

| 参照項目（カラム名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| ut_user | ユーザー名 | 全レコード | 最大32文字 |
| ut_line | TTYデバイス名 | 全レコード | 例: pts/0, ttyv0 |
| ut_host | 接続元ホスト名 | 全レコード | 例: 192.168.1.1, host.example.com |
| ut_tv.tv_sec | ログイン日時 | 全レコード | time_t型、ctime()で文字列変換 |
| ut_type | レコードタイプ | USER_PROCESSのみ対象 | 130行目のフィルタ |

## 計算仕様

### 計算項目一覧

特別な計算項目なし。utmpxレコードの値をそのまま出力する。

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コマンド実行] --> B[xo_parse_args: libxo引数解析]
    B --> C[getoptでオプション解析 -f -r -t]
    C --> D{ユーザー指定あり?}
    D -->|Yes| E[指定ユーザーループ]
    E --> F[setutxdb UTXDB_LASTLOGIN]
    F --> G[getutxuser: 指定ユーザーのレコード取得]
    G --> H[output: 1行出力]
    H --> I[endutxent]
    I --> J{次のユーザー?}
    J -->|Yes| F
    J -->|No| K[xo_finish → 終了]
    D -->|No| L[setutxdb UTXDB_LASTLOGIN]
    L --> M[getutxentループ: 全レコード取得]
    M --> N{ut_type == USER_PROCESS?}
    N -->|Yes| O[ulist配列に追加]
    N -->|No| M
    O --> P{次のレコード?}
    P -->|Yes| M
    P -->|No| Q[endutxent]
    Q --> R[qsort: ソート utcmp関数]
    R --> S[ulistループ: output出力]
    S --> K
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| lastlogデータベースオープン失敗 | setutxdb失敗 | xo_err(1, "failed to open lastlog database") | lastlogファイルの存在・権限確認 |
| ユーザー未発見 | getutxuserがNULL返却 | xo_warnx("user '%s' not found", argv[i]) | ユーザー名確認 |
| メモリ確保失敗 | reallocがNULL返却 | xo_err(1, "malloc") | メモリ不足の解消 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | ユーザー数（通常数十～数百） |
| 目標出力時間 | 即時（lastlogデータベースは小規模） |
| 同時出力数上限 | N/A |

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

- lastlogデータベースへの読み取り権限が必要
- ユーザーのログイン情報（接続元ホスト含む）はプライバシーに関わる情報
- -fオプションで任意ファイルを指定可能（OS側のファイルパーミッションで制御）

## 備考

- LASTLOGIN_XO_VERSION "1" でlibxo構造化出力をバージョン管理（50行目）
- output関数（157-167行目）はlast(1)コマンドの出力フォーマットを模倣
- xo_attr("seconds", "%lu", t)で秒数属性を出力（libxo構造化出力時、164行目）
- 全ユーザー表示モードでは16件ずつrealloc（132行目）
- ユーザー名指定時は各ユーザーごとにsetutxdb→getutxuser→endutxentのサイクルを実行

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lastlogin.c | `usr.sbin/lastlogin/lastlogin.c` | 36-46行目: インクルードファイル。utmpx.hでstruct utmpx定義を参照 |
| 1-2 | lastlogin.c | `usr.sbin/lastlogin/lastlogin.c` | 57-59行目: グローバル変数。order（ソート順）、file（データベースパス）、utcmp（比較関数ポインタ） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lastlogin.c | `usr.sbin/lastlogin/lastlogin.c` | 79-153行目: main関数 |

**主要処理フロー**:
1. **85行目**: xo_parse_args()でlibxo引数処理
2. **89行目**: getopt()で3つのオプション(-f, -r, -t)解析
3. **107-109行目**: xo_set_version/xo_open_container/xo_open_listでlibxo構造化出力開始
4. **111-122行目**: ユーザー指定時のループ（setutxdb→getutxuser→output→endutxent）
5. **123-145行目**: 全ユーザーモード（getutxentループ→USER_PROCESSフィルタ→ulist蓄積→qsort→output）

#### Step 3: ソート処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lastlogin.c | `usr.sbin/lastlogin/lastlogin.c` | 61-77行目: utcmp_user関数（ユーザー名ソート）、utcmp_time関数（時刻ソート） |

**読解のコツ**: order変数（デフォルト1、-r時は-1）をstrcmp/時刻比較の結果に乗算することで昇順/降順を切り替え。

#### Step 4: 出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | lastlogin.c | `usr.sbin/lastlogin/lastlogin.c` | 157-167行目: output関数。xo_open_instance→xo_emit→xo_attr→xo_emit→xo_close_instance |

**注目ポイント**:
- 162行目: `{:user/%-10s/%s}`でユーザー名10桁左詰め
- 162行目: `{:tty/%-8s/%s}`でTTY8桁左詰め
- 162行目: `{:from/%-22.22s/%s}`でホスト名22桁最大22文字
- 164行目: xo_attr("seconds", ...)で構造化出力時に秒数属性を追加
- 165行目: `{:login-time/%.24s/%.24s}`でctime形式24文字

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

```
main() [79行目]
    |
    +-- xo_parse_args() [85行目] ... libxo引数解析
    +-- getopt() [89行目] ... オプション解析
    +-- xo_set_version() [107行目]
    +-- xo_open_container("lastlogin-information") [108行目]
    +-- xo_open_list("lastlogin") [109行目]
    |
    +-- [ユーザー指定時]
    |      +-- setutxdb(UTXDB_LASTLOGIN) [114行目]
    |      +-- getutxuser() [116行目]
    |      +-- output() [120行目]
    |      +-- endutxent() [121行目]
    |
    +-- [全ユーザー時]
    |      +-- setutxdb(UTXDB_LASTLOGIN) [125行目]
    |      +-- getutxent()ループ [129行目]
    |      +-- endutxent() [140行目]
    |      +-- qsort(ulist, ..., utcmp) [142行目]
    |      +-- outputループ [143-144行目]
    |
    +-- xo_close_list/xo_close_container [147-148行目]
    +-- xo_finish() [149行目]

output() [157行目]
    |
    +-- xo_open_instance("lastlogin") [161行目]
    +-- xo_emit() [162-163行目] ... ユーザー名/TTY/ホスト
    +-- xo_attr("seconds") [164行目] ... 秒数属性
    +-- xo_emit() [165行目] ... ログイン日時（ctime形式）
    +-- xo_close_instance("lastlogin") [166行目]
```

### データフロー図

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

UTXDB_LASTLOGIN ─────▶ setutxdb() + getutxent()       ──▶ 標準出力
  (lastlogデータベース)       |                                (xo_emit)
                             +-- USER_PROCESSフィルタ
                             +-- ulist配列に蓄積
                             +-- qsort(utcmp_user or utcmp_time)
                             +-- output(): xo_emit出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lastlogin.c | `usr.sbin/lastlogin/lastlogin.c` | ソース | 全処理が単一ファイルに集約（175行） |
