如何在C中找到可执行文件的位置?

era*_*ran 140 c c++ unix linux path

在C/C++中是否有办法找到当前执行程序的位置(完整路径)?

(问题argv[0]在于它没有给出完整的路径.)

lis*_*ine 189

总结一下:

  • 在Unix上,/proc真正直接和可行的方法是:

    • readlink("/proc/self/exe", buf, bufsize) (Linux)的

    • readlink("/proc/curproc/file", buf, bufsize) (FreeBSD的)

    • readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)上

  • 在Unix上没有/proc(即如果失败):

    • 如果argv [0]以"/"(绝对路径)开头,则这是路径.

    • 否则,如果argv [0]包含"/"(相对路径),则将其附加到cwd(假设它尚未更改).

    • 否则搜索目录中$PATH的可执行文件argv[0].

    之后,检查可执行文件是否实际上不是符号链接可能是合理的.如果是相对于symlink目录解析它.

    / proc方法中不需要此步骤(至少对于Linux).proc符号链接直接指向可执行文件.

    请注意,由调用进程argv[0]正确设置.大多数时候都是正确的,但有时候调用进程不可信(例如setuid可执行文件).

  • 在Windows上:使用 GetModuleFileName(NULL, buf, bufsize)

  • 任何依赖于argv [0]作为程序名称的东西都是不可靠的.它大部分时间都可以工作,但不是*每一次.没有/ proc的unix上这个问题很难 (21认同)
  • 并非所有带proc的unix都有/ proc/self/exe./ proc的布局完全是特定于操作系统的,它们的执行方式略有不同.例如,FreeBSD提供的/ proc/curproc/file与Linux的/ proc/self/exe相同.但其他人可能根本不这样做. (8认同)
  • 请注意,如果有人需要隐藏他们的踪迹,那么`execl("/ home/hacker/.hidden/malicious","/ bin/ls"," - s",(char*)0);`leaves`argv [ 0]`绝对路径名,与执行文件的名称无关.但是,其他信息很有用; 谢谢. (6认同)
  • 一个模糊的角落案例:如果 exe 驻留在 clearcase MVFS 视图中,则 Linux /proc/self/exe 方法不太适用,因为 Linux 最终返回视图存储目录中可执行文件的位置,而不是 /view 限定小路。例如,对于 /vbs/bldsupp/linuxamd64/clang/debug/bin/llvm-config /proc/self/exe 将我指向不友好的路径:/home/peeterj/views/peeterj_clang-7.vws/.s/00024/ 8000023250b8f17fllvm-tblgen (3认同)
  • 在Windows上,您不必调用`GetModuleFileName`.相反,只需`#include <windows.h>`并使用Windows自动提供的路径字符串`_pgmptr`.它比使用`GetModuleFileName`函数更容易,因为它有可能失败. (2认同)

Shi*_*C G 22

如果您使用的是Windows,请使用GetModuleFileName()函数.

  • 谢谢,但我正在使用linux和unix. (3认同)

Dal*_*und 17

请注意,以下注释仅限unix.

迂腐这个问题的答案是,没有一般在所有情况下正确地回答这个问题的方式.正如您所发现的那样,父进程可以将argv [0]设置为任何内容,因此无需与程序的实际名称或其在文件系统中的位置有任何关系.

但是,以下启发式通常有效:

  1. 如果argv [0]是绝对路径,则假设这是可执行文件的完整路径.
  2. 如果argv [0]是一个相对路径,即它包含a /,则用getcwd()确定当前工作目录,然后将argv [0]附加到它.
  3. 如果argv [0]是一个普通单词,搜索$ PATH寻找argv [0],并将argv [0]追加到你找到它的任何目录中.

请注意,所有这些都可以通过调用相关程序的过程来规避.最后,您可以使用特定于Linux的技术,例如emg-2提到的技术.其他操作系统可能有相同的技术.

即使假设上面的步骤为您提供了有效的路径名,您仍然可能没有您真正想要的路径名(因为我怀疑您实际想要做的是在某处找到配置文件).硬链接的存在意味着您可以遇到以下情况:

-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo     # create a hard link to foo
$ /some/where/else/foo
Run Code Online (Sandbox Code Playgroud)

现在,上面的方法(包括,我怀疑,/ proc/$ pid/exe)将/some/where/else/foo作为程序的真实路径.而且,事实上,这是该计划真正途径,而不是您想要的那个.请注意,符号链接不会出现此问题,这在实践中比硬链接更常见.

尽管这种方法原则上不可靠,但在大多数情况下,它在实践中运行良好.


Mic*_*ael 10

实际上不是一个答案,但只是要记住一个注意事项.

正如我们所看到的,在Linux和Unix中找到运行可执行文件的位置的问题非常棘手并且特定于平台.在做这件事之前,应该三思而行.

如果您需要可执行文件的位置,用于发现一些配置或资源文件,也许你应该遵循将文件放置到系统的Unix的方式:把CONFIGS到/etc/usr/local/etc或在当前用户的主目录,/usr/share是把你的资源文件的好地方.


小智 6

在许多POSIX系统中,您可以检查位于/ proc/PID/exe下的simlink.几个例子:

# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond
Run Code Online (Sandbox Code Playgroud)

  • / proc不是POSIX,它不是很标准化.许多现代统一有它,有些则没有. (13认同)
  • 在Linux/proc文件系统中是一个内核级选项 - 因此无法保证在任何给定的Linux系统上可用或启用它.此外,它可以在内核中启用,但如果/ etc/fstab没有挂载点则不可用.此外,您可能会遇到安全问题. (3认同)

Tho*_*mas 5

请记住,在 Unix 系统上,二进制文件可能自启动以来已被删除。它在 Unix 上是完全合法和安全的。最后我检查了 Windows 不允许您删除正在运行的二进制文件。

/proc/self/exe 仍然是可读的,但它实际上不会是一个有效的符号链接。这会……很奇怪。

  • 什么都不会发生。IIRC,您不会“删除”文件,而只是删除其在目录中的条目。一旦对它的所有引用消失,实际文件将自动删除。引用可以是文件系统条目(硬链接)或打开的文件描述符(例如作为进程的映像)。因此,在您“删除”该文件后,您将看不到该文件,但实际删除将推迟到该过程终止。 (3认同)