Who コマンドを掘り下げよう

Who コマンドとは

基who コマンドでは、現在システムにログオンしているユーザーを一覧表示することができます。 

$ who
user1 tty2         2020-08-30 15:06 (tty2)
user1 pts/1        2020-08-30 15:06 (tmux(1555).%0)
user1 pts/2        2020-08-30 16:41 (tmux(1555).%6)
user1 pts/4        2020-08-30 15:57 (tmux(1555).%3)

物理的な端末 tty2 と 3 つの疑似端末でログインしていることを教えてくれている。この例だと現在のGnome Shellのセッションはtty2で実行されており、3つのtmuxウィンドウが開いている。

しかし、これらの情報はどこから取得しているのか?Linuxではすべてファイルとして扱われることを思い出すと、この情報はおそらくファイルからだと推測できるが、どのファイルにどのようにデータが保存されているのか確認してみたい。

ちょっとしたリバースエンジニアリング

whoコマンドが何をしているのかを見るために、ソースコードを見つけてそれを掘り下げてみることができる。また、代わりにstraceを使ってプロセスが何をしているかをチェックするのが面白い。

$ strace who 2>&1 | grep open
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 3

最初のファイル /etc/ld.so.cache, /usr/lib/libc.so.6 はプロセスが読み込んだ共有ライブラリである。

次に、/usr/lib/locale/local-archive, /var/run/utmp, /etc/localtime が開かれる。これらのファイルが何を保存しているのか見てみよう。

manで確認してみると、マニュアルの第5章は「ファイル形式と規約(“file formats and conventions” )」にページが割かれていることがわかる。ここをしらべよう。

locale-archive

$ man -wK 5 '/usr/lib/locale/locale-archive'
Sends us to locale(5) where we can read:

ロケール定義ファイルには、localedef(1) コマンドがそれをバイナリロケールのデータベースに変換するために必要なすべての情報が含まれている。 このページでは、これらの情報についてのより詳しい説明のために locale(7) にもかかれている。

ロケールとは、言語と文化のルールの集合です。ロケールとは、言語や文化のルールの集合です。 メッセージの言語、文字セット、語彙・図形の規則などが含まれます。プログラムは、異文化に移植できるようにロケールを決定し、それに応じて行動できるようにしなければなりません。 そこで、who コマンドはこのファイルを読み込んで、おそらく setlocale(3) 関数を使って、情報の書式や表示方法を調べていることがわかるだろう。

これは以下のように実際に確認することができる。

$ LC_ALL='fr_FR.utf8' who
gauthier tty2         Sep  2 11:38 (:1)
gauthier pts/1        Sep  2 12:11 (tmux(2445).%0)
gauthier pts/2        Sep  2 12:37 (tmux(2445).%1)
gauthier pts/3        Sep  2 13:04 (tmux(2445).%2)

確かに、日付は同じようにフォーマットされていません!

localtime
$ man -wK 5 '/etc/localtime'

localtime(5) は

・etc/localtime ファイルは、アプリケーションがユーザに表示するために使用するローカルシステムのシステム全体のタイムゾーンを設定。

となる。

おそらくwhoがこのファイルを使っているか(あるいはこのファイルを使っている関数を使っているか)は、ユーザによって設定された正しいタイムゾーンを使ってタイムスタンプ(誰の出力の4列目と5列目)をprintしてうr