inside tmux
Table of Contents
ハルシネーションの証拠
前回、ChatGPTにtmuxのログを容易に調べる方法を尋ねたら、盛大な嘘をつかれた。-vvvv と重ねなさいってね。tmux(1)には、
-v Request verbose logging. Log messages will be saved into tmux-client-PID.log and tmux-server-PID.log files in the current directory, where PID is the PID of the server or client process. If -v is specified twice, an additional tmux-out-PID.log file is generated with a copy of everything tmux writes to the terminal. The SIGUSR2 signal may be sent to the tmux server process to toggle logging between on (as if -v was given) and off.
これだけで嘘の証明が出来ちゃった訳だけど、原典に当ってみる。-vでレベルが1になる。
もう1回-vするとレベルが2になる。レベル1の時は、それぞれのログファイルを開いて
log_debug
で出力。2の場合は、
server.c
if (log_get_level() > 1) tty_create_log();
tty.c
tty_create_log(void) { char name[64]; xsnprintf(name, sizeof name, "tmux-out-%ld.log", (long)getpid()); tty_log_fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0644); static void tty_add(struct tty *tty, const char *buf, size_t len) { log_debug("%s: %.*s", c->name, (int)len, buf); c->written += len; if (tty_log_fd != -1) write(tty_log_fd, buf, len);
log_debug
に出力するデータの内、ttyに間するやつだけをレベル2では抽出してる
んだな。
log == trace ?
schemeだと、その規格書(RnRS)にtrace手続を実装しなさいって指示されている。 debugの手段として、重要視されてるんだね。tmuxはschemeの一種じゃないから、 traceは勿論実装されていない。
tmuxはshellから気軽に呼び出すコマンドの様に振る舞っているけど、実態は5万行を 越えるC言語で記述されたサーバーだ。して、その作りもschemeに似てる所がある。 cmd-xxxで提供される、ユーザー寄りの機能集と、それらを実現する為のいわゆる プリミティブの部分だ。
そんな横道めいた話は置いておいて、-vでログが取得できる事に注目。これって、 どのあたりを実行したかのトレースとも見做せる。on/off自由だしね。
1746743131 add peer 0x2c0ce01d000: 7 (0x0) 1746743131 sending message 111 to peer 0x2c0ce01d000 (8 bytes)
これ、ログの極一部だ。peerって何なの、とかメッセージ111って何者? そんな時は、検索さ。
ad$ fgrep 'add peer' *.c proc.c: log_debug("add peer %p: %d (%p)", peer, fd, arg); ad$ fgrep 'sending message' *.c proc.c: log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
これでもう、どの関数を実行してたか判明。内容をログから理解できれば、おんの字。 それが駄目でもgdbでブレークさせる場所が入手できる。そして、構造体とかの内容物 から推測するのさ。tmuxの作者さんは、くどくどコメントを記述しないようで、変数名 から想像すると言う楽しみを提供してくれています。
tmux.h
大量に *.c が有るのにヘッダーファイルは4個しかない。そのうちの見るべき奴は、 tmux.hだ。つらつら見てくと、cmd-xxxを実装する為に供給されてるんだなとヒシヒシと 感じる。コメントも、それなりに記述されてるしね。
それからマニュアルもparseの関係が充実して説明されてる。だから腕に覚えがある人は tpm用のモジュールを作りたくなる。これってtmuxの生存戦略だな。
watch
traceと言えばgdbでのそれもりっぱなトレースだ。前回だったか、forkptyで新らしい 仮想端末が作成される事実をキャッチしていたので、サーバーでfdforkptyにトレースを 仕込んでみた。そしてC-t Spc で、端末画面を追加。
(gdb) bt #0 fdforkpty (ptmfd=3, amaster=0x402df15c, name=0x402df048 "", termp=0x0, winp=0xcf7eae6c) at /usr/src/lib/libutil/pty.c:123 #1 0x17dc2747 in spawn_pane (sc=0xcf7eafc0, cause=0xcf7eafbc) at spawn.c:371 #2 0x17dc194c in spawn_window (sc=0xcf7eafc0, cause=0xcf7eafbc) at spawn.c:174 #3 0x17d2a3f6 in cmd_new_window_exec (self=0x4a71e000, item=0x4a6df400) at cmd-new-window.c:130 #4 0x17d3264d in cmdq_fire_command (item=0x4a6df400) at cmd-queue.c:650 #5 0x17d3223e in cmdq_next (c=0x402b7800) at cmd-queue.c:775 #6 0x17dbbd88 in server_loop () at server.c:268 #7 0x17d9997d in proc_loop (tp=0x57d4c500, loopcb=0x17dbbd00 <server_loop>) at proc.c:210 #8 0x17dbb79b in server_start (client=0x57d51a00, flags=402718720, base=0x57d51c80, lockfd=5, lockfile=0x4a6e1480 "tmux") at server.c:247 #9 0x17d1814d in client_connect (base=0x57d51c80, path=0x4a6e3e00 "/tmp/tmux-1000/default", flags=402718720) at client.c:165 #10 0x17d170b5 in client_main (base=0x57d51c80, argc=0, argv=0xcf7eb418, flags=402718720, feat=0) at client.c:290 #11 0x17dcd94b in main (argc=0, argv=0xcf7eb418) at tmux.c:549
これを見ると、windowの下部組織であるpaneから作成してるって事が、つまびやかに なった。もう隠す所さえ無いね。fdforkptyなんてのも隠れていられないぞ。
fdforkpty(int ptmfd, int *amaster, char *name, const struct termios *termp, const struct winsize *winp) { if (fdopenpty(ptmfd, &master, &slave, name, termp, winp) == -1) return (-1); switch (pid = fork()) { case -1: (void) close(master); (void) close(slave); return (-1); case 0: // child (void) close(master); login_tty(slave); return (0); } // parent *amaster = master; (void) close(slave); return (pid); }
省略しちゃったけど、openptyだって見放題だぞ。
The login_tty() function prepares for a login on the tty fd (which may be a real tty device, or the slave of a pseudo-tty as returned by openpty()) by creating a new session, making fd the controlling terminal for the current process, setting fd to be the standard input, output, and error streams of the current process, and closing fd.
これが、新たに開かれたwindowsの端末デバイスになるのか。
tmuxの外観
insideもいいけど、もっと大局的に外観を調べてみる。それにはfstatだな。リナの場合 だとlsofが相当品かな。でもあちらは結構余計な情報が出てくるんだよな。
vm$ fstat -p 95866 ;; tmux client USER CMD PID FD MOUNT INUM MODE R/W SZ|DV : sakae tmux 95866 0 / 700335 crw--w---- rw ttyp0 sakae tmux 95866 1 / 700335 crw--w---- rw ttyp0 sakae tmux 95866 2 / 700335 crw--w---- rw ttyp0 sakae tmux 95866 4 kqueue 0x0 0 state: W sakae tmux 95866 6* unix stream 0x0 vm$ fstat -p 20921 ;; tmux server USER CMD PID FD MOUNT INUM MODE R/W SZ|DV : sakae tmux 20921 0 / 701012 crw-rw-rw- rwp null sakae tmux 20921 1 / 701012 crw-rw-rw- rwp null sakae tmux 20921 2 / 701012 crw-rw-rw- rwp null sakae tmux 20921 3 / 700611 crw-rw-rw- rwe ptm sakae tmux 20921 4 kqueue 0x0 0 state: W sakae tmux 20921 5 / 700335 crw--w---- rw ttyp0 sakae tmux 20921 6* unix stream 0x0 /tmp/tmux-1000/default sakae tmux 20921 7* unix stream 0x0 sakae tmux 20921 8 / 700338 crw-rw-rw- rwp ptyp1 sakae tmux 20921 9 / 700340 crw-rw-rw- rwp ptyp2
kqueueってカーネルが提供するイベント・システムかな? 昔調べた記憶があるぞ(150923)。 unix streamって同一マシン内で通用するプロセス間通信か。異なるマシンと通信 したかったらインターネットだな。
サーバーはサーバーらしく、標準入出力が無効になってる。セッションを切断した後 で、サーバーに再接続出来るようにunix streamは名前で呼び出しできる様になってるとな。 色々な技術の複合体になってる。複雑怪奇な作りだ。
そんじゃ、 FreeBSD方面も観察。デフィでは提供されていないのでportsからの導入品です。
sakae@fb:~ $ fstat -p 4863 ;; client USER CMD PID FD MOUNT INUM MODE SZ|DV R/W : sakae tmux 4863 ctty /dev 100 crw--w---- pts/1 rw sakae tmux 4863 0 /dev 100 crw--w---- pts/1 rw sakae tmux 4863 1 /dev 100 crw--w---- pts/1 rw sakae tmux 4863 2 /dev 100 crw--w---- pts/1 rw sakae tmux 4863 3* pipe 18447680 <-> 18447744 0 rw sakae tmux 4863 4* pipe 18447744 <-> 18447680 0 rw sakae tmux 4863 6* local stream 185f5840 <-> 185f5540 sakae@fb:~ $ fstat -p 4865 ;; server USER CMD PID FD MOUNT INUM MODE SZ|DV R/W : sakae tmux 4865 0 /dev 39 crw-rw-rw- null rw sakae tmux 4865 1 /dev 39 crw-rw-rw- null rw sakae tmux 4865 2 /dev 39 crw-rw-rw- null rw sakae tmux 4865 3* pipe 18448000 <-> 184480c4 0 rw sakae tmux 4865 4* pipe 184480c4 <-> 18448000 0 rw sakae tmux 4865 5 /dev 100 crw--w---- pts/1 rw sakae tmux 4865 6* local stream 185f5600 sakae tmux 4865 7* local stream 185f5540 <-> 185f5840 sakae tmux 4865 8* pseudo-terminal master pts/2 rw sakae tmux 4865 9* pseudo-terminal master pts/3 rw
それぞれにパイプが施設されてるけど、流れる情報はどんな物? 再接続する時の目印が想像出来無いぞ。
ならば、リナ方面はどうよ? Lubuntu tmux client から。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME : tmux:\x20 2475 sakae 0u CHR 136,0 0t0 3 /dev/pts/0 tmux:\x20 2475 sakae 1u CHR 136,0 0t0 3 /dev/pts/0 tmux:\x20 2475 sakae 2u CHR 136,0 0t0 3 /dev/pts/0 tmux:\x20 2475 sakae 3r FIFO 0,14 0t0 17647 pipe tmux:\x20 2475 sakae 4w FIFO 0,14 0t0 17647 pipe tmux:\x20 2475 sakae 6u unix 0x0000000000000000 0t0 17650 type=STREAM (CONNECTED) tmux:\x20 2475 sakae 9u unix 0x0000000000000000 0t0 15527 type=STREAM (CONNECTED) tmux:\x20 2475 sakae 10u unix 0x0000000000000000 0t0 15528 type=STREAM (CONNECTED)
Lubuntu tmux server
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME : tmux:\x20 2477 sakae 0u CHR 1,3 0t0 5 /dev/null tmux:\x20 2477 sakae 1u CHR 1,3 0t0 5 /dev/null tmux:\x20 2477 sakae 2u CHR 1,3 0t0 5 /dev/null tmux:\x20 2477 sakae 3r FIFO 0,14 0t0 15208 pipe tmux:\x20 2477 sakae 4w FIFO 0,14 0t0 15208 pipe tmux:\x20 2477 sakae 5u CHR 136,0 0t0 3 /dev/pts/0 tmux:\x20 2477 sakae 6u unix 0x0000000000000000 0t0 15209 /tmp/tmux-1000/default type=STREAM (LISTEN) tmux:\x20 2477 sakae 7u unix 0x0000000000000000 0t0 17651 type=STREAM (CONNECTED) tmux:\x20 2477 sakae 8u CHR 5,2 0t0 89 /dev/ptmx tmux:\x20 2477 sakae 9u unix 0x0000000000000000 0t0 15527 type=STREAM (CONNECTED) tmux:\x20 2477 sakae 10u unix 0x0000000000000000 0t0 15528 type=STREAM (CONNECTED) tmux:\x20 2477 sakae 11u CHR 5,2 0t0 89 /dev/ptmx
FD 6には、ちゃんと名前が付いているなあ。と言う事は、FreeBSDのfstatがちょっと不 親切なだけかな。きっとそうだろう。OpenBSDのtmuxは独自進化してるけど、FreeBSDと リナのそれは、ちょっとバージョン違いが有るぐらいで、同一なソースだからね。
こんな風に、色々な環境(OS)で比べてみると、疑問が解消する事が有るね。一つのOSに 固執するってもったいないぞ。
(gdb) bt #0 client_connect (base=0xddb96a3d800, path=0xddbfc112f80 "/tmp/tmux-1000/default", flags=402653184) at client.c:110 #1 0x00000dd90b1fa22a in client_main (base=0xddb96a3d800, argc=0, argv=0x7f3b96f691d0, flags=402653184, feat=0) at client.c:290 #2 0x00000dd90b2a8ad9 in main (argc=0, argv=0x7f3b96f691d0) at tmux.c:549
pathは、 tmux.c/make_lable()
で作成されたものがデフォで利用される。
tmux-clientの挙動
tmux-serverのinsideを解析しようと項を立てたけど、とっても複雑で沼化まちがい なしなんで、より簡単そうなクライアントに焦点を移してみる。で、ソースを見ても 答が得られそうにない事を問うてみる。
Q: tmuxについて質問します。 起動すると tmux-serverとtmux-clientの2つのプロセスが生成されます。 そのうちのtmux-clientの方はserverを起動した後、ひたすらtmuxの終了 (exitとかdetache)だけを待っているだけの様に見うけられます。 あえてtmux-clientを残す理由は何ですか?
A: 良い観察です。tmux を起動すると、実際に tmux-server(セッションの管理を行うプロセス)と tmux-client(ユーザーとの対話を担当するプロセス)の2つが生成されます。
ご指摘の通り、最初に tmux を起動したとき、tmux-client は tmux-server を起動し、以後は「ユーザーがセッションから離脱(detach)する」あるいは「セッションが終了(exit)」するのを待ち受けるだけのように見えます。
まとめ tmux-client を残すのは:
- 端末との入出力処理のため
- ユーザー操作を受け付けるため
- 複数クライアントの同時接続に対応するため
- サーバーとの通信継続のため
という実用的な理由に基づいています。もし tmux-client が終了してしまうと、セッションとのインタラクションが失われてしまうため、意図的に残っているわけです。
この回答に一部納得できないので、自分で調べてみる。
OpenBSD 7.7 + GNU Emacs 30.1 な環境で
GNU gdb (GDB) 15.2 : (gdb) b client_main Breakpoint 1 at 0x5b05f: file client.c, line 243. (gdb) r ls The target does not support running in non-stop mode.
gdbがrunしなくなった。
vm$ gdb -q myx/tmux Reading symbols from myx/tmux... (gdb) b client_main Breakpoint 1 at 0x5b05f: file client.c, line 243. (gdb) r ls Starting program: /tmp/myx/tmux ls Breakpoint 1, client_main (base=0x3de184fac00, argc=1, argv=0x7131449ab5c0, flags=134217728, feat=0) at client.c:243 243 size_t size, linesize = 0; (gdb) bt #0 client_main (base=0x3de184fac00, argc=1, argv=0x7131449ab5c0, flags=134217728, feat=0) at client.c:243 #1 0x000003db43c9bad9 in main (argc=1, argv=0x7131449ab5c0) at tmux.c:549
emacs抜きだと走るんだよなあ。layout srcで、emacsの真似をするしかないか。 まあ、そういう環境問題は無視して、tmux-client-xxx.logを眺める。
1746743131 client loop enter 1746743131 client_signal: Child exited 1746743131 peer 0x2c0ce01d000 message 207 1746743131 sending message 208 to peer 0x2c0ce01d000 (0 bytes) 1746743919 peer 0x2c0ce01d000 message 203 1746743919 sending message 205 to peer 0x2c0ce01d000 (0 bytes) 1746743919 peer 0x2c0ce01d000 message 204 1746743919 client loop exit
exitした時。
1747545091 cmd_pack_argv: argv[0]=ls 1747545091 sending message 200 to peer 0x9702288a000 (7 bytes) 1747545091 client loop enter 1747545091 peer 0x9702288a000 message 303 1747545091 open write file 1 - 1747545091 sending message 305 to peer 0x9702288a000 (8 bytes) 1747545091 write check file 1 1747545091 peer 0x9702288a000 message 304 1747545091 write 59 to file 1 1747545091 peer 0x9702288a000 message 203 1747545091 file 1 59 bytes left 1747545091 write check file 1 1747545091 client loop exit
lsした時。結果をサーバーから受領したので、その結果を出力してる。 これがChatGPTが解説してた入出力の処理なんだな。了解しましただ。
1747546054 cmd_pack_argv: argv[0]=clock 1747546054 sending message 200 to peer 0x1a00bed1000 (10 bytes) 1747546054 client loop enter 1747546054 peer 0x1a00bed1000 message 203 1747546054 client loop exit
clockした時。時計は、別な仮想端末に表示を任せてしまっているので、直ぐに終了 した。
いずれも、1回こっきりのイベントを受け取ってから終了するようになってる。
proc_loop(struct tmuxproc *tp, int (*loopcb)(void)) { log_debug("%s loop enter", tp->name); do event_loop(EVLOOP_ONCE); while (!tp->exit && (loopcb == NULL || !loopcb ())); log_debug("%s loop exit", tp->name); }
イベントはkillでもいいみたい。
ad$ ps : 80841 00 I+p 0:00.06 tmux: client (/tmp/tmux-1000/default) (tmux) ad$ kill 80841
セッションが終了して目印の緑バーは消失した。
ad$ myx/tmux [terminated]
でも、復活の呪文を唱えると、回復する。
ad$ tmux ls 0: 2 windows (created Sun May 18 13:28:13 2025) ad$ myx/tmux a
サーバーのプロセスを殺してしまうと、もう復活できない。
[server exited] ad$ tmux ls no server running on /tmp/tmux-1000/default
もう、このぐらいにしておくか。
fstat
何気に、kshの外観も調べてみた所、変なのが居るぞ。
Q: OpenBSDについて、質問します。
te$ fstat -p `echo $$` USER CMD PID FD MOUNT INUM MODE R/W SZ|DV sakae ksh 2984 text / 3007019 -r-xr-xr-x r 706784 sakae ksh 2984 wd /tmp 2 drwxrwxrwt r 512 sakae ksh 2984 0 / 311530 crw--w---- rw ttyp0 sakae ksh 2984 1 / 311530 crw--w---- rw ttyp0 sakae ksh 2984 2 / 311530 crw--w---- rw ttyp0 sakae ksh 2984 10 / 312204 crw-rw-rw- rwep tty
FD 0,1,2は有名なので理解できます。FD 10 .. tty は、何を意味するのでしょう?
A: OpenBSDの `fstat` コマンド出力にある FD 10(`crw-rw-rw-` 権限の `/dev/tty` 相当のエントリ)は、**制御端末 (controlling terminal)** を明示的に開いたファイルディスクリプタです。
—
### 解説:
- FD 0, 1, 2 はそれぞれ、標準入力 (`stdin`), 標準出力 (`stdout`), 標準エラー (`stderr`) に対応しています。
- それらがすでに `/dev/ttyp0` に割り当てられていることから、現在のセッションの制御端末は `/dev/ttyp0` です。
では、**FD 10 に別の tty(同じ `/dev/ttyp0` の可能性あり)がなぜ現れるのか?**
### 可能性として高いのは:
- `ksh` が明示的に `/dev/tty` を開いた(例:スクリプトや内部処理で)。
- あるいは、ユーザーが `exec 10<> /dev/tty` のように `fd 10` を端末にバインドした。
- このファイルディスクリプタは `rwep`(読み・書き・実行・ポリシー対象)属性が付いており、**端末に対するI/O用に開かれている**ことを示しています。
### 典型的な用途の例:
exec 10<> /dev/tty echo "Hello" >&10 read answer <&10
このように、**標準入出力とは別に端末とのI/Oをしたいとき**に fd 10 を使うことがあります。たとえば、スクリプトが標準入力を別のファイルにリダイレクトしていても、ユーザーからの入力を tty から直接受けたいときなどに便利です。
—
### まとめ:
- FD 10 のエントリは、`/dev/tty`(制御端末)を別途開いた結果。
- スクリプトやシェルの内部処理、もしくはユーザー操作で明示的に開かれた可能性が高いです。
- このファイルディスクリプタを使うと、標準入出力に関係なく端末と直接やりとりできます。
—
このファイルディスクリプタが何によって開かれたのか特定したい場合は、`ktrace` や `gdb` などで `open("/dev/tty", …)` 系のシステムコールをトレースするのが有効です。
何か具体的なスクリプトや状況の中でこの fd が出ている場合、それも教えてもらえればさらに詳しく追えます。
直接ソースを見た方が速そうなんでガサ入れ。tty.cでホシを発見。尋問はChatGPTに 丸投げする。
非常に鋭い観察です。この `ttyinit()` 関数のコメントとコード片から読み取れることは、OpenBSD(あるいはそのシェル実装など)において、**制御端末 `/dev/tty` を特別なファイルディスクリプタ(FD 10)に保持している理由**を裏付けるものです。
—
### コードとコメントの要点
/* Initialize ttyfd. Used for saving/resetting tty modes upon
- foreground job completion and for setting up tty process group.
*/
このコメントは、tty\fd が以下の目的で使われることを示唆しています:
- 端末状態(tty modes)の保存・復元 → 例えば、`tcgetattr()` / `tcsetattr()` によって、エコーや行バッファリングなどの設定を一時的に変更し、後で戻す処理。
- プロセスグループの設定(setpgrp / tcsetpgrp) → シェルがジョブ制御を行う際、**フォアグラウンド/バックグラウンドの切り替え時に、どのプロセスが端末を制御するか**を適切に操作する必要があります。
—
### `FDUPFDCLOEXEC` + `FDBASE`(10)
fcntl(tfd, FDUPFDCLOEXEC, FDBASE)
この処理の意味:
- `tfd` を **FD 10以上で複製**(=衝突しにくいファイルディスクリプタ番号を使う)
- `CLOEXEC` をセット → 子プロセスではこのFDが自動的に閉じられる
つまり、**「シェル内部でのみ使いたい特殊なFD」として FD 10 を割り当てている**ということです。
—
### では、なぜ FD 10 を使うのか?
- FD 0, 1, 2 は stdin, stdout, stderr で固定用途
- FD 3〜9 は一般的なスクリプトや他のファイルに使われる可能性がある
- FD 10以上は衝突リスクが低く、内部処理用に都合がよい
- 実際に `ttyfd` に `/dev/tty` を明示的に割り当てて保持することで、**標準入出力がリダイレクトされていても制御端末へのアクセスが保証される**
—
### コメントと機能の関連性まとめ
コメント内容 | 実装との関連性 |
------------------------------ | ----------------------------------------------------------- |
`saving/resetting tty modes` | FD 10 を通して `tcgetattr`/`tcsetattr` を行うために `/dev/tty` を開いている |
`setting up tty process group` | `tcsetpgrp(ttyfd, pgid)` によって制御端末を変更する必要があるため、専用FDを確保している |
—
### 捕捉できること(まとめ)
- tty\fd = FD 10 は、ジョブ制御や端末設定のために特別に `/dev/tty` を開いて確保されたFDである。
- このFDは、標準入出力の状態に関係なく、常に制御端末へのアクセスを保証する役割を持つ。
- コメントは直接的ではないものの、**ジョブ制御(プロセスグループ設定)や tty モードの保存/復元**といった目的でこのFDを開いているという意図が明確に読み取れる。
—
このような `ttyfd` の使い道は、特に POSIX準拠シェルや端末ベースのアプリケーション(例: `tmux`, `screen`, `bash`, `zsh`) で共通して見られます。
必要であれば、この `ttyfd` が実際に使われる箇所(例えば `tcsetpgrp`, `tcsetattr` 呼び出し)も追って調査することが可能です。興味ありますか?
lessも端末アプリなんで、事情は同じだろうって事で確認。
ob$ fstat -p 31610 USER CMD PID FD MOUNT INUM MODE R/W SZ|DV sakae less 31610 text /usr 2099821 -r-xr-xr-x r 136148 sakae less 31610 wd /tmp 2 drwxrwxrwt r 512 sakae less 31610 0 / 562 crw--w---- rw ttyp1 sakae less 31610 1 / 562 crw--w---- rw ttyp1 sakae less 31610 2 / 562 crw--w---- rw ttyp1 sakae less 31610 3 / 1234 crw-rw-rw- rp tty sakae less 31610 4 /tmp 4 -rw-r--r-- rp 22
やっぱりtty君が居たな。次回の素材はlessにしよう。
ob$ fstat -p 4749 USER CMD PID FD MOUNT INUM MODE R/W SZ|DV sakae nc 4749 text /usr 2099623 -r-xr-xr-x r 39224 sakae nc 4749 wd /tmp 2 drwxrwxrwt r 512 sakae nc 4749 0 / 562 crw--w---- rw ttyp1 sakae nc 4749 1 / 562 crw--w---- rw ttyp1 sakae nc 4749 2 / 562 crw--w---- rw ttyp1 sakae nc 4749 3* internet stream tcp 0x0 *:12345
おまけで、ネットワーク・アプリも確認してみた。こちらにはtty君は不在だった。
Byobu
README
料理は知識が9割 なんて本を眺めている。女房が昔良く買っていたオレンジページ と言う雑誌の関連本だ。と言う事は、普段から料理をやっている主婦向けの本だな。
レシピを真似して料理を作りましょ、じゃ、言われた通りにやるマニュアル人間 じゃん。そこに何故は無い。考える事を放棄しちゃってる。何故は知識が有って こその賜物だ。と、偉そうに言ってるけど、オイラーは料理なんてさっぱりやって ません。
せいぜいカップラーメンにお湯を注いて3分待つだけです。何故3分なの? お湯は何度がいいの? 水を注いじゃ駄目なの? 今度聞いてみよう。