/dev/tty
先日 のエントリで「tty デバイスに...」と書いたのだが*1、tty とは何? たまに聞くことはあっても、よくわかっていないのだ。
tty について調べていると、次のようなことができるとわかった。
% tty # 自分の制御端末を調べる /dev/pts/0 % echo "hello world" > /dev/pts/0 # 自分の制御端末にデータを書き込む hello world # 書き込んだデータが表示される (echo の出力が表示されたわけではない)
ひとつの端末でやるとよくわからないんだけど、2 つ使うとわかりやすいと思う。
そういえば、マシンを shutdown させるとき次のようなメッセージが端末に表示される。
hogehoge@fugafuga からのブロードキャスト・メッセージ (/dev/pts/1) at 21:22 ... The system is going down for reboot NOW!
今までどうやって表示させているのかわからなかったけど、何となくわかった気がする。ので、shutdown コマンドがどのようにメッセージを各端末に送っているのかを調べてみた。ソースは http://launchpad.net/upstart/0.6/0.6.3/+download/upstart-0.6.3.tar.gz。
shutdown.c を追ってみると wall() という関数がどうもそれくさい。以下は、shutdown.c の 732 行目から 767 行目を抜き出してみた。
/* Iterate entries in the utmp file */ setutxent (); while ((ent = getutxent ()) != NULL) { char dev[PATH_MAX + 1]; int fd; /* Ignore entries without a name, or not a user process */ if ((ent->ut_type != USER_PROCESS) || (! strlen (ent->ut_user))) continue; /* Construct the device path */ if (strncmp (ent->ut_line, DEV "/", 5)) { snprintf (dev, sizeof (dev), "%s/%s", DEV, ent->ut_line); } else { snprintf (dev, sizeof (dev), "%s", ent->ut_line); } alarm (2); fd = open (dev, O_WRONLY | O_NDELAY | O_NOCTTY); if ((fd >= 0) && isatty (fd)) { FILE *term; term = fdopen (fd, "w"); if (term) { fprintf (term, "\007\r\n%s\r\n\t%s\r\n\r\n", banner1, banner2); fputs (message, term); fflush (term); fclose (term); } } alarm (0); } endutxent ();
getutxent() で現在ログイン中のユーザの情報を得る。ログイン中のユーザの情報は /var/run/utmp にある。これでユーザがどの端末を使っているのかがわかるので、その端末に向けてメッセージを送っている。
大体予想通りの仕組みになっていた。ただ、ほんの 35 行程抜き出しただけなのに、知らない関数が多くあった。普通のアプリを作るだけじゃなく OS 寄りのアプリ (?) を書いて(読んで)みるのもいい刺激になるかも。
で、結局 tty ってなんだっけ?制御端末?
*1:引用部だけど