tmux (2)

携帯通話料金は何故高い?

携帯を新しくした時、通話料金が40円/分(0.666円/秒)ですって説明された。今まで余り意識してこなかったけど、固定電話に比べて高すぎると思うぞ。何故高いのってチコちゃんに質問したって、そんなのを取り上げてくれるなんて絶対に無い(と思う)。自分で考えろ。

携帯業界ってかスマホ業界は、今仁義なき戦いが繰り広げられている。政府に尻を叩かれて、20Gで2500円の攻防戦。但し、端末はヨドバシあたりで仕入れてきて、ネットで契約してROMを手に入れて装着って条件。スマホ屋の運営費をカットしたから、この値段って事か。

1Gで125円相当。1Mだと、0.125円になる(1K当たりに直すと、0.125円/1000)。オイラーの携帯は、ネット接続無しと言う契約。若しネットに繋いでWebとか見ると、1Kあたり、0.6円かかりますって念を押された。携帯屋にしてみれば、ちゃんと説明したからね。後は自己責任ですって事。 こんな説明をすっかり忘れて、AV鑑賞する年寄りを鴨にする作戦だな。桁違いに高い脳。

ああ、話が逸れた。通話料金何故高いの考察。電話は、通過帯域が300Hzから3400Hz。このアナログ信号をデジタルに変換する。サンプリングレートの定理により、標本化周波数を8KHzにしてる。1サンプリング当たり10Bitで量子化してても、最終的に1Byteに圧縮される。人間の聴覚は、小さい音の変化には敏感だけど、大きな音の場合変化は容易に分からないと言う、対数的特性を持っているからね。一種の対数的な圧縮をしてるんだ。ミュー・ロー・コーディックなんて言ったりする。 よって、一秒間に8KByteの転送量になる。

電話の場合は、この通信を、遅延なく確実に伝送する為、専用線(相当の無線通信路)を確保してるんだ。だから、高額でいいしょって事にしてる。客層を分けてるんだな。

大体20Gも使う人は、動画をみたり音楽聞いたりだから、多少のエラーとか遅延は気にしない使い方。ぶっちゃけた言い方をすれば、乗り心地が悪くても、がんがん行ける方が良い。だから安く提供しますだな。

対して、電話は、安定指向。高いのは我慢してください。未だに、ショルダーフォン時代の高値時代を引きずっている。高いのは当たり前って消費者は刷り込まれているんだな。

銀行間の送金手数料が数十年ぶりに値下げへ。

公正取引委員会が噛みついて、実現の運びになったそうな。通話料金でぼろ儲けにも、噛みついてください。本当は管さんが噛みついて、スゲーになって欲しいんだけど、本格的にやると、また総務省の人材が減る(可能性がある)からなあ。躊躇してますって事だろう。それとも、支持率低下時の浮揚策として、隠しておくのかな? もしやれば、年寄りの支持間違い無し。

WebSerial

ググル正のブラウザーが89版になって、WebSerialがサポートされた。早速試した人がいる。

USBのシリアル接続先をWebにしちゃうと言う、正しいUSBの使い方をしてる。なんたってUSBってのは、ユニバーサル・シリアル・バスの略ですから。原点に帰ってRS232Cのコネクターの代替を務めようって訳。USBスティックだけ(or USB-HDD or スマホの充電)を繋ぐんじゃもったいない。

Raspberry Pi PicoをブラウザだけでLチカする入門

で使われていた

https://googlechromelabs.github.io/serial-terminal/

を見ておこう。これぞ、正統派のシリアル端末だぞ。直ぐにfirefoxも追従するに違いない。

vlock / lock

tmuxのmanをパラパラしてたんだ。そしたら、ロックだぜいってコマンドが取り上げられていた。具体的には、どうやって使うの? 迷わずggしたよ。 vlock コマンドで tmux をロックする を見ると、リナにはvlockなんてコマンドが有るようだ。じゃ、OpenBSDには?

vbox$ lock -a passwd
lock: /dev/ttyp2 on vbox.local.jp. no timeout
time now is Fri Mar  5 06:15:55 2021
Key:

これで、CUI版のロックになる。解除はlogin passwd。-t 5 なんてのを付けると、5分間だけ、ロックがかかって、それを過ぎるとロックが解ける。see: lock(1) 2BSDから有る、歴史的なコマンドだな。

このロック機構をtmuxに組み込むには、リナだと下記のようにする。 .tmux.conf for Linux

set -g lock-command vlock
set -g lock-after-time 0
bind l lock-session

OpenBSDなら、上記のbind行だけを登録する。何故なら

lock-command shell-command
        Command to run when locking each client.  The default is to run
        lock(1) with -np.

