如何实现readlink查找路径

28

使用readlink函数作为解决方案,用于如何在C中找到可执行文件的位置?问题。如何将路径保存到字符数组中?另外,变量buf和bufsize代表什么,如何初始化它们?

编辑:我正在尝试获取当前运行程序的路径,就像上面链接的问题一样。那个问题的答案是使用readlink("proc/self/exe")。我不知道如何将其实现到我的程序中。我尝试过:

char buf[1024];  
string var = readlink("/proc/self/exe", buf, bufsize);  

显然这是错误的。

5个回答

45

正确使用readlink函数可参考POS30-C,使用readlink()函数时要正确处理

如果你的路径在std::string中,你可以像这样做:

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

std::string do_readlink(std::string const& path) {
    char buff[PATH_MAX];
    ssize_t len = ::readlink(path.c_str(), buff, sizeof(buff)-1);
    if (len != -1) {
      buff[len] = '\0';
      return std::string(buff);
    }
    /* handle error condition */
}

如果你只需要一个固定的路径:

std::string get_selfpath() {
    char buff[PATH_MAX];
    ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
    if (len != -1) {
      buff[len] = '\0';
      return std::string(buff);
    }
    /* handle error condition */
}

使用方法:

int main()
{
  std::string selfpath = get_selfpath();
  std::cout << selfpath << std::endl;
  return 0;
}

不好意思,我猜我没有正确表达我的句子。我没有路径,我正在正确使用readlink("/proc/self/exe", buf, bufsize);来检索它。 - a sandwhich
我不明白你在说什么。请编辑你的问题,显示你已经拥有的内容和你想要的示例。 - Mat
好的,我加入了更多细节,但是我的原始答案在使用固定路径时已经非常有效了... - Mat
@a.lasram:这完全不是打字错误。 - Mat
@MatпјҡеҮҪж•°do_readlinkзҡ„еҸӮж•°еә”иҜҘжҳҜд»Җд№ҲеҖјпјҹ - Jackzz
显示剩余4条评论

6

被接受的答案几乎是正确的,但是你不能依赖PATH_MAX,因为如果系统没有这样的限制,则POSIX不保证其定义。(来自readlink(2)手册)

如果系统没有此限制,则无法保证每个POSIX都定义。

此外,当它被定义时,它并不总是代表“真正”的限制。(参见http://insanecoding.blogspot.fr/2007/11/pathmax-simply-isnt.html

readlink的手册还提供了一种在符号链接上执行该操作的方法:

使用静态大小的缓冲区可能不提供足够的空间以容纳符号链接内容。可以从对链接调用lstat(2)返回的stat.st_size值中获取缓冲区所需的大小。但是,应检查readlink()和readlinkat()写入的字节数,以确保符号链接的大小在两次调用之间没有增加。

然而,对于大多数/proc文件,包括/proc/self/exe/,stat.st_size将为0。我所看到的唯一剩下的解决方案是在它不适合的时候调整缓冲区大小。
我建议使用以下vector<char>来实现此目的:
std::string get_selfpath()
{
    std::vector<char> buf(400);
    ssize_t len;

    do
    {
        buf.resize(buf.size() + 100);
        len = ::readlink("/proc/self/exe", &(buf[0]), buf.size());
    } while (buf.size() == len);

    if (len > 0)
    {
        buf[len] = '\0';
        return (std::string(&(buf[0])));
    }
    /* handle error */
    return "";
}

总是加100(而不是像len - buf.size()这样的东西)有什么原因吗? - c-x-berger

4

让我们看看手册上说了什么:

 readlink() places the contents of the symbolic link path in the buffer
 buf, which has size bufsiz.  readlink does not append a NUL character to
 buf.

好的,应该很简单。给定你的1024个字符的缓冲区:

 char buf[1024];

 /* The manpage says it won't null terminate.  Let's zero the buffer. */
 memset(buf, 0, sizeof(buf));

 /* Note we use sizeof(buf)-1 since we may need an extra char for NUL. */
 if (readlink("/proc/self/exe", buf, sizeof(buf)-1) < 0)
 {
    /* There was an error...  Perhaps the path does not exist
     * or the buffer is not big enough.  errno has the details. */
    perror("readlink");
    return -1;
 }

如果(readlink("/proc/self/exe", buf, sizeof(buf)-1) <0),就不应该... - Lucio M. Tato
如果(readlink(/.../))测试为非零。小于0是非零的。 - asveikau
1
readlink在成功时返回>0。"成功时,readlink()返回放置在buf中的字节数。发生错误时,返回-1"。http://linux.die.net/man/2/readlink。 - Lucio M. Tato
好的。那就编辑一下吧。这对于系统调用来说有点不寻常。通常情况下,0表示成功。 - asveikau

2
char *
readlink_malloc (const char *filename)
{
  int size = 100;
  char *buffer = NULL;

  while (1)
    {
      buffer = (char *) xrealloc (buffer, size);
      int nchars = readlink (filename, buffer, size);
      if (nchars < 0)
        {
          free (buffer);
          return NULL;
        }
      if (nchars < size)
        return buffer;
      size *= 2;
    }
}

来源: http://www.delorie.com/gnu/docs/glibc/libc_279.html

此函数将字符串 str 中的第一个 n 个字符复制到字符数组 dest 中,并在末尾添加空字符。如果 str 的长度小于 n,则复制整个字符串并在剩余空间中填充空字符。

返回指向目标字符串 dest 的指针。


1
#include <stdlib.h>
#include <unistd.h>

static char *exename(void)
{
    char *buf;
    char *newbuf;
    size_t cap;
    ssize_t len;

    buf = NULL;
    for (cap = 64; cap <= 16384; cap *= 2) {
        newbuf = realloc(buf, cap);
        if (newbuf == NULL) {
            break;
        }
        buf = newbuf;
        len = readlink("/proc/self/exe", buf, cap);
        if (len < 0) {
            break;
        }
        if ((size_t)len < cap) {
            buf[len] = 0;
            return buf;
        }
    }
    free(buf);
    return NULL;
}

#include <stdio.h>

int main(void)
{
    char *e = exename();
    printf("%s\n", e ? e : "unknown");
    free(e);
    return 0;
}

这里使用传统的“当你不知道正确缓冲区大小时,重新分配增加二的幂”的技巧。我们假设为路径名分配少于64字节的空间不值得。我们还假设一个长达16384(2 ** 14)字节的可执行文件路径名必须指示程序安装方式存在某种异常,并且知道路径名并没有用,因为我们很快就会遇到更大的问题需要担心。
没有必要费心去处理像PATH_MAX这样的常量。为几乎所有路径名保留如此多的内存是过度的,并且正如另一个答案中所指出的那样,它并不能保证实际上限。对于这个应用程序,我们可以选择一个常识上限,例如16384。即使对于没有常识上限的应用程序,重新分配增加二的幂也是一个好方法。您只需要log n调用来获取n字节的结果,浪费的内存容量与结果的长度成比例。它还避免了在realloc()和readlink()之间字符串长度发生变化的竞争条件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接