# 機能設計書 160-実行ファイルパス取得

## 概要

本ドキュメントは、libuvライブラリにおけるuv_exepath()関数による現在の実行ファイルパス取得機能の設計を記述する。

### 本機能の処理概要

uv_exepath()関数は、現在実行中のプログラムの実行ファイルの絶対パスをクロスプラットフォームで取得する機能を提供する。

**業務上の目的・背景**：アプリケーションが自身の実行ファイルの位置を把握する必要がある場面は多い。設定ファイルやリソースファイルの相対パス解決、自動更新機能での実行ファイル特定、ログへの実行ファイルパス記録、子プロセスの再起動などにおいて、実行ファイルのパスを正確に取得するニーズがある。各プラットフォームで異なるメカニズム（_NSGetExecutablePath、/proc/self/exe、GetModuleFileNameW等）を統一的にラップする。

**機能の利用シーン**：アプリケーション起動時のリソースディレクトリ特定、設定ファイルの自動検索パス構築、自動アップデート機能での実行ファイル特定、ログ出力への実行ファイル情報埋め込み、ワーカープロセス起動時の自身のパス取得などに利用される。

**主要な処理内容**：
1. 引数（buffer, size）のNULLチェックとゼロサイズチェック
2. プラットフォーム固有のAPIで実行ファイルパスを取得
3. 必要に応じてシンボリックリンクの解決（realpath）
4. 結果をバッファにコピーしてNUL終端

**関連システム・外部連携**：
- macOS: _NSGetExecutablePath() + realpath()
- Linux: readlink("/proc/self/exe")
- Windows: GetModuleFileNameW() + UTF-16→UTF-8変換

**権限による制御**：特別な権限は不要。一般ユーザー権限で実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | その他ユーティリティ | 主機能 | uv_exepath()による実行ファイルパス取得のAPI定義 |

## 機能種別

データ取得処理（実行ファイルパスの読み取り）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| buffer | char* | Yes | パスを格納するバッファ | NULLの場合UV_EINVAL |
| size | size_t* | Yes | バッファサイズ（入力）／実際の長さ（出力） | NULLまたは*size==0の場合UV_EINVAL |

### 入力データソース

呼び出し元からのバッファポインタとサイズ。パス情報はOSカーネル/ファイルシステムから取得する。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| buffer | char* | NUL終端された実行ファイルの絶対パス |
| *size | size_t | パスの長さ（NUL終端を含まない） |
| 戻り値 | int | 成功時0、失敗時負のエラーコード |

### 出力先

呼び出し元が提供するバッファに書き込む。

## 処理フロー

### 処理シーケンス

