# 機能設計書 79-シェル（sh / csh）

## 概要

本ドキュメントは、FreeBSD標準のコマンドラインシェルであるsh（Bourneシェル）およびcsh（Cシェル）の機能設計について記述する。shはPOSIX準拠のBourneシェルであり、スクリプト実行およびインタラクティブなコマンド入力の基盤となる。cshはC言語風の構文を持つ対話型シェルである。

### 本機能の処理概要

**業務上の目的・背景**：シェルはユーザとカーネルの間のインタフェースであり、コマンドの入力・解釈・実行、パイプライン処理、リダイレクション、ジョブ制御、変数管理、スクリプト実行など、システム操作の基盤機能を提供する。FreeBSDではshが標準シェルとして/bin/shに配置され、cshは/bin/cshとして提供される。

**機能の利用シーン**：対話的なコマンド入力、シェルスクリプトの実行、RCスクリプトの処理、bsdinstall内のchroot環境シェル、cronジョブのコマンド実行。

**主要な処理内容**：
1. コマンドライン解析（パーサ）: トークン化、構文木の構築
2. コマンド実行（eval）: 組み込みコマンド、外部コマンド、関数の実行
3. 変数管理: シェル変数、環境変数の設定・参照・エクスポート
4. リダイレクションとパイプ: ファイルディスクリプタの操作
5. ジョブ制御: フォアグラウンド/バックグラウンドジョブの管理
6. パラメータ展開: $変数、`コマンド置換`、${パラメータ展開}
7. グロビング: ワイルドカード展開（*, ?, [...])
8. ヒストリ/行編集: libedit(3)による対話的行編集（sh）
9. エイリアス: コマンドエイリアスの定義・展開

**関連システム・外部連携**：fork(2)/exec(2)によるプロセス生成、waitpid(2)によるプロセス待機、pipe(2)/dup2(2)によるパイプ/リダイレクション、signal(3)によるシグナル処理、libedit(3)による行編集。

**権限による制御**：特になし。シェルはログインユーザの権限で実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 32 | 手動設定確認画面 | 遷移先機能 | Yes選択時のchroot環境内シェル起動 |

## 機能種別

コマンドインタプリタ / スクリプト実行エンジン

## 入力仕様

### 入力パラメータ（sh）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -c string | 文字列 | No | 指定文字列をコマンドとして実行 | なし |
| -i | フラグ | No | インタラクティブモード | なし |
| -l | フラグ | No | ログインシェルとして動作 | なし |
| -s | フラグ | No | 標準入力からコマンドを読み取り | なし |
| -e | フラグ | No | エラー時に即座に終了（errexit） | なし |
| -f | フラグ | No | グロビング無効化 | なし |
| -n | フラグ | No | コマンドを実行せず構文チェックのみ | なし |
| -u | フラグ | No | 未定義変数参照でエラー | なし |
| -v | フラグ | No | 入力行をそのまま表示 | なし |
| -x | フラグ | No | 実行前にコマンドを表示（トレース） | なし |
| script | ファイル | No | 実行するスクリプトファイル | なし |

### 入力データソース

- 標準入力（対話モード/パイプ入力）
- スクリプトファイル
- コマンドライン文字列（-c指定）
- 環境変数（PATH, HOME, ENV等）
- プロファイルファイル（.profile, .shrc）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| コマンド出力 | テキスト | 実行されたコマンドの標準出力 |
| エラー出力 | テキスト | シェルおよびコマンドのエラーメッセージ |
| 終了コード | 整数 | 最後に実行されたコマンドの終了コード（$?） |

### 出力先

- 標準出力（fd 1）
- 標準エラー出力（fd 2）
- リダイレクション先のファイル/パイプ

## 処理フロー

### 処理シーケンス

```
sh:
1. 初期化
   └─ ロケール設定、シグナルハンドラ設定、変数初期化
2. プロファイル読み込み（ログインシェル時）
   └─ /etc/profile、~/.profile、$ENV
3. コマンドループ（cmdloop）
   └─ プロンプト表示 → 行読み込み → トークン化 → 解析 → 実行
4. トークン化（lex）
   └─ 入力をトークンに分割
5. 構文解析（parser）
   └─ トークンから構文木を構築
6. 評価・実行（eval）
   └─ 構文木を走査してコマンドを実行
7. 終了処理
   └─ トラップ実行、リソース解放
```