こんな説明がmanにあったから。デフォルトでBSD系のロック機構を採用してるんですね。最近はリナ系がデフォなアプリが蔓延してるけど、これは快挙ですよ。

from source

OpenBSDの綺麗に整理されたソースだけじゃぬるま湯なんで、世間一般に流通してるソースを取ってきて、ごにょごにょする。青年は荒野を目指すじゃなくて、爺の暇つぶしね。

-rw-r--r--  1 sakae sakae    2273 Apr 14  2020 osdep-aix.c
-rw-r--r--  1 sakae sakae    1921 Apr 14  2020 osdep-cygwin.c
-rw-r--r--  1 sakae sakae    2661 May  4  2020 osdep-darwin.c
-rw-r--r--  1 sakae sakae    3027 Apr 14  2020 osdep-dragonfly.c
-rw-r--r--  1 sakae sakae    4572 Apr 14  2020 osdep-freebsd.c
-rw-r--r--  1 sakae sakae    1103 Apr 14  2020 osdep-hpux.c
-rw-r--r--  1 sakae sakae    2284 Apr 14  2020 osdep-linux.c
-rw-r--r--  1 sakae sakae    3720 Apr 14  2020 osdep-netbsd.c
-rw-r--r--  1 sakae sakae    3729 Apr 14  2020 osdep-openbsd.c
-rw-r--r--  1 sakae sakae    2230 Apr 14  2020 osdep-sunos.c
-rw-r--r--  1 sakae sakae    1094 Apr 14  2020 osdep-unknown.c

こんなOSをサポートしてるとな。一番文字数の少ないhpuxが、作者様の愛用OSかな。と、デカの推測機構が言ってますよ。そんな事より、README.jaが同梱されてたのにはびっくり。熱狂的な日本人が書いてるかと思ったら、マリオットさんと言う方の筆によるものだった。

丁寧に、コンパイル時の必要品が書いてあるんで、buildには困らないだろう。

tmuxのドキュメントについてはtmux.1マニュアルをご覧ください。こちらのコマンドで
参照可能です。

        $ nroff -mdoc tmux.1|less

manを読まない人向けの説明まで出てた。

debian:tmux-3.1b$ ./tmux -V
tmux 3.1b

Changesによると、最初のリリースされたのは、2007/07 になってた。

Initial import to CVS. Basic functions are working, albeit with a couple of
showstopper memory bugs and many missing features. Detaching, reattaching,
creating new sessions, listing sessions work acceptably for using with shells.
Simple curses programs (top, systat, tetris) and more complicated ones (mutt,
emacs) that don't require scrolling regions (ESC[r) mostly work fine
(including mutt, emacs). No status bar yet and no key remapping or other
customisation.

最初は、アタッチ/デタッチの基本からだったのね。マルチプレクサで、windowを増やすのは、後の仕事だったのか。

折角debugバージョンを作ってみたけど、元々がGUIの環境でプロセスが動き過ぎ。tmuxの挙動を追うには、雑音が多すぎる。ってな事で、またOpenBSDに戻ります。

tmux client

前回調べたpstreeを再掲する。

-+= 00001 root /sbin/init
 |-+= 35291 root sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups (sshd)
 | \-+= 21705 root sshd: sakae [priv] (sshd)
 |   \-+- 74961 sakae sshd: sakae@ttyp0 (sshd)
 |     \-+= 73521 sakae -ksh (ksh)
 |       \--= 80340 sakae tmux: client (/tmp/tmux-1000/default) (tmux)
 |--= 82502 root /usr/sbin/cron
 |-+= 01678 sakae tmux: server (/tmp/tmux-1000/default) (tmux)
 | |-+= 50968 sakae -ksh (ksh)
 | | \-+= 97744 sakae pstree
 | |   \-+- 80180 sakae sh -c ps -kaxwwo user,pid,ppid,pgid,command
 | |     \--- 02255 sakae ps -kaxwwo user
 | \-+= 37289 sakae -ksh (ksh)
 |   \--= 03864 sakae emacs tmux.c (emacs-27.1)

サーバーにgdbをアタッチしてgdbが入力待ちになってると、tmuxが開いてるwindowからの入力は出来ない。しかし、クライアントにgdbをアタッチした時は、windowからの入力をブロックされる事は無い。

この現象を捉えると、クライアントは、単にサーバーを起動するだけのように思える。んだけど、何でクライアントは居座っているの? 何か役目が有るはずとデカは考える。考える。考える。起動時に-vをつけて、サーバー/クライアントの両者友、ログを残すようにしてるんで、クライアントのログでも確認してみる。

vbox$ cat tmux-client-80340.log
  :
