当从C中的符号链接调用时,如何使用getcwd获取可执行路径

时间:2012-08-12 06:13:42

标签: c linux file-io symlink

假设我在Linux中有一个程序abc,方法是:

char *currentPath(){
        char *path=NULL;
        path = getcwd(path, MAXPATHLEN);
        return path;
}

直接调用abc时,此路径会返回abc所在的路径。

如果我建立了abc的符号链接,并调用符号链接,currentPath()将返回符号链接的路径。

有没有办法让这个方法返回abc的路径?我有兴趣访问相对于abc的位置的文件。

3 个答案:

答案 0 :(得分:4)

您不能使用getcwd()来帮助获取可执行文件名称;找到可执行文件的路径名不是一种明智的方法。

在Linux上,有一个符号链接/proc/self/exe,如果您使用readlink()系统调用读取它,则会为您提供可执行文件的名称。请注意,readlink()系统调用不会终止它返回的值(我不知道为什么不会;这在我的书中是非常奇怪的行为,并且是导致不警惕的错误的原因)。

您的方案存在许多问题。

  1. 如果通过$ PATH找到程序,则无法保证当前目录与包含可执行文件的目录相同。如果您考虑一下,则无需进入/bin/ls目录即可运行/bin
  2. 如果您担心安全性,请注意argv[0]的值受启动目标程序的程序控制。外壳表现很好;其他程序可能更恶意:

    #include <unistd.h>
    int main(void)
    {
        char *argv[] = { "/opt/you/bin/bogus", "300", 0 };
        execvp("sleep", argv);
        return(-1);
    }
    

    这会将程序名称传递为/opt/you/bin/bogus,即使它调用程序sleep

  3. 如果您在网上搜索,您会发现大量“如何获取可执行文件名称”的例子,假设argv[0]是可行的方法;它不是。其他平台具有获取可执行文件名称的其他技术。使用/proc/self/exe不可移植;也没有其他技术。

答案 1 :(得分:2)

使用realpath(const char *path, char *resolved_path)

  

realpath()展开所有符号链接并解析对/./,/../和的引用          以路径命名的以null结尾的字符串中的额外“/”字符以生成a          规范化的绝对​​路径名。

在你的情况下:

char *currentPath() {
  char *path, *canon_path;
  path = getcwd(NULL, MAXPATHLEN);
  canon_path = realpath(path, NULL);
  free(path);
  return canon_path;
}

请注意,这不会获得可执行程序的路径(不清楚您要尝试做什么)。要做到这一点便携是棘手的。您需要使用argv[0]的值来获取它:

char *bindir(char *argv0) {
  char *canon_path = realpath(argv0, NULL);
  char *canon_dir = strdup(dirname(canon_path));
  free(canon_path);
  return canon_dir;
}

strdup调用是必需的,因为dirname可能会修改其参数并将指针返回到该参数或返回指向静态分配缓冲区的指针。

答案 2 :(得分:0)

尝试此代码(根据您的需要进行修改):

#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

#define MAXPATHLEN      256

char buffer[1024];

char *currentPath(char *bin_path){
        char *path = NULL;
        ssize_t len;
        struct stat file_stat;

        if (lstat(bin_path, &file_stat) != 0) 
        {
                /* handle error */
                fprintf(stderr, "ERROR\n");
        }

        if (!S_ISREG(file_stat.st_mode)) 
        {
                /* file is a symlink */
                fprintf(stdout, "Is a symlink\n");
                if ((len = readlink(bin_path, buffer, sizeof(buffer)-1)) != -1)
                        buffer[len] = '\0';
                /* In this case we return the name of the link */
                return buffer;
        }
        else
        {
                fprintf(stdout, "Is a regular file\n");
                path = getcwd(bin_path, MAXPATHLEN);

                return path;
        }
}

int main(int argc, char **argv)
{
        fprintf(stdout, "My path is : %s\n", currentPath(argv[0]));

        return 0;
}