### フローチャート

```mermaid
flowchart TD
    A[sh起動] --> B[初期化]
    B --> C{ログインシェル?}
    C -->|Yes| D[/etc/profile読み込み]
    D --> E[~/.profile読み込み]
    C -->|No| F{ENV設定?}
    E --> F
    F -->|Yes| G[$ENV読み込み]
    F -->|No| H[cmdloop開始]
    G --> H
    H --> I[プロンプト表示]
    I --> J[行読み込み]
    J --> K[トークン化]
    K --> L[構文解析]
    L --> M{コマンド種別}
    M -->|組み込み| N[組み込みコマンド実行]
    M -->|外部| O[fork + exec]
    M -->|関数| P[関数本体実行]
    M -->|パイプ| Q[パイプ構築 + 各コマンド実行]
    N --> R{EOF/exit?}
    O --> R
    P --> R
    Q --> R
    R -->|No| I
    R -->|Yes| S[終了処理]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-79-01 | POSIX準拠 | shはPOSIX.1-2008のシェルコマンド言語仕様に準拠する | sh使用時 |
| BR-79-02 | ログインシェル初期化 | ログインシェルはまず/etc/profileを読み、次に~/.profileを読む | -l指定またはargv[0]が'-'で始まる場合 |
| BR-79-03 | PATH検索 | 外部コマンドはPATH環境変数のディレクトリ順に検索する | 外部コマンド実行時 |
| BR-79-04 | 終了コード | $?には最後に実行されたコマンドの終了コードが格納される | 常時 |
| BR-79-05 | setjmp/longjmp例外処理 | shは例外処理にsetjmp/longjmpを使用する（Cの例外処理がないため） | エラー発生時 |

### 計算ロジック

特になし。

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

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベースは使用しない |

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 127 | コマンド未検出 | PATHにコマンドが見つからない | "command not found"エラー |
| 126 | 実行権限なし | 実行パーミッションがない | "Permission denied"エラー |
| 2 | 構文エラー | スクリプトの構文不正 | "syntax error"メッセージ |
| 1 | 一般エラー | 各種エラー | エラーメッセージ出力 |

### リトライ仕様

リトライは行わない。対話モードではエラー後もプロンプトに戻る。-e（errexit）オプション指定時はエラーで即座に終了。

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

該当なし。

## パフォーマンス要件

- コマンドの起動オーバーヘッドを最小限にするため、組み込みコマンド（cd, echo, test等）はfork/execなしで実行
- PATHキャッシュ（ハッシュテーブル）によるコマンド検索の高速化

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

- PATH環境変数の先頭に"."を含めることは推奨されない（トロイの木馬攻撃のリスク）
- 特権シェル（setuid root）は危険であり通常は使用されない
- ENV変数による自動スクリプト実行のリスク
- コマンド置換（`...` / $(...)）による意図しないコマンド実行のリスク

## 備考

- FreeBSDのshはashベースの実装で、GNU bashとは異なる
- cshはtcshの祖先であり、iconv_stub.cでiconv対応を行っている
- shは約30のソースファイルで構成される比較的大きなプログラム

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | shell.h | `bin/sh/shell.h` | シェルの基本定義を理解する |
| 1-2 | nodes.h | `bin/sh/nodes.h` | 構文木のノード定義を理解する |

**読解のコツ**: shは約30ファイルで構成される大きなプログラム。構文木（nodes.h）、変数管理（var.h）、実行制御（eval.h）の3つのデータ構造が核心。setjmp/longjmpベースの例外処理（error.h）にも注意。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.c | `bin/sh/main.c` | main関数の初期化処理、cmdloop関数のメインループを理解する |

**主要処理フロー**:
1. **68-69行目**: rootpid/rootshellのグローバル変数
2. **70行目**: main_handler（setjmpによる例外処理のジャンプ先）
3. **73-76行目**: reset/cmdloop/read_profile/find_dot_fileのプロトタイプ
4. **86-100行目**: main関数の初期化（setlocale、state管理、setjmpによる例外処理設定）

#### Step 3: パーサ・評価器を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | parser.c | `bin/sh/parser.c` | コマンドラインの解析（トークン化→構文木構築）を理解する |
| 3-2 | eval.c | `bin/sh/eval.c` | 構文木の評価・コマンド実行を理解する |
| 3-3 | exec.c | `bin/sh/exec.c` | 外部コマンドの検索・実行（PATH検索、fork/exec）を理解する |

#### Step 4: その他の主要機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | jobs.c | `bin/sh/jobs.c` | ジョブ制御の実装を理解する |
| 4-2 | var.c | `bin/sh/var.c` | 変数管理の実装を理解する |
| 4-3 | expand.c | `bin/sh/expand.c` | パラメータ展開・グロビングの実装を理解する |
| 4-4 | redir.c | `bin/sh/redir.c` | リダイレクション処理の実装を理解する |
| 4-5 | trap.c | `bin/sh/trap.c` | シグナルトラップの実装を理解する |
| 4-6 | histedit.c | `bin/sh/histedit.c` | libedit(3)によるヒストリ・行編集を理解する |

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

```
sh (bin/sh/main.c)
    |
    +-- main()
          +-- setlocale()
          +-- init()                     # 各モジュール初期化
          +-- read_profile()             # プロファイル読み込み
          +-- cmdloop()                  # メインコマンドループ
                |
                +-- parsecmd()           # 構文解析 [parser.c]
                |     +-- readtoken()    # トークン化
                |     +-- list()         # 構文木構築
                |
                +-- evaltree()           # 構文木評価 [eval.c]
                      |
                      +-- evalcommand()  # コマンド実行
                      |     +-- find_command()  # PATH検索 [exec.c]
                      |     +-- forkshell()     # fork + exec
                      |     +-- evalbuiltin()   # 組み込みコマンド
                      |
                      +-- evalpipe()     # パイプ処理
                      +-- evalfor()      # forループ
                      +-- evalcase()     # case文
                      +-- evalsubshell() # サブシェル
