つうさにメモブログ

つうさにがメモをブログとして書いていくところ

実行ファイル名で動作が変わるCLIたち

同じ実行ファイルなのに動作が違うことに、慣れてなくてびっくりした。

qiita.com

上の記事を読みました。

systemdなGNU/Linuxにおいてshutdownコマンド(/sbin/shutdown)やhaltコマンド(/sbin/halt)などは、実はただのシンボリックリンクで、どれも/bin/systemctlを実行しているようです。 同じバイナリなのに呼び出すコマンド名によって違う動作をするということです。

最初どうやって実現してるんだろうと不思議に思ってしまいましたが、よく考えればmain関数でargv[0]を使って動作を変えればいいだけでした。やっていることは--versionみたいなオプションで動作が変わるのと同じですね。

TeX Liveでのバイナリたち

実はTeXで用いられるあれやこれやなコマンドたちもこのような機能をもってたりします。

pdfTeX

たとえば、TeX Live (2018)においてpdfetexpdflatexなどのコマンドは、pdftexという名前の実行可能ファイルへのシンボリックリンクです。

$ cd /usr/local/texlive/2018/bin/x86_64-linux/
$ ls -l pdftex etex latex pdfetex pdflatex
lrwxrwxrwx 1 root root       6 11月 26  2016 etex -> pdftex
lrwxrwxrwx 1 root root       6 11月 26  2016 latex -> pdftex
lrwxrwxrwx 1 root root       6 11月 26  2016 pdfetex -> pdftex
lrwxrwxrwx 1 root root       6 11月 26  2016 pdflatex -> pdftex
-rwxr-xr-x 1 root root 2175808  9月 20  2018 pdftex
$

これらは同じ実行ファイルを実行しますが、もちろん動作は異なります。具体的には、別のfmtファイルが読み込まれます。(参考: Web2c: A TeX implementation; Determining the memory dump to use)

ここで注目なのはetexlatexでさえ、pdftexが使われているということですね。(参考: https://oku.edu.mie-u.ac.jp/texconf10/presentations/yato.pdf; 今どき、(TRIP テストの意味で)TeX なんて誰も使っていない!)

dvipdfmx

日本語LaTeXでよく使われる、dviファイルからpdfを生成するdvipdfmxも同じようなことになっています。

$ ls -l xdvipdfmx dvipdfm dvipdfmx ebb extractbb
lrwxrwxrwx 1 root root      9 11月 26  2016 dvipdfm -> xdvipdfmx
lrwxrwxrwx 1 root root      9 11月 26  2016 dvipdfmx -> xdvipdfmx
lrwxrwxrwx 1 root root      9 11月 26  2016 ebb -> xdvipdfmx
lrwxrwxrwx 1 root root      9 11月 26  2016 extractbb -> xdvipdfmx
-rwxr-xr-x 1 root root 978840  9月 20  2018 xdvipdfmx
$

dvipdfmxのソースはC言語なのでわかりやすいです。

http://www.tug.org/svn/texlive/trunk/Build/source/texk/dvipdfm-x/dvipdfmx.c?revision=51819&view=markup#l1089

argv[0]から得られた文字列を比較(FILESTRCASEEQ)して、動作が変わります。

おわり

TeX Live 2018では、dvipdfmxもシンボリックリンクになってるんですね。

おしまい💫

追記

同様の機能がある実行ファイルとしてBusyBoxというものを知りました。これは複数のコマンド(lsmvなど他多数)をひとつの小さな実行ファイルにまとめたものようです。

busybox lsなどでも呼び出せますが、/bin/lsなどと名前をつけたシンボリックリンクを置いておけば、BusyBoxによるものであることを意識することなくlsコマンドを使えます。