0

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

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

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

如果我对 进行符号链接abc并调用符号链接,currentPath()则返回符号链接的路径。

有没有办法让这个方法返回路径abc?我有兴趣访问相对于abc.

4

3 回答 3

4

你不能getcwd()用来帮助获取可执行文件名;查找可执行文件的路径名不是明智的方法。

/proc/self/exe在 Linux 上,如果您使用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

如果您在网上搜索,您会发现很多“如何获取可执行文件名称”的示例,这些示例假定这argv[0]是要走的路;它不是。其他平台有其他技术来获取可执行文件名称。使用/proc/self/exe不便携;其他技术也不是。

于 2012-08-12T06:44:48.190 回答
2

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

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

在你的情况下:

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可能会修改其参数并返回指向该参数的指针或返回指向静态分配缓冲区的指针。

于 2012-08-12T06:45:56.690 回答
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;
}
于 2012-08-12T07:13:16.420 回答