# 機能設計書 84-日時・環境情報

## 概要

本ドキュメントは、FreeBSDにおける日時・環境情報コマンド群（date、hostname、freebsd-version、uuidgen）の機能設計を記述する。これらはシステムの日時表示・設定、ホスト名の取得・設定、OSバージョン情報の取得、UUID生成を行うベースシステムコマンドである。

### 本機能の処理概要

**業務上の目的・背景**：日時・環境情報コマンドはシステム識別と時刻管理の基盤を提供する。スクリプトでのタイムスタンプ生成、ログ出力の日時付与、システム識別情報の取得、一意識別子の生成など、あらゆるシステム管理・運用タスクの基礎として利用される。

**機能の利用シーン**：システム時刻の表示・設定（date）、ネットワークホスト名の表示・設定（hostname）、FreeBSDバージョンの確認（freebsd-version）、データベースやファイルの一意識別子生成（uuidgen）。RCスクリプトやインストーラからも広く参照される。

**主要な処理内容**：
1. date: システム日時の表示（strftime形式）・設定。ISO 8601/RFC 2822フォーマット対応、ナノ秒精度、日時調整機能
2. hostname: gethostname(3)/sethostname(3)によるホスト名の表示・設定。短縮名(-s)・ドメイン名(-d)の抽出
3. freebsd-version: カーネル・ユーザランド・実行中カーネルの各バージョン情報を表示するシェルスクリプト
4. uuidgen: UUID v1（時間ベース）およびUUID v4（ランダム）の生成

**関連システム・外部連携**：clock_gettime(2)システムコール、settimeofday(2)、sysctl(kern.osrelease)、loader.conf（freebsd-version）、uuid(3)ライブラリ。

**権限による制御**：日時設定（date -s）はroot権限が必要。ホスト名設定もroot権限が必要。参照系は一般ユーザで実行可能。

## 関連画面

該当なし（CLIコマンドのため画面は存在しない）

## 機能種別

システム情報照会 / システム設定変更

## 入力仕様

### 入力パラメータ

#### date

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| +format | string | No | strftime形式の出力フォーマット | 有効なstrftime書式 |
| -I[FMT] | string | No | ISO 8601形式出力（date/hours/minutes/seconds/ns） | 有効なFMT値 |
| -R | flag | No | RFC 2822形式出力 | - |
| -r seconds | integer | No | エポック秒から日時変換 | 有効な整数値 |
| -v +/-value | string | No | 日時の相対調整 | vary.c対応の調整式 |
| date_string | string | No | 設定する日時文字列 | MMDDhhmm[[CC]YY][.ss]形式 |

#### hostname

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -s | flag | No | 短縮ホスト名のみ表示 | -dと排他 |
| -d | flag | No | ドメイン名のみ表示 | -sと排他 |
| -f | flag | No | FQDN表示（BSD標準と同じ、互換用） | - |
| hostname | string | No | 設定するホスト名 | MAXHOSTNAMELEN以下 |

#### freebsd-version

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -k | flag | No | インストール済みカーネルバージョン表示 | - |
| -r | flag | No | 実行中カーネルバージョン表示 | - |
| -u | flag | No | ユーザランドバージョン表示（デフォルト） | - |
| -j jail | string | No | 指定jail内のバージョン表示 | 有効なjail名/ID |

#### uuidgen

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -1 | flag | No | 1回のシステムコールで生成 | - |
| -r | flag | No | UUID v4（ランダム）生成 | - |
| -n count | integer | No | 生成するUUID数 | 正の整数 |
| -o filename | string | No | 出力先ファイル | 書き込み可能なパス |

### 入力データソース

システムクロック（clock_gettime）、カーネルパラメータ（sysctl）、loader.conf（カーネルバージョン）、/dev/urandom（UUID v4）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 日時文字列 | string | strftime形式でフォーマットされた日時 |
| ホスト名 | string | FQDNまたは短縮ホスト名 |
| バージョン文字列 | string | FreeBSD XX.X-RELEASE形式 |
| UUID | string | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx形式 |

### 出力先

標準出力（uuidgenは-oオプションでファイル出力も可能）。

## 処理フロー

### 処理シーケンス（date）

