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)」になりました。
これでいいんだろうか、、、。