web-dev-qa-db-ja.com

exec関数でファイル名を2回渡す必要があるのはなぜですか?

私はNIX環境での高度なプログラミングを読んだ番目 章。 6つのexec関数すべてを読んで理解しました。

私が気づくのは、すべてのexec関数で:

  • 最初の引数は、ファイル名/パス名です(exec関数によって異なります)。
  • 2番目の引数はmain()で取得するargv [0]です。これはファイル名自体です。

したがって、ここでは関数でファイル名を2回渡す必要があります。

それには何らかの理由がありますか(最初の引数からパス名からファイル名を取得できないなど)?

11
munjal007

したがって、ここでは関数でファイル名を2回渡す必要があります。

それらは、それらのoneが_argv[0]_値として使用されていることを確認することで気づくのとまったく同じではありません。これは、実行可能ファイルのベース名と同じである必要はありません。多くの/ほとんどのものがそれを無視し、あなたが望むものをそこに置くことができます。

1つ目は、実行可能ファイルへの実際のパスです。これには、明らかに必要があります。 2番目のものは、それを呼び出すために使用された名前としてプロセスに渡されますが、例えば:

_execl("/bin/ls", "banana", "-l", NULL);
_

_/bin/ls_が正しいパスであると仮定して、正常に動作します。

ただし、一部のアプリケーションは_argv[0]_を使用します。通常、これらは_$PATH_に1つ以上のシンボリックリンクがあります。これは圧縮ユーティリティでは一般的です(代わりにシェルラッパーを使用する場合があります)。 xzがインストールされている場合、stat $(which xzcat)はそれがxzへのリンクであることを示し、_man xzcat_は_man xz_と同じで、「xzcatはxz --decompress --stdout "と同等です。 xzがどのように呼び出されたかを知る方法は、_argv[0]_をチェックして同等のものにすることです。

_execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);
_
14
goldilocks

ファイル名を2回渡す必要はありません。

1つ目は、実際に実行されるファイルです。

2番目の引数は、argv[0]プロセスの名前、つまり、プロセスがその名前として何を表示するか。例えば。シェルからlsを実行する場合、最初の引数は/bin/ls、2番目はlsです。

特定のファイルを実行し、2番目の引数を介して別のファイルを呼び出すことができます。プログラムはその名前をチェックし、名前に応じて異なる動作をすることができます。これはハードリンク(またはシンボリックリンク)を介して行うこともできますが、これにより柔軟性が高まります。

6
wurtel

重要なのは、_argv[0]_は(NULLを含めて)何にでも設定できるということです。 慣例により、_argv[0]_は、実行可能ファイルが開始されたときのパスに設定されます(execve()を実行するときにシェルプロセスによって)。

_./foo_と_dir/bar_が同じ実行可能ファイルへの2つの異なるリンク(ハードまたはシンボリック)である場合、2つのパスを使用してシェルからプログラムを起動すると、_argv[0]_が_./foo_に設定されます。および_dir/bar_、それぞれ。

_argv[0]_がNULLになる可能性があるという事実は見過ごされがちです。次のコードは、たとえばNULL _argv[0]_の場合にクラッシュする可能性があります(ただし、glibcは_argv[0]_の代わりに<null>のように出力します)。

_if (argc != 3) {
    fprintf(stderr, "%s: expected 2 arguments\n", argv[0]);
    exit(EXIT_FAILURE);
}
_

Linuxの代替手段は、そのような場合に_/proc/self/exe_を使用することです。

1
Ulfalizer