argv[0]
Binary Hacksがようやく届き、ざっと目を通しました。
HACK#64の「実行中のプロセスのパス名をチェックする」を読んで、実行中に実行ファイルを移動したらどうなるのかと思い、試してみました。
まずは、Linux。(ファイル移動の時間稼ぎのためgets()が入ってます。)
% cat>exe_name.c #include <stdio.h> #include <unistd.h> int main(void) { char buf[4096]; gets(buf); buf[readlink("/proc/self/exe", buf, sizeof(buf)-1)] = '\0'; puts(buf); return 0; } ^D % gcc -o exe_name exe_name.c % ./exe_name /tmp/exe_name % ./exe_name& % mv exe_name exe % fg /tmp/exe
無事、移動後のパス名が取得できました。
ちなみに、readlink()は末尾にヌル文字を付けないので、サイズは「sizeof(buf)-1」を指定しています。
また、readlink()の戻り値はバッファに書き込んだサイズなので、それを元に末尾をヌル文字で埋めています。
ついでにシンボリックリンクとハードリンクも調査しました。
% ln -s exe sym % ./sym</dev/null /tmp/exe % ln exe link % ./link</dev/null /tmp/link
シンボリックリンクの場合はターゲットのパスになりました。
ハードリンクは当然そのままです。
一方、Windowsでは、
C:\Temp> type CON>exe_name.c #include <windows.h> #include <stdio.h> int main(void) { char buf[MAX_PATH]; gets(buf); GetModuleFileName(GetModuleHandle(NULL), buf, sizeof(buf)); puts(buf); return 0; } ^Z C:\Temp> cl exe_name.c C:\Temp> exe_name<NUL C:\Temp\exe_name.exe C:\Temp> exe_name&ren exe_name.exe exe.exe C:\Temp\exe_name.exe
移動しても結果は反映されないようです。
一応ジャンクションも試してみましたが、POSIXと違ってジャンクションの名前が表示されました。
それとargv[0]ですが、これはあまり役に立たないものでして、何でも設定できます。
% cat>argv.c #include <unistd.h> int main(void) { execlp("./argv", "hoge", "1", "2", 0); return 0; } ^D % cat>argv0.c #include <unistd.h> int main(int argc, char* argv[]) { execvp(argv[1], argv+2); return 0; } ^D % gcc -o argv argv.c % gcc -o argv0 argv0.c % ./argv 1 2 ./argv 1 2 % ./argv0 ./argv hoge 1 2 hoge 1 2
DJBのucspi-tcpに同名のプログラムがあります。
http://tools.qmail.jp/ucspi-tcp/argv0.html
また、bashのようにargv[0]の内容で動作が替わるプログラムもあります。
http://www.linux.or.jp/JM/html/GNU_bash/man1/bash.1.html
結局、argv[0]はただの慣習なので、利用はusage程度に留めておいたほうがよいと思います。
WindowsのCreateProcess()もほぼ同じ仕様ですが、面倒なので省略します。
(21:50追記)
Linuxで、実行中にファイルを消したら、
/tmp/link (deleted)
のように「 (deleted)」が付きました。
(11/17 09:34追記)
元々「link (deleted)」というファイル/ディレクトリがあっても、「link (deleted)」になりました。
これでいいんだろうか、、、。