```
1. 引数バリデーション
   └─ buffer==NULL, size==NULL, *size==0の場合UV_EINVALを返す

2. [macOS] _NSGetExecutablePath()で相対パス取得
   ├─ 失敗時UV_EIOを返す
   ├─ realpath()で絶対パスに解決
   ├─ 失敗時はerrnoをlibuvエラーに変換
   └─ abspath_sizeが0の場合UV_EIOを返す

3. [Linux] readlink("/proc/self/exe")でパス取得
   ├─ n = *size - 1 でバッファサイズを制限
   ├─ readlink()でシンボリックリンクを読み取り
   ├─ 失敗時はerrnoをlibuvエラーに変換
   └─ NUL終端を設定

4. [Windows] GetModuleFileNameW()でUTF-16パスを取得
   └─ WideCharToMultiByte()でUTF-8に変換

5. バッファにパスをコピーし*sizeを更新
6. 正常完了（0を返す）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{buffer==NULL or size==NULL or *size==0?}
    B -->|Yes| C[return UV_EINVAL]
    B -->|No| D{プラットフォーム}
    D -->|macOS| E[_NSGetExecutablePath]
    D -->|Linux| F[readlink /proc/self/exe]
    D -->|Windows| G[GetModuleFileNameW]
    E --> H{成功?}
    H -->|No| I[return UV_EIO]
    H -->|Yes| J[realpath で絶対パス解決]
    J --> K{成功?}
    K -->|No| L[return UV__ERR errno]
    K -->|Yes| M[パス長計算]
    F --> N{readlink成功?}
    N -->|No| O[return UV__ERR errno]
    N -->|Yes| P[NUL終端設定]
    G --> Q[UTF-16→UTF-8変換]
    M --> R{パス長 <= *size?}
    R -->|Yes| S[バッファにコピー]
    R -->|No| T[*size分だけコピー]
    P --> U[*size = n]
    S --> V[*size = パス長]
    T --> V
    U --> W[return 0]
    V --> W
    Q --> W
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-160-01 | NULLチェック | buffer, sizeがNULLまたは*sizeが0の場合UV_EINVAL | 常時 |
| BR-160-02 | macOS realpath | macOSでは_NSGetExecutablePath()の結果をrealpath()で絶対パスに解決する | macOSプラットフォーム |
| BR-160-03 | macOSバッファサイズ | macOSではPATH_MAX*2+1の内部バッファを使用（realpathの結果がPATH_MAXを超える可能性への対応） | macOSプラットフォーム |
| BR-160-04 | Linuxシンボリックリンク | Linuxでは/proc/self/exeはシンボリックリンクであり、readlink()で解決する | Linuxプラットフォーム |
| BR-160-05 | バッファサイズ制限 | Linuxではreadlink()に渡すバッファサイズを*size-1に制限し、NUL終端分を確保 | Linuxプラットフォーム |

### 計算ロジック

特別な計算ロジックはない。

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

該当なし（データベース操作は行わない）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | 引数不正 | buffer==NULL, size==NULL, *size==0 | 有効な引数を渡す |
| UV_EIO | I/Oエラー | _NSGetExecutablePath()失敗、またはパス長が0 | 環境を確認 |
| UV__ERR(errno) | システムエラー | readlink()/realpath()失敗 | ファイルシステムの状態を確認 |

### リトライ仕様

リトライは不要。

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

該当なし。

## パフォーマンス要件

ファイルシステムへのアクセスを伴うが、/proc/self/exeはprocfs経由の仮想パスであり高速。macOSのrealpath()はファイルシステムへのアクセスが発生するが、通常は即座に完了する。

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

実行ファイルパスはファイルシステム上の位置情報を含む。攻撃者がアプリケーションの配置場所を知る手がかりになる可能性がある。symlink攻撃への耐性はrealpath()による正規化で対応している（macOS）。

## 備考

- macOS実装では`PATH_MAX * 2 + 1`サイズの内部バッファを使用している。これは「realpath(exepath)がPATH_MAXを超える可能性がある」ためのコメントがソースコードに記されている。
- Linux実装ではprocfs-exepath.cに汎用的なreadlink("/proc/self/exe")ベースの実装がある。
- 各プラットフォーム（AIX, FreeBSD, NetBSD, OpenBSD, Haiku, QNX等）にそれぞれ固有の実装がある。

---

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

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

### 推奨読解順序

#### Step 1: API宣言を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | uv_exepath()のAPI宣言（1825行目） |

**読解のコツ**: `UV_EXTERN int uv_exepath(char* buffer, size_t* size);` - bufferにパス文字列を、*sizeにパスの長さを格納する。

#### Step 2: macOS実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | darwin.c | `src/unix/darwin.c` | macOS版uv_exepath()実装 |

**主要処理フロー**:
- **66行目**: 関数エントリーポイント
- **68行目**: `char abspath[PATH_MAX * 2 + 1]` - 大きめの内部バッファ
- **73-74行目**: 引数NULLチェック
- **77-78行目**: `_NSGetExecutablePath(exepath, &exepath_size)` 呼び出し
- **80-81行目**: `realpath(exepath, abspath)` でシンボリックリンク解決
- **83-85行目**: パス長計算と空文字列チェック

#### Step 3: Linux実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | procfs-exepath.c | `src/unix/procfs-exepath.c` | procfsベースの汎用実装 |

**主要処理フロー**:
- **28行目**: 関数エントリーポイント
- **31-32行目**: 引数NULLチェック
- **34-36行目**: `readlink("/proc/self/exe", buffer, n)` でパス取得
- **38-39行目**: readlink失敗時のエラー処理
- **41行目**: `buffer[n] = '\0'` でNUL終端
- **42行目**: `*size = n` で長さ設定

#### Step 4: Windows実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | util.c | `src/win/util.c` | Windows版uv_exepath()実装 |

**主要処理フロー**:
- **97行目**: 関数エントリーポイント
- GetModuleFileNameW()でUTF-16パスを取得後、UTF-8に変換

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

```
uv_exepath(buffer, size)
    |
    +-- [macOS] _NSGetExecutablePath(exepath, &exepath_size)
    |       +-- realpath(exepath, abspath)        ... シンボリックリンク解決
    |       +-- strlen(abspath)
    |       +-- memcpy(buffer, abspath, ...)
    |
    +-- [Linux] readlink("/proc/self/exe", buffer, n)
    |       +-- NUL終端設定
    |
    +-- [Windows] GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len)
            +-- WideCharToMultiByte()             ... UTF-16→UTF-8変換
```

### データフロー図

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

buffer (char*)      ----> uv_exepath()                 ---> buffer にパス文字列
size (size_t*)            |                                  *size にパス長
                          +-- _NSGetExecutablePath /         戻り値: 0 or error
                              readlink / GetModuleFileNameW
                          +-- realpath (macOS)
                          +-- memcpy / NUL終端
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言 |
| darwin.c | `src/unix/darwin.c` | ソース | macOS版uv_exepath()実装 |
| procfs-exepath.c | `src/unix/procfs-exepath.c` | ソース | procfsベースの汎用実装（Linux等） |
| freebsd.c | `src/unix/freebsd.c` | ソース | FreeBSD版uv_exepath()実装 |
| netbsd.c | `src/unix/netbsd.c` | ソース | NetBSD版uv_exepath()実装 |
| openbsd.c | `src/unix/openbsd.c` | ソース | OpenBSD版uv_exepath()実装 |
| aix.c | `src/unix/aix.c` | ソース | AIX版uv_exepath()実装 |
| aix-common.c | `src/unix/aix-common.c` | ソース | AIX共通ヘルパー |
| sunos.c | `src/unix/sunos.c` | ソース | Solaris版uv_exepath()実装 |
| haiku.c | `src/unix/haiku.c` | ソース | Haiku版uv_exepath()実装 |
| qnx.c | `src/unix/qnx.c` | ソース | QNX版uv_exepath()実装 |
| util.c | `src/win/util.c` | ソース | Windows版uv_exepath()実装 |