```
1. コマンドライン引数解析
   └─ getopt()でオプション解析、ISO 8601/RFC 2822フォーマット選択
2. 現在時刻取得
   └─ clock_gettime(CLOCK_REALTIME)でナノ秒精度の時刻取得
3. 日時調整（-vオプション時）
   └─ vary.c: 相対的な日時調整処理
4. 日時設定（設定モード時）
   └─ setthetime(): settimeofday(2)で日時設定、utmpx記録
5. 日時表示
   └─ strftime_ns(): ナノ秒対応のstrftime拡張フォーマット出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[オプション解析]
    B --> C{設定モード?}
    C -->|Yes| D[setthetime: 日時設定]
    C -->|No| E[clock_gettime: 時刻取得]
    D --> E
    E --> F{-vオプション?}
    F -->|Yes| G[vary: 日時調整]
    F -->|No| H{ISO 8601?}
    G --> H
    H -->|Yes| I[printisodate: ISO形式出力]
    H -->|No| J{RFC 2822?}
    J -->|Yes| K[strftime: RFC形式出力]
    J -->|No| L[strftime_ns: カスタム形式出力]
    I --> M[終了]
    K --> M
    L --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-84-01 | デフォルトISO形式 | ISO 8601の各段階(date/hours/minutes/seconds/ns)を指定可能 | -Iオプション |
| BR-84-02 | RFC 2822形式 | "%a, %d %b %Y %T %z"フォーマット | -Rオプション |
| BR-84-03 | hostnameデフォルト | 引数なしでFQDN表示（-fオプションはLinux互換で無視） | hostname実行時 |
| BR-84-04 | freebsd-versionデフォルト | オプション未指定時は-u（ユーザランドバージョン）を表示 | freebsd-version実行時 |
| BR-84-05 | uuidgen v4 | -rオプションでランダムベースのUUID v4を生成 | -rオプション指定時 |
| BR-84-06 | UUID compact形式 | コンパクト形式（ハイフンなし）出力も可能 | 内部関数uuid_to_compact_string使用 |

### 計算ロジック

date: TM_YEAR_BASE=1900を基準に年を計算。vary.cモジュールで「+1d」（1日後）などの相対日時計算を実行。
uuidgen v4: arc4random()による暗号学的に安全な乱数からUUIDを生成。バージョンビット(0100)とバリアントビット(10xx)を適切に設定。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | 権限エラー | date: 一般ユーザでの日時設定試行 | err()で終了 |
| 1 | 権限エラー | hostname: 一般ユーザでのホスト名設定試行 | err()で終了 |
| 1 | フォーマットエラー | date: 不正な日時文字列 | badformat()で終了 |
| 1 | カーネル不在 | freebsd-version -k: カーネルファイルが見つからない | error()で終了 |
| 1 | UUID生成エラー | uuidgen: uuidgen(2)システムコール失敗 | err()で終了 |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- dateはclock_gettime()の単一システムコールで時刻取得（高速）
- uuidgenは-nオプションで複数UUID一括生成可能（バッチ生成による効率化）
- uuidgenはCapsicum対応でサンドボックス化実行が可能

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

- 日時設定はroot権限が必要（settimeofday(2)のカーネル権限チェック）
- uuidgenはcapsicum_helpers.hを使用しCapsicumサンドボックスモードで動作可能
- UUID v4はarc4random()による暗号学的に安全な乱数を使用

## 備考

- freebsd-versionはシェルスクリプト（freebsd-version.sh.in）からビルド時に生成
- USERLAND_VERSIONはビルド時に@@REVISION@@-@@BRANCH@@が置換される
- freebsd-versionのカーネルバージョン取得はwhat(1)コマンドとsed(1)で実装
- dateのISO 8601対応はiso8601_fmts[]テーブル（68-74行目）で段階的フォーマットを管理

---

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

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

### 推奨読解順序

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

dateコマンドのフォーマット管理構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | date.c | `bin/date/date.c` | iso8601_fmt構造体、iso8601_fmts[]テーブル |
| 1-2 | vary.h | `bin/date/vary.h` | 日時調整モジュールのインタフェース |

**読解のコツ**: `iso8601_fmts[]`テーブル（65-74行目）はdate/hours/minutes/seconds/nsの5段階のISO 8601フォーマットを定義。`iso8601_selected`ポインタで選択された精度を追跡する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | date.c | `bin/date/date.c` | main()関数。オプション解析、時刻取得、フォーマット出力 |

**主要処理フロー**:
1. **51-53行目**: TM_YEAR_BASE=1900定義
2. **55-63行目**: static関数宣言（badformat, iso8601_usage, setthetime, strftime_ns等）
3. **65-74行目**: ISO 8601フォーマットテーブル
4. **77行目**: RFC 2822フォーマット文字列 "%a, %d %b %Y %T %z"

#### Step 3: 日時調整モジュール

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | vary.c | `bin/date/vary.c` | -vオプションの相対日時計算処理 |

#### Step 4: hostname実装

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | hostname.c | `bin/hostname/hostname.c` | gethostname/sethostname、短縮名・ドメイン名抽出 |

**主要処理フロー**:
- **46行目**: MAXHOSTNAMELEN定数による上限
- **50行目**: getopt "fsd" オプション（-f:FQDN互換, -s:短縮名, -d:ドメイン名）
- **75-77行目**: 引数ありの場合sethostname()でホスト名設定
- **79-80行目**: 引数なしの場合gethostname()でホスト名取得

#### Step 5: freebsd-version実装

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | freebsd-version.sh.in | `bin/freebsd-version/freebsd-version.sh.in` | シェルスクリプト。kernel_version/running_version/userland_version関数 |

**主要処理フロー**:
- **31行目**: USERLAND_VERSIONの定義（ビルド時置換）
- **55-58行目**: kernel_file(): loader.confからカーネルパスを決定
- **64-69行目**: kernel_version(): what(1)とsedでカーネルバージョン抽出
- **75-77行目**: running_version(): sysctl kern.osrelease
- **82-84行目**: userland_version(): ハードコード値出力
- **106-161行目**: main(): -k/-r/-u/-jオプション処理

#### Step 6: uuidgen実装

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | uuidgen.c | `bin/uuidgen/uuidgen.c` | UUID生成。v1(時間ベース)/v4(ランダム)対応 |

**主要処理フロー**:
- **29行目**: capsicum.hインクルード（サンドボックス対応）
- **46-69行目**: uuid_to_compact_string(): コンパクト形式出力
- **71-80行目**: uuidgen_v4(): arc4random()によるランダムUUID生成

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

```
date main()
    |
    +-- getopt()                    # オプション解析
    +-- clock_gettime(CLOCK_REALTIME) # 時刻取得
    +-- vary_apply()                # 日時調整（-vオプション時）
    +-- setthetime()                # 日時設定（設定モード時）
    |       +-- settimeofday(2)     # システムコール
    +-- printisodate() / strftime_ns() # 日時出力