```

### データフロー図

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

標準入力 / スクリプト    parsecmd()                    コマンド出力
(コマンド行) -------->  トークン化 --> 構文木構築  --> (標準出力/ファイル)
                         |
                    evaltree()
                    構文木評価
                         |
                    evalcommand()
                    コマンド実行
                    |         |
              組み込み    fork + exec
              (cd等)      (外部コマンド)
                              |
                         waitpid()
                         (終了コード取得)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main.c | `bin/sh/main.c` | ソース | メイン関数、cmdloop |
| parser.c | `bin/sh/parser.c` | ソース | 構文解析（パーサ） |
| eval.c | `bin/sh/eval.c` | ソース | 構文木評価・コマンド実行 |
| exec.c | `bin/sh/exec.c` | ソース | 外部コマンド検索・実行 |
| expand.c | `bin/sh/expand.c` | ソース | パラメータ展開・グロビング |
| jobs.c | `bin/sh/jobs.c` | ソース | ジョブ制御 |
| var.c | `bin/sh/var.c` | ソース | 変数管理 |
| redir.c | `bin/sh/redir.c` | ソース | リダイレクション |
| trap.c | `bin/sh/trap.c` | ソース | シグナルトラップ |
| input.c | `bin/sh/input.c` | ソース | 入力処理 |
| error.c | `bin/sh/error.c` | ソース | エラー処理（setjmp/longjmp） |
| histedit.c | `bin/sh/histedit.c` | ソース | ヒストリ・行編集 |
| alias.c | `bin/sh/alias.c` | ソース | エイリアス管理 |
| cd.c | `bin/sh/cd.c` | ソース | cd組み込みコマンド |
| builtins.def | `bin/sh/builtins.def` | 定義 | 組み込みコマンド一覧 |
| dot.profile | `bin/sh/dot.profile` | 設定 | デフォルト.profile |
| dot.shrc | `bin/sh/dot.shrc` | 設定 | デフォルト.shrc |
