【问题标题】:How to implement readlink to find the path如何实现readlink查找路径
【发布时间】:2011-07-28 09:28:35
【问题描述】:

使用 readlink 函数作为How do I find the location of the executable in C? 的解决方案,我如何将路径放入 char 数组?另外,变量 buf 和 bufsize 代表什么以及如何初始化它们?

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

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

这显然是不正确的。

【问题讨论】:

    标签: c++ linux path executable


    【解决方案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。即使对于没有常识性上限的应用程序,重新分配 2 的递增幂也是一个好方法。您只需要log n 调用n-byte 结果,您浪费的内存容量与结果的长度成正比。它还避免了字符串长度在realloc()readlink() 之间变化的竞争条件。

    【讨论】:

      【解决方案2】:

      接受的答案几乎是正确的,但您不能依赖 PATH_MAX,因为它是

      如果系统没有这样的定义,则不保证按 POSIX 定义 限制。

      (来自 readlink(2) 手册页)

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

      readlink 的联机帮助页也提供了一种在符号链接上执行此操作的方法:

      使用静态大小的缓冲区可能无法为 符号链接内容。缓冲区所需的大小可以是 从调用 lstat(2) 返回的 stat.st_size 值获得 链接。但是,readlink() 和 read- 写入的字节数 应检查 linkat() 以确保符号的大小 调用之间的链接没有增加。

      但是,对于 /proc/self/exe/ 而言,对于大多数 /proc 文件,stat.st_size 将为 0。我看到的唯一剩余解决方案是调整不适合的缓冲区大小。

      为此,我建议使用vector&lt;char&gt;,如下所示:

      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() 这样的东西?)
      【解决方案3】:

      Use the readlink() function properly 用于正确使用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);正确地检索它。
      • 我不明白你在说什么。请编辑您的问题以显示您所拥有的内容,以及您想要的示例。
      • 好的,我输入了更多细节,但我的原始答案在固定路径下效果很好......
      • 只是添加一些我一直在努力的细节:get_selfPath() 函数返回包含可执行文件名称的路径。要获取删除 exe 名称的路径,您可以执行以下操作:std::string::size_type t = path.find_last_of("/"),然后是 path = path.substr(0,t)。我不知道为什么这在任何地方都没有得到足够的澄清;)
      • @a.lasram:这根本不是错字。
      【解决方案4】:

      让我们看看the manpage是怎么说的:

       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;
       }
      

      【讨论】:

      • 不应该是... if (readlink("/proc/self/exe", buf, sizeof(buf)-1)
      • if (readlink(/*...*/)) 测试非零值。小于 0 是非零。
      • readlink 在成功时返回 >0。 “成功时,readlink() 返回放在 buf 中的字节数。出错时,返回 -1”。 linux.die.net/man/2/readlink.
      • 好的。届时将进行编辑。这对于系统调用来说有点不寻常。通常 0 表示成功。
      【解决方案5】:
      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

      【讨论】:

        猜你喜欢
        • 2014-12-08
        • 2011-11-30
        • 2013-03-23
        • 2020-06-22
        • 2014-12-09
        • 2012-03-24
        • 1970-01-01
        • 2011-03-08
        • 2012-11-26
        相关资源
        最近更新 更多