hostname main()
    |
    +-- getopt()                    # オプション解析
    +-- sethostname() / gethostname() # ホスト名設定/取得

freebsd-version main()
    |
    +-- kernel_version()            # -k: what + sed
    +-- running_version()           # -r: sysctl kern.osrelease
    +-- userland_version()          # -u: ハードコード値
    +-- jail_version()              # -j: jexec freebsd-version

uuidgen main()
    |
    +-- uuidgen(2)                  # UUID v1生成（システムコール）
    +-- uuidgen_v4()                # UUID v4生成
    |       +-- arc4random()        # 乱数生成
    +-- uuid_to_string()            # 標準形式出力
    +-- uuid_to_compact_string()    # コンパクト形式出力
```

### データフロー図

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

システムクロック ──> date: clock_gettime + strftime ──> 日時文字列
カーネルパラメータ ──> hostname: gethostname ──> ホスト名
loader.conf/sysctl ──> freebsd-version: バージョン抽出 ──> バージョン文字列
/dev/urandom ──> uuidgen: arc4random/uuidgen(2) ──> UUID文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| date.c | `bin/date/date.c` | ソース | dateコマンドメイン |
| vary.c | `bin/date/vary.c` | ソース | 日時調整モジュール |
| vary.h | `bin/date/vary.h` | ヘッダ | vary関数宣言 |
| hostname.c | `bin/hostname/hostname.c` | ソース | hostnameコマンド |
| freebsd-version.sh.in | `bin/freebsd-version/freebsd-version.sh.in` | テンプレート | freebsd-versionスクリプトテンプレート |
| uuidgen.c | `bin/uuidgen/uuidgen.c` | ソース | uuidgenコマンド |
