【问题标题】:Can an executable discover its own path? (Linux) [duplicate]可执行文件可以发现自己的路径吗? (Linux)[重复]
【发布时间】:2010-10-26 15:44:55
【问题描述】:

可能重复:
how to find the location of the executable in C

我希望可执行文件能够发现自己的路径;我感觉答案是“你不能这样做”,但我希望得到证实!

我认为我不能使用getcwd(),因为我可能不会从同一个目录执行它。我认为我不能使用argv[0],因为那是基于用于执行它的字符串。还有其他选择吗?

基本原理

真正的问题是我想在文件系统的某个地方放置一个可执行文件,并在它旁边放置一个默认配置文件。我希望可执行文件能够在运行时读取其配置文件,但我不想将此位置硬编码到可执行文件中,也不希望用户必须设置环境变量。如果这种情况有更好的解决方案,我会全力以赴......

【问题讨论】:

  • "如果这种情况有更好的解决方案",是的,照别人的做法,把配置文件放到/etc目录下。
  • @Steve:是的,这个问题的答案正是我想要的。谢谢!
  • 这是一个典型的答案,很高兴有帮助
  • @Anders:我不能这样做的原因是因为这将位于每个人都可以使用的 NFS 共享上。不能放到大家本地的/etc目录下!

标签: c linux


【解决方案1】:

文件 /proc/self/exe 是当前运行的可执行文件的 simlink。

【讨论】:

【解决方案2】:

编辑:有人指出,使用/proc/self/exe 更直接。这是完全正确的,但我没有看到编辑代码有任何好处。由于我仍然得到有关它的信息,因此我已经对其进行了编辑。

#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

int main()
{
  char dest[PATH_MAX];
  memset(dest,0,sizeof(dest)); // readlink does not null terminate!
  if (readlink("/proc/self/exe", dest, PATH_MAX) == -1) {
    perror("readlink");
  } else {
    printf("%s\n", dest);
  }
  return 0;
}

初步答案: 您可以使用 getpid() 查找当前进程的 pid,然后读取 /proc/&lt;pid&gt;/cmdline(供人类阅读器使用)或 /proc/&lt;pid&gt;/exe,这是指向实际程序的符号链接。然后,使用 readlink() 可以找到程序的完整路径。

这是一个 C 语言的实现:

#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>

int main()
{
  char path[PATH_MAX];
  char dest[PATH_MAX];
  memset(dest,0,sizeof(dest)); // readlink does not null terminate!
  pid_t pid = getpid();
  sprintf(path, "/proc/%d/exe", pid);
  if (readlink(path, dest, PATH_MAX) == -1) {
    perror("readlink");
  } else {
    printf("%s\n", dest);
  }
  return 0;
}

如果你想尝试,你可以编译它,从可执行文件到另一个路径的符号链接,然后调用链接:

$ gcc -o mybin source.c
$ ln -s ./mybin /tmp/otherplace
$ /tmp/otherplace
/home/fser/mybin

【讨论】:

  • 正如@Cercerilla 的回答中所指出的,/proc/self/exe 的工作方式与/proc/&lt;PID&gt;/exe 一样,您不必费心找出自己的 pid。
  • 没错,我最近一直在用self
  • 您的/proc/.../exe 策略是正确的。使用snprintf(注意n)而不是sprintf。使用%ld 而不是%d 并将pid 转换为long。使用/proc/self/exe 可以避免这两个问题。将readlink() 结果存储在ssize_t n; 中并检查(size_t)n &lt; sizeof(dest)
  • @Lassi 感谢您的评论! sprintf(与 snprintf 相对)的假设是,我们正在将现有路径复制到静态分配的 PATH_MAX 之一中。隐含地假设现有路径不能更大。您是否看到实际情况并非如此?
  • 不——你是对的,在这种情况下没有实际的场景。原因很简单,sprintfstrcpy 经常被不安全地使用,以至于有经验的 C 程序员不再出于任何目的推荐它们,编译器/linter 可能会警告它们。使用snprintf 是一个“我知道我在做什么”的信号,至少可以确保代码中的错误不会变成缓冲区溢出。可以验证 sprintfstrcpy 的单独使用是否正确,但它容易出错并且在大型代码库中需要付出很多努力。
【解决方案3】:

使用proc filesystem

您的流程是:

  • 获取可执行文件的 pid
  • 查看/proc/PID/exe 的符号链接

【讨论】:

  • 为什么投反对票?为什么只在 CodeninjaTim 基本上说同样的话时才投反对票?
  • 无需获取 pid 并动态操作字符串。硬编码的字符串"/proc/self/exe"更简单更好。
  • 这是适用于 Linux 的正确解决方案,不值得反对。 /proc/self/exe 是一种更简单的方法来做同样的事情,但手动插入 PID 仍然可以正常工作。
【解决方案4】:

好吧,您必须将getcwd()argv[0] 结合使用。第一个为您提供工作目录,第二个为您提供二进制文件相对于工作目录的相对位置(或绝对路径)。

【讨论】:

  • 为什么还要对这个投反对票?有人跛脚..
  • 我没有投反对票,但我认为这行不通。 argv[0] 不一定是相对的(考虑从命令行以/blah/my_app 运行可执行文件)。
  • 要运行的程序不在 cwd 中搜索,而是在 $PATH 中搜索,直到您指定可执行文件的路径。
  • argv[0] 甚至可能不是真正的可执行文件名。
  • 不幸的是,这只会在偶然的情况下起作用。可以将任意字符串作为argv[0] 传递给execve()。即使argv[0] 只是一个没有目录部分的基本名称,并且实际上是指可执行文件,该名称通常不在 CWD 中;它可以在PATH 的任何目录中。没有便携式解决方案。对于 Linux,readlink("/proc/self/exe") 解决方案是正确的,并且比 PATH 搜索更容易编码。
【解决方案5】:

argv[0] 获取您的姓名,然后调用which 命令。仅当您的可执行文件位于$PATH 中时,这才有效。

【讨论】:

  • 不幸的是,基于argv[0] 的解决方案只能在偶然情况下起作用。对于简单的任务,还建议避免调用外部命令,例如which,因为这会增加更多可能破坏的因素。虽然没有可移植且可靠的解决方案,但对于 Linux,readlink("/proc/self/exe") 是简单而正确的。
猜你喜欢
  • 2014-11-24
  • 2016-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
相关资源
最近更新 更多