1615007794.094493 client loop enter
1615007794.517364 peer 0x6cf7b000 message 207
1615007794.517746 sending message 208 to peer 0x6cf7b000 (0 bytes)
vbox$ date -r 1615007794
Sat Mar  6 14:16:34 JST 2021

この状態で、PuTTYの接続を強制切断。そして、再度sshでlogin。クライアントのログを確認。

vbox$ cat tmux-client-80340.log
  :
1615007794.517746 sending message 208 to peer 0x6cf7b000 (0 bytes)
1615011118.959884 client loop exit
vbox$ date -r 1615011118
Sat Mar  6 15:11:58 JST 2021

切断した時、クライアントの何処かでループしてたのが、そこを抜け出したって事を検出したんだな。だったら、それをサーバー側に伝えて、良きに計らって欲しいと懇願してるのではなかろうか。

vbox$ grep 1615011118 tmux-server-1678.log
1615011118.959156 /dev/ttyp0: read closed
1615011118.959204 lost client 0x42f1b000
1615011118.959345 removing term xterm
1615011118.959684 remove peer 0x6bd30000
1615011118.977591 unref client 0x42f1b000 (1 references)
1615011118.977751 recalculate_size: @0 is 80,31
1615011118.977794 recalculate_size: @1 is 80,31
1615011118.977866 cmdq_next <global>: empty
1615011118.977903 server_client_check_pane_buffer: pane %0 is on
1615011118.977939 @0 active pane not changed
1615011118.977973 server_client_check_pane_buffer: pane %1 is on
1615011118.978006 @1 active pane not changed
1615011118.978121 free client 0x42f1b000 (0 references)
1615011118.978226 cmdq_next <global>: empty
1615011118.978460 server_client_check_pane_buffer: pane %0 is on
1615011118.980693 @0 active pane not changed
1615011118.982547 server_client_check_pane_buffer: pane %1 is on
1615011118.982585 @1 active pane not changed

サーバー側もそれに呼応して、何やらアクションを起こしているな。 当然ながら、事故が起こって、デタッチされた状態だ。

vbox$ tmux ls
0: 2 windows (created Sat Mar  6 14:16:34 2021)

アタッチするには、tmux a して、サーバー側に知らせる必要がある。 その時、サーバー側でロックされてたら? クライアント側は待ちに入るのかな? 実験したら、ロックは解除された状態で、アタッチされたよ。非常事態だから、ロックが解放されたんだな。

昔読んだ時代小説を思い出した。小伝馬町の牢屋敷近くで火事が発生。このままでは、牢も燃える。幾ら罪人と言えども、閉じ込めておいて丸焼けにするのは忍びない。看守は独断で、罪人を解放する。但し、XX日までに、戻って来いよと念を押す。

それから、罪人のそれぞれの事情で、戻ろうか、そのまま、とんづらしようかの葛藤が始まる。確か、江戸の赤猫とかいう題名がついていたな。 赤猫異聞 って、浅田次郎さんの小説だった。次郎さんと言えば、強力伝・孤島の孤島を読んでみたいんだけど、図書館に無いんだよね。

ついつい余計な事を書いてしまったな。ならば、余計な事ついでに、tmuxの緑色のstatus-lineが15秒間隔で更新される事に気がついた(サーバーのログを調べていてね)。

この15秒は、コード中に記述してあるはず。一番可能性が高そうなのは、tmu.h。でもそれらいいのは見当たらず。で、Cのファイルをガサ入れ。やつは、こんな所に潜んでいたぞ。

options-table.c

{ .name = "status-interval",
  .type = OPTIONS_TABLE_NUMBER,
  .scope = OPTIONS_TABLE_SESSION,
  .minimum = 0,
  .maximum = INT_MAX,
  .default_num = 15,
  .unit = "seconds",
  .text = "Number of seconds between status line updates."
},

{ .name = "lock-command",
  .type = OPTIONS_TABLE_STRING,
  .scope = OPTIONS_TABLE_SESSION,
  .default_str = "lock -np",
  .text = "Shell command to run to lock a client."
},

上で出て来た、ロックだぜいってやつも、ここに有った。カスタマイズ出来るデータをデフォをまとめて、収録してるのね。

status-interval interval
        Update the status line every interval seconds.  By default,
        updates will occur every 15 seconds.  A setting of zero disables
        redrawing at interval.

これ、ソースの内容とmanが一致してるか調べた図。ちゃんと保守されてた。リナ系はどうよ?

execl by tmux

何となくソース(見)してたんだ。そしたら、exec系の呼び出しが目に入ってきた。これって、コマンドを起動するシステムコールもどきじゃないですか。tmuxは新しいWindowを作る時、shellを割り当てている。と言う事は、この流れを追えば、windowが作成される過程が分かる(かも知れない)な。

