
eBPFトレースポイントを使用して、Linuxホスト上で発生するすべてのシグナルをリアルタイムでストリーミングし、送信元、ターゲット、処理方法、ハンドラレイテンシ、およびシステムコール割り込みを表示するライブカーネルシグナル観測ツール。
sigwire
tail -fシグナル用。 マシン上の任意のプロセスが発生させるすべてのシグナル — 誰が送ったか、誰が受けたか、どのシグナルか、どのように発生したか(kill(2)、カーネル、POSIX タイマー)、ターゲットがそれを捕捉したかどうかとハンドラの実行時間、ブロックされたシステムコールをEINTRで引き裂いたかどうか — カーネルのシグナルトレースポイントからデコードし、ライブで端末にストリーミングします。1つのPIDにstrace -fする必要も、ptraceも、関係するプロセスからの協力も不要です。
sigwire はカーネルのシグナル機構をライブパッチベイに変えます: 各行は sender ──SIGNAL──▶ target で、深刻度で色分けされ、発生方法でタグ付けされ、ターゲットが 捕捉 したか(およびハンドラの実行時間)、ブロックされたシステムコールを中断したか(↯ EINTR read)、スパム時に ×N に折りたたまれ、真の殺傷打撃の場合は ☠ でマークされます。 サイドレールは回線上を飛び交うものを集計します; 一時停止して行を選択すると全体像を検査できます — 処置、ハンドラアドレス、sigaction フラグ、その瞬間にターゲットがブロックしていたシグナル。
カーネルの トレースポイント をフックするため、特定のプロセスではなく、1回の実行でホスト上のすべてのシグナルを一度に監視します — あなたのアプリ、スーパーバイザー、カーネル自身のフォールト機構 — それらがトレースされていることに気づかれることなく。
[!TIP] すべてのシグナルには2つの側面があります。 sigwireは
signal:signal_generate(送信者 の視点 — 誰が何を発生させたか、スイッチボード回線)とsignal:signal_deliver(ターゲット の視点 — 捕捉したか、どのハンドラとフラグで、何をブロックしていたか、システムコールを中断したか)の両方を監視します。さらに2つのフック —rt_sigreturn(2)とシステムコール終了トレースポイント — がハンドラの時間を計測し、EINTRを捕捉します。これらはすべて1つの行に相関付けられます。この分割が、☠ fatalカウントが意図的に保守的である理由でもあります(致命的とみなされる条件 を参照): 生成は配送の前に行われるため、送信側はシグナルの運命を知ることができません — 配送側だけが知ることができ、しかも観測したケースに限られます。
curl -fsSL https://yeet.cx | sh # install the yeet daemon (one time) yeet run github:yeet-src/sigwire # run the dashboard (the daemon does the privileged BPF load)
[Manual install guide](https://yeet.cx/docs/manual-installation) | Linux only
設定は不要です — シグナルはあらゆるマシンで常時バックグラウンドトラフィックとして発生するため、行はすぐに上部に表示され始めます。自分でシグナルを発生させたい場合は? `kill -USR1 <pid>`、フォアグラウンドジョブを `Ctrl-C`、またはマネージドランタイムを起動して、そのGC/スケジューラが自身のスレッドにpingを送るのを確認してください(`↯ EINTR futex` が流れていきます)。
## コントロール
デフォルトではフィードは最新のシグナルを追跡します。行を選択するか一時停止すると、その位置で固定され、その間もデータは下に流れ続けます。
| キー | アクション |
| --- | ------ |
| `p` · `Space` | フィードの一時停止/再開(読み込みのために固定する) |
| `↑`/`↓`, `k`/`j` | 一時停止して行を検査 — 詳細パネルを開く |
| `/` | ファジーフィルター — プロセス、pid、シグナル、ソース、処理結果に一致。一致した文字がライブでハイライト表示されます |
| `e` | **中断されたシステムコールのみ**にフィルター(`↯ EINTR` / `↺ restarted`) |
| `s` | **シグナルピッカー**を開く — 任意のシグナルをミュートまたは表示、ライブで |
| `Esc` | 1階層戻る — フィルターをクリア/ピッカーを閉じる/選択を解除、その後終了 |
| `q` | 終了 |
## 表示内容
各行は生成された1つのシグナルであり、新しいものほど上に表示されます。```
WHEN SENDER SIGNAL TARGET NOTE
now bash·4402──SIGINT───▶ node·8813 kill(2) ↯ EINTR read caught 41µs
1.2s systemd·1──────SIGTERM──▶ nginx·1291 kill(2) caught 1.2ms
3.4s kernel·8813──SIGSEGV──▶ chrome·8813 fault default ☠
4.1s postgres·507──SIGUSR1───▶ postgres·509 ×6 kill(2) caught 9µs
各行は1つのブロックです。送信者 → 対象 は comm・pid(送信者はシグナルを上げたプロセス、current は現在のプロセス、対象はそのシグナルの宛先)で、中央の ワイヤ は重要度に応じて色付けされたシグナル名を表示し、×N は同じシグナルが連続したものを1行にまとめます。右側の 注釈 は発生源、システムコールの割り込み、そして処理方法を示します。
各行は配信が解決した瞬間に固定され、その後は変わりません。つまり、バーストはちらつく集約ではなく、安定したログとしてスクロールしていきます。
ワイヤは重要度に応じて色付けされ、UIの他の部分と同じ256色パレットを使用します。
注釈 は発生源(kill(2)、tgkill、sigqueue、timer、kernel、fault)です。次に、ブロックされたシステムコールを割り込んだ場合、↯ EINTR read(または SA_RESTART で自動再開された場合は ↺ restarted read)が続きます。そして、処理方法(caught 41µs:ハンドラが実行され、その所要時間; default:ハンドラなしでデフォルトのアクションが適用; または ⊘ ignored)です。☠ は実際の致命的な一撃を示します(何が致命的かを参照)。
[!NOTE]
↯ EINTRに注目してください。 スレッドが低速システムコール(read、poll、accept、futex、nanosleepなど)で停止しているときにシグナルが届くと、スレッドは強制的に抜け出します。システムコールは-1/EINTRを返し、ハンドラがSA_RESTARTを設定していない限り、再開されません。アプリは再試行する必要があります。これを忘れると、タイミングに依存する古典的で頭を悩ませるバグが発生します(「なぜread()が 一度だけ 失敗したのか?」)。sigwire はそれがライブで発生し、どのシステムコールが影響を受けたかを表示します。eを押すと、他のすべてを非表示にして割り込みだけを監視できます。
右側のレールは集約ビューです。トップシグナル(ボリューム順)、発生源別の内訳、そして 配信 集計(キャッチされたシグナル数、デフォルトにヒットした数、無視された数)を表示します。
↑/↓(または p)を押してフィードをフリーズし、行を選択します。レールは詳細パネルに変わり、配信側がそのシグナルについて知っているすべての情報が表示されます。```
SIGNAL
SIGUSR1 (10) user
from ctarget·3980913
to ctarget·3980913
RAISED
via tgkill
code SI_TKILL
scope thread
result delivered
DELIVERY
handled caught
syscall EINTR ← read
handler 0x55f0a1c3
ran 3.0ms
flags SA_SIGINFO
TARGET BLOCKS
SIGINT SIGQUIT SIGTERM
- **handled** — `caught`(ユーザー空間ハンドラを実行)、`default`(→ デフォルトアクション:終了/コアダンプ/停止/無視)、または`ignored`。
- **syscall** — このシグナルがブロックされたシステムコールを中断した場合:`EINTR ← read`(ユーザー空間が`EINTR`を確認)または`restarted read`(`SA_RESTART`が透過的に再開)。
- **ran** — ハンドラの実行時間。配送からそれを終了する`rt_sigreturn(2)`まで計測。(Cハンドラでフラグを設定するだけで実際の処理を後で行うランタイム — CPython, Go — はここで微小な時間を示します。それはそれらのランタイムであり、sigwire の問題ではありません。)
- **flags** — ハンドラの`sigaction`フラグ(`SA_RESTART`、`SA_SIGINFO`、`SA_NODEFER`、…)。
- **TARGET BLOCKS** — 配送時のターゲットがブロックしていたシグナル(その`sigprocmask`)、`task_struct`から直接取得。
`Esc`でインスペクタを閉じます。`p`でライブフィードを再開します。
## 致命的と見なされるもの
`☠ fatal`カウンタと`☠`行バッジは意図的に厳格です。`signal_generate`は*生成時*に発火するため、sigwire はターゲットがハンドラを設定したかどうかを見ることができません — `SIGTERM`はキャッチされてクリーンシャットダウンに変換されるかもしれませんし、まったく無視されるかもしれません。そのため、明確な場合にのみ死亡をカウントします:
- **`SIGKILL`** 配送 — キャッチ不可、無視不可、常に致命的;**または**
- **カーネル自身が発生させた**(ユーザー空間の`kill`ではなく同期的フォールト)**コアダンプシグナル**(`SEGV`/`BUS`/`ABRT`/`ILL`/`FPE`/`TRAP`/`SYS`/`QUIT`)
その他すべて — `systemd`からの`SIGTERM`、Ctrl-Cからの`SIGINT`、ランタイムが自身のスレッドに送る`SIGPWR` — は表示され色付けされますが、死亡としてはカウントされません。おそらく死亡ではないからです。
## シグナルピッカー(ライブカーネルノブ)
どのビジーボックスでも3つのシグナルは純粋なバックグラウンドノイズです: `SIGCHLD`(すべての子プロセスの回収)、`SIGURG`(Goの非同期プリエンプションのハートビート)、`SIGWINCH`(ターミナルサイズ変更、フォアグラウンドプロセスすべてにブロードキャスト)。sigwireはデフォルトでこれら3つを**カーネル内で**ミュートし、フィードが興味深いトラフィックになるようにします — ただし、どのシグナルがノイズかはあなたの判断です。
`s`を押して**シグナルピッカー**を開きます: 各シグナルのライブ重大度色と表示回数をリストしたモーダルで、それぞれ`shown`と`muted`を切り替えられます。矢印で移動するか(または**数字を入力** — `1`、`5` → 15にジャンプ)、`space`を押すと、そのシグナルが即座に切り替わります。`a`は**すべて**を一度に切り替えます。タイトルバーの`muted`カウントは隠されている数を追跡します。
これがデモの双方向部分です: ミュートマスクは実行中のBPFプログラムの`.data`セクションにある`__u64`グローバルで、行を切り替えるとプログラムが実行し続けている間に`DataSec.patch()`を通じて対応するビットが修正されます。カーネルはミュートされたシグナルをリングバッファに到達する前にドロップするため、ミュートは何もコストがかからず — アンミュートするとリロードなしでシグナルがストリームに戻ります。
## 仕組み
コアは [`src/bpf/sigwire.bpf.c`](https://github.com/yeet-src/sigwire/blob/HEAD/src/bpf/sigwire.bpf.c) + [`src/bpf/deliver.bpf.c`](https://github.com/yeet-src/sigwire/blob/HEAD/src/bpf/deliver.bpf.c)(カーネル、1つのオブジェクトにリンク)と [`src/probes/sigwire.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/probes/sigwire.js)(ユーザー空間)です。すべては`(target tid, signal)`によって関連付けられます。
### BPF 側
2つのソースファイルが1つのロード可能オブジェクト`bin/probe.bpf.o`にリンクされ、4つのトレースポイントプログラムがあります:
| Program | Attached to | What it captures |
|---|---|---|
| `on_signal_generate` | `signal:signal_generate` | 送信者(`current`)+ ターゲット(`comm`/`pid`)、シグナル、`si_code`、`group`フラグ、`result` — ライブの`mute_mask`でシグナルのビットが設定されている場合はカーネル内でドロップ |
| `on_signal_deliver` | `signal:signal_deliver` | 送信先のdisposition(`sa_handler`)、`sa_flags`、および — `task_struct`から — その`blocked`シグセット;ハンドラタイミングのために配送をスタンプ |
| (rt_sigreturn) | `syscalls:sys_enter_rt_sigreturn` | スタンプされた配送との差分をとり、ハンドラの実行時間を計算 |
| (sys_exit) | `raw_syscalls:sys_exit` | まれな`-ERESTART*`リターンを記録し、次の`signal_deliver`がそれを`EINTR`/`restarted` + 中断されたシステムコール番号に解決できるようにする |
マップがカーネルとユーザー空間を接続します:
- `events` — `RINGBUF`、生成ごとに1つの`signal_event`。
- `dispatch` — `RINGBUF`、配送/ハンドラ復帰ごとに1つの`dispatch_event`。
- `mute_mask` — `.data`セクションの`__u64`グローバル;ピッカーが個々のビットを修正してカーネル内でシグナルをドロップ。
- `handler_start` / `restart_pending` — `HASH`、tidでキー付けされ、配送とその`rt_sigreturn`をペアリングし、システムコールの`-ERESTART*`終了とそれに続く配送をペアリングするスレッドごとのスクラッチ。
### JS 側
| file | responsibility |
|---|---|
| [`src/probes/probe.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/probes/probe.js) | `bin/probe.bpf.o`を一度ロードし、マップをバインドし、プログラムを開始します(自動アタッチ) |
| [`src/probes/sigwire.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/probes/sigwire.js) | 唯一のBPF認識データモジュール: 両方のリングバッファを集計付きのローリングフィードにまとめ、配送を生成に関連付け、ミュートマスクノブを所有 — `feed`、`visible`、`muteMask`シグナルを公開 |
| [`src/main.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/main.jsx) | コンポジションルート: 入力、選択、レスポンシブレイアウト(狭い端末ではレールが非表示)、`mount`を公開 |
| [`src/components/feed.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/feed.jsx) | スイッチボード: `sender ──SIG──▶ target`、disposition/レイテンシ、バッジ、色合い、同一行結合 |
| [`src/components/tally.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/tally.jsx) | サイドレール — トップシグナル、ソース別内訳、配送集計 |
| [`src/components/detail.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/detail.jsx) | インスペクタ — シグナルごとのdisposition、ハンドラ、フラグ、ブロックマスク |
| [`src/components/picker.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/picker.jsx) | シグナルピッカーモーダル — カーネルミュートマスクを介して各シグナルをミュート/表示 |
| [`src/components/titlebar.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/titlebar.jsx) | ブランド、ライブレート、合計、`☠ fatal`カウンタ、ミュート数、ライブ/一時停止 |
| [`src/components/footer.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/footer.jsx) | キーヒントとライブフィルタプロンプト |
| [`src/lib/signals.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/lib/signals.js) | 唯一の真実の源: 名前、重大度、色、`si_code` → ソース、disposition、フラグ、マスクデコード、致命性 |
| [`src/lib/format.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/lib/format.js) | ピュアフォーマッタ — パディング、切り詰め、`ago()`、持続時間、コンパクトカウント |
| [`src/lib/fuzzy.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/lib/fuzzy.js) | プロセス + pid + シグナル + ソース + dispositionに対する部分列ファジーマッチ |
モデルは生成されたシグナルのローリング**フィード**で、同一の繰り返しを`×N`行に結合します。シグナルの生成行はその配送が解決した瞬間に固定されます — そのため、すでに画面にある行が変更されたりジャンプしたりすることはありません。120msのウィンドウタイマーがフレームごとに1つのスナップショットを発行するため、ビジーなリングバッファでも何千もの再レンダリングではなく1回の再レンダリングで済みます。
### トレースポイントを使う理由(`strace`/`ptrace` ではなく)
`strace -f`は1つのプロセスツリーを追跡し、すべてのイベントでトレース対象を停止します。`ptrace`はターゲットごとに設定が必要で侵入的です。シグナルトレースポイントは、*カーネル*がシグナルを発生させて配送する場所であり、*すべての*プロセスに対して、アプリごとの設定や誰も停止することなく機能します。生成 ↔ 配送 ↔ `rt_sigreturn`のペアリングにより、送信者/ターゲットペア、disposition、ハンドラごとのレイテンシ、シグナルの全ライフサイクルを結びつけるEINTR判定が得られます。
## カーネル間でのテスト
`make veristat`は**あなたの**カーネル上で`bin/probe.bpf.o`をveristatでロードします — すべてのプログラムが検証器を通過すること、およびプログラムごとの複雑さ(insns/states)を素早く確認します。BPFのロードには特権が必要なため、`sudo`を使用してください。
あなたのラップトップでロードできるプログラムでも、古いカーネルの検証器では拒否される可能性があります。[`.github/workflows/kernel-matrix.yml`](https://github.com/yeet-src/sigwire/blob/HEAD/.github/workflows/kernel-matrix.yml)がそれに対処します: マトリックス内の各カーネルについて、オブジェクトをビルドし、そのカーネルをVM([cilium's little-vm-helper](https://github.com/cilium/little-vm-helper)、イメージは`quay.io/lvh-images`)で起動し、ベンダー提供の静的**veristat**を実行します — 検証器がプログラムを拒否した場合、ジョブは失敗し、カーネルごとの結果が ✅/❌ のグリッドに整理されます。VM内のゲートは[`build/verify-kernel.sh`](https://github.com/yeet-src/sigwire/blob/HEAD/build/verify-kernel.sh)です。
ローカル(Linux + KVM)で同じマトリックスを実行するには`make veristat-matrix`を使用します — `lvh` + QEMUでカーネルイメージを起動し、`ok`/`FAIL`のグリッドを表示します。カーネルを選択するには`make veristat-matrix KERNELS="6.6 bpf-next"`を使用します。
## 必要条件
> [!IMPORTANT]
> - **BTF(`CONFIG_DEBUG_INFO_BTF`)を持つLinuxカーネル** — CO-RE用。`bpftool`がこれから`src/bpf/include/vmlinux.h`を生成します。現在のArch、Fedora、Ubuntu、Debian(~5.4以降のすべての主流ディストリカーネル)ではデフォルトで有効です。
> - **yeetデーモン** — 特権BPFロードを実行します。BPFのケイパビリティはデーモン化されたプロセスに委譲されるため、`sigwire`自体は非特権で実行されます。`curl -fsSL https://yeet.cx | sh`でインストールします。
> - ソースからビルドするには`clang`と`bpftool`も必要です — しかし、ベンダー提供の静的ツールチェーンがこれらを提供するため、システムのC/BPFツールチェーンは必要ありません。node/npmは不要: esbuildもベンダー提供されており、プロジェクトにサードパーティの依存関係はありません。
## 正直な注意点
> [!NOTE]
> `sigwire`は観測可能性ツールであり、強制力はありません。発生したシグナルを表示するだけです。シグナルをブロック、遅延、変更することはありません。
- **行は*発生した*シグナルです。** スイッチボードの行は生成から来ます。ターゲットはそれをキャッチしたり、ブロックしたり、すでに終了している可能性があります。disposition/ハンドラ/マスク列は*配送*側から来て、カーネルが実際に配送した場合にのみ入力されます — ブロックされた、またはまだ保留中のシグナルはdispositionを表示しません。[致命的と見なされるもの](#what-counts-as-fatal)を参照してください。
- **関連付けはベストエフォートです。** 生成と配送は共有IDのない別々のトレースポイントであり、時間ウィンドウ内で`(target tid, signal)`で照合します。同じスレッドへの同じシグナルの嵐の下では、ペアリングがぼやける可能性がありますが、圧倒的に一般的なケースでは正しいです。
- **ハンドラタイミングはカーネルのフレームを測定し、意図を測定しません。** `ran`は配送 → `rt_sigreturn`です。フラグを設定するだけのハンドラ(CPython、Goのランタイム)は、"実際の"処理が後でイベントループで行われても、マイクロ秒で戻ります — 正確ですが、期待するものではないかもしれません。
- **EINTR検出はすべてのシステムコール終了を監視します。** 中断されたシステムコールをキャッチするには`raw_syscalls:sys_exit`にアタッチする必要があり、これはシステム全体の*すべての*システムコールリターンで発火します(ハンドラはまれな`-ERESTART*`コード以外では即座にベイルするため、追加コストはシステムコールあたり数命令ですが、ゼロではありません)。システムコール*名*はx86-64のテーブルです。他のアーキテクチャでは生のシステムコール番号が表示されます。
- **カーネルシグナルの送信者は`current`です。** 同期フォールト(不正アクセスによる`SIGSEGV`)の場合、それはフォールトを起こしたタスク自身です — 正しくて有用です。非同期カーネルシグナルの場合、`current`はカーネルがシグナルを発生させたときに実行中だったタスクであり、ヒントに過ぎず、絶対的なものではありません。
- **リアルタイムシグナルの番号付けは名目上のものです。** `SIGRTMIN+n`は生のオフセットで表示されます。ライブラリは低い数個を自身の用途のために予約しています。
- **`comm`は16バイトです。** 長いプロセス名はカーネルによって切り詰められ、sigwireによるものではありません。
## コミュニティからの質問
**トレース対象のプロセスを遅くしますか?**
有意なオーバーヘッドはありません。トレースポイントプログラムは受動的です。コストはシグナルごとの境界のあるリングバッファ書き込み(およびEINTR検出のためのシステムコール終了ごとの数命令)であり、リングバッファはユーザー空間が遅れた場合にブロックするのではなくドロップします。
**起動時にすでに実行中だったプロセスに向けられたシグナルも表示されますか?**
はい。sigwireがアタッチした瞬間からのすべてのシグナルに対してトレースポイントが発火します。送信者やターゲットがいつ起動したかは関係ありません — 見逃すようなプロセスごとの状態はありません。
**任意のプロセス、または1つのプロセスだけに対して機能しますか?**
ホスト上のすべてのプロセスを一度に監視します — 送信者/ターゲットのガターがそれらを区別します。1つのpidではなく、マシン全体のシグナルトラフィックです。
**フィードをエクスポートできますか?**
組み込みではありません。`probes/sigwire.js`の`RingBuf.subscribe`コールバックはすべてのデコードされたレコードを保持しているため、JSON/HTTP/Kafkaシンクはそこにブランチを追加することで可能です。管理されたパイプラインを設定するには、[お問い合わせください](https://yeet.cx/)。
## ソースからのビルド```sh
make # clang + bpftool → bin/probe.bpf.o ; esbuild → src/index.jsx
make bpf # just the BPF object
make bundle # just the JS bundle
make clean # remove build artifacts
Then yeet run . を実行するとローカルビルドが行われます。make は2つの独立したコンパイラを実行します。clang + bpftool は src/bpf/*.bpf.c をリンクしてロード可能なオブジェクト bin/probe.bpf.o を生成し、esbuild は src/main.jsx をバンドルして src/index.jsx を生成します。その際、tsconfig の paths を用いて @/(ソースルート)と #/(プロジェクトルート)の バンドル時エイリアス を解決し、yeet:* の組み込み関数は外部のままにします。両方のコンパイラはベンダリングされた静的ツールチェーンから提供されるため、ビルドにシステムのC/BPFツールチェーンやnode/npmは必要ありません。生成される vmlinux.h、src/index.jsx、bin/*.bpf.o はビルド成果物です。
エイリアスはバンドル時のみ有効であるため、ランタイムはエイリアスではなく import.meta.dirname を使用してBPFオブジェクトを特定します。yeetダッシュボード作成ガイドについては AGENTS.md(別名 CLAUDE.md)を参照してください。
デュアルライセンス BSD/GPL。BPFプログラムは src/bpf/sigwire.bpf.c 内で char LICENSE[] SEC("license") = "Dual BSD/GPL" と宣言しています。これは、使用するヘルパー関数に対してカーネルが要求するものです。
yeet で構築されています。yeet は Linux 上で eBPF プログラムを記述するための JS ランタイムです。Discord に参加してください。
| 重要度 | シグナル | 色 |
|---|
| kill | SIGKILL | ホットレッド |
| fatal (コアダンプ) | SEGV BUS ABRT ILL FPE TRAP SYS QUIT | レッド |
| terminating | TERM INT HUP PIPE ALRM … | アンバー |
| ジョブ制御 | STOP TSTP TTIN TTOU | イエロー |
| continue | CONT | グリーン |
| user | USR1 USR2 | シアン |
| リアルタイム | SIGRTMIN+n | バイオレット |
| housekeeping | CHLD URG WINCH … | グレー |