Answers:
因此,这里我们必须在函数中两次传递文件名。
通过观察将其中之一用作argv[0]
值,它们与您注意到的完全不同。这不必与可执行文件的基本名称相同。许多/大多数事物都忽略了它,您可以在其中放置任何内容。
第一个是可执行文件的实际路径,显然有必要。表面上,第二个作为用于调用它的名称传递给该进程,但是,例如:
execl("/bin/ls", "banana", "-l", NULL);
会正常工作,假定/bin/ls
是正确的路径。
但是,某些应用程序确实使用argv[0]
。通常,这些链接中包含一个或多个符号链接$PATH
;这在压缩实用程序中很常见(有时它们使用Shell包装器代替)。如果已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);
/bin/ls
是busybox,它将不知道如何执行banana
!
您不必两次传递文件名。
第一个是实际执行的文件。
第二个参数是argv[0]
流程的名称,即流程应将其视为什么。例如,如果您ls
从外壳程序运行,则第一个参数是/bin/ls
,第二个参数是just ls
。
您可以执行某个文件,然后通过第二个参数将其调用。程序可以检查其名称,并根据名称进行不同的处理。这也可以通过硬链接(或符号链接)来完成,但是这种方式提供了更大的灵活性。
argv[0]
为链接名称。
要点是argv[0]
可以设置为任何值(包括NULL
)。按照约定,argv[0]
将设置为可执行文件的启动路径(由shell进程执行时execve()
)。
如果./foo
和dir/bar
是指向同一可执行文件的两个不同链接(硬链接或符号链接),则使用两个路径从shell启动程序将分别设置argv[0]
为./foo
和dir/bar
。
argv[0]
可以NULL
忽略的事实常常被忽略。例如,以下代码可能会崩溃NULL
argv[0]
(尽管glibc打印类似<null>的内容argv[0]
):
if (argc != 3) {
fprintf(stderr, "%s: expected 2 arguments\n", argv[0]);
exit(EXIT_FAILURE);
}
Linux上的一种替代方法是/proc/self/exe
用于这种情况。
./foo
和一次dir/bar
。argv[0]
在这两种情况下会有所不同(在每种情况下,它都将与您使用的路径相同)。
argv[0]
时可以设置为任何内容exec*()
。将外壳程序设置argv[0]
为用于启动程序的路径是一种惯例(并且明智的做法是在您exec*()
编写程序时执行此操作,因为许多程序会检查argv[0]
并希望它保留路径)。
busybox
您如何将其定义为正确的名称?