サーバーにアタッチしてから、下記の準備をする。

(gdb) set follow-fork-mode child
(gdb) b execl
Breakpoint 1 at 0x1417cbd: file /usr/src/lib/libc/gen/exec.c, line 50.
(gdb) c
Continuing.
[New process 38761]            ;; tmux server
[New process 47332]            ;; gdb-side ksh
[Switching to thread 294425]

Thread 2.1 hit Breakpoint 1, _libc_execl (name=0x46f14aa0 "/bin/ksh", arg=0x4ec84500 "-ksh") at /usr/src/lib/libc/gen/exec.c:50
50              va_start(ap, arg);

forkしたら子供側を追いかけてねの設定。execlにBPを置いてからcontinue。そして、tmux側で、PREFIX+c して、新たなWindowを作成。kshがlogin-shellの権限で起動した。

(gdb) bt
#0  _libc_execl (name=0x46f14aa0 "/bin/ksh", arg=0x4ec84500 "-ksh") at /usr/src/lib/libc/gen/exec.c:50
#1  0x162d67d1 in spawn_pane (sc=0xcf7ded10, cause=0xcf7ded0c) at spawn.c:438
#2  0x162d51af in spawn_window (sc=0xcf7ded10, cause=0xcf7ded0c) at spawn.c:173
#3  0x162550a7 in cmd_new_window_exec (self=0x4bfe5bc0, item=0x40299280) at cmd-new-window.c:100
#4  0x1625ce36 in cmdq_fire_command (item=0x40299280) at cmd-queue.c:613
#5  0x1625c9bb in cmdq_next (c=0x7d840800) at cmd-queue.c:729
#6  0x162cf659 in server_loop () at server.c:254
#7  0x162b49b7 in proc_loop (tp=0x3f953400, loopcb=0x162cf5f0 <server_loop>) at proc.c:203
#8  0x162cedd9 in server_start (client=0x4d457000, flags=402718720, base=0x6ba7fc00, lockfd=5, lockfile=0x640a1080 '\337' <repeats 199 times>, <incomplete sequence \337>...) at server.c:235
#9  0x16242d41 in client_connect (base=0x6ba7fc00, path=0x56ad4a80 "/tmp/tmux-1000/default", flags=402718720) at client.c:161
#10 0x16241cb6 in client_main (base=0x6ba7fc00, argc=0, argv=0xcf7df278, flags=402718720, feat=0) at client.c:292
#11 0x162e005a in main (argc=0, argv=0xcf7df278) at tmux.c:502

ソースを追うのにetagを使って、緻密にやるのもいいけど、こうやって大まかな流れを掴んでおくと、迷子になる事もなくて良いな。

lock

ついでなので、ロックだぜいも行ってみる。

gdb) b cmd_lock_server_exec
Breakpoint 1 at 0x1a7ae17a: file cmd-lock-server.c, line 67.
(gdb) c
  :
(gdb) bt 5
#0  cmd_lock_server_exec (self=0x821fb100, item=0x53d57d80) at cmd-lock-server.c:68
#1  0x1a7b7e36 in cmdq_fire_command (item=0x53d57d80) at cmd-queue.c:613
#2  0x1a7b79bb in cmdq_next (c=0x59df3000) at cmd-queue.c:729
#3  0x1a82a659 in server_loop () at server.c:254
#4  0x1a80f9b7 in proc_loop (tp=0x5f837800, loopcb=0x1a82a5f0 <server_loop>) at proc.c:203
(More stack frames follow...)

server-fn.c

void
server_lock_client(struct client *c)
{
        const char      *cmd;

        if (c->flags & CLIENT_CONTROL)
                return;

        if (c->flags & CLIENT_SUSPENDED)
                return;

        cmd = options_get_string(c->session->options, "lock-command");
        if (*cmd == '\0' || strlen(cmd) + 1 > MAX_IMSGSIZE - IMSG_HEADER_SIZE  )
                return;
        tty_stop_tty(&c->tty);
=>      tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP));
        tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR));
        tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3));

        c->flags |= CLIENT_SUSPENDED;
        proc_send(c->peer, MSG_LOCK, -1, cmd, strlen(cmd) + 1);
}

tty_stop_tty を実行した所で、tmux-statusラインが消えた。次の行が実行されたら、画面がクリアされた。最後の行で、規定の lock -np に制御を渡すんだな。

こういう追跡劇、オイラーは大好きよ。

今まで、 Lock Lock Lock だぜいって騒いでいたけど、本当は Rock だぜいじゃなかろうか? 内田先生に失礼だぞ。大体オイラーは、LとRの区別がつかない人だからなあ。


This year's Index

Home