readlink既是一个linux下的命令,又是Linux系统编程中的一个函数,因此本文分两部分介绍readlink.

readlink命令

readlink是linux系统中一个常用工具,主要用来找出符号链接所指向的位置。

在Ubuntu系统中执行以下命令:

$ readlink --help
可以查看readlink命令的帮助信息,或者执行

$ man readlink
查看帮助手册。

从帮助信息中可以得到readlink命令的用途描述:

输出符号链接值或者权威文件名

英文为:

print value of a symbolic link or canonical file name

举例:

系统中的awk命令到底是执行哪个可以执行文件呢?

$ readlink /usr/bin/awk
/etc/alternatives/awk ----> 其实这个还是一个符号连接
$ readlink /etc/alternatives/awk
/usr/bin/gawk ----> 这个才是真正的可执行文件
-f 选项:

-f 选项可以递归跟随给出文件名的所有符号链接以标准化,除最后一个外所有组件必须存在。

简单地说,就是一直跟随符号链接,直到直到非符号链接的文件位置,限制是最后必须存在一个非符号链接的文件。

$ readlink -f /usr/bin/awk
/usr/bin/gawk

readlink函数

readlink函数,在linux c系统编程中用于读取符号链接,man7.org中的一个例子如下:

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

       int
       main(int argc, char *argv[])
       {
           struct stat sb;
           char *buf;
           ssize_t nbytes, bufsiz;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           if (lstat(argv[1], &sb) == -1) {
               perror("lstat");
               exit(EXIT_FAILURE);
           }

           /* Add one to the link size, so that we can determine whether
              the buffer returned by readlink() was truncated. */

           bufsiz = sb.st_size + 1;

           /* Some magic symlinks under (for example) /proc and /sys
              report 'st_size' as zero. In that case, take PATH_MAX as
              a "good enough" estimate. */

           if (sb.st_size == 0)
               bufsiz = PATH_MAX;

           buf = malloc(bufsiz);
           if (buf == NULL) {
               perror("malloc");
               exit(EXIT_FAILURE);
           }

           nbytes = readlink(argv[1], buf, bufsiz);
           if (nbytes == -1) {
               perror("readlink");
               exit(EXIT_FAILURE);
           }

           printf("'%s' points to '%.*s'\n", argv[1], (int) nbytes, buf);

           /* If the return value was equal to the buffer size, then the
              the link target was larger than expected (perhaps because the
              target was changed between the call to lstat() and the call to
              readlink()). Warn the user that the returned target may have
              been truncated. */

           if (nbytes == bufsiz)
               printf("(Returned buffer may have been truncated)\n");

           free(buf);
           exit(EXIT_SUCCESS);
       }

一种根据可执行文件的路径,拼接相对路径的方法

#include <stdio.h>
#include <limits.h>                          /*PATH_MAX*/
#include <string.h>
#include <assert.h>

char g_execpath[PATH_MAX];                  /* 可执行文件的所有目录 */

static void get_exec_path()
{
    int r;
    if ((r = readlink("/proc/self/exe", g_execpath, sizeof(g_execpath) - 1)) != -1) 
    {
        char *p;
        
        assert((size_t)r < sizeof(g_execpath));
        g_execpath[r] = 0;
        if ((p = strrchr(g_execpath, '/'))) 
        {
            *p = 0;
        } 
        else 
        {
            g_execpath[0] = '/';
            g_execpath[1] = 0;
        }
    } 
    else 
    {
        g_execpath[0] = '/';
        g_execpath[1] = 0;
    }

}

/* 路径转换 */
void relative_path_transform(const char *dir, char *out, size_t outsize)
{
    assert(dir && out && outsize);
    
    if (!g_execpath[0]) 
    {
        get_exec_path();
    }
    
    if (*dir == '@') 
    {
        snprintf(out, outsize, "%s%s", g_execpath, dir + 1);
    } 
    else 
    {
        snprintf(out, outsize, "%s", dir);
    }
}

#define APP_PROCESS_PATH    "@/app"
#define ABS_PROCESS_PATH    "/root/app"

int main()
{
    /*相对路径使用readlink获取程序路径地址*/
    char proxy_path[PATH_MAX] = { 0 };
    (void)relative_path_transform(APP_PROCESS_PATH, proxy_path, PATH_MAX);
    printf("%s\n",proxy_path);

    /*绝对路径直接打印路径信息*/
    char abs_proxy_path[PATH_MAX] = { 0 };
    (void)relative_path_transform(ABS_PROCESS_PATH, abs_proxy_path, PATH_MAX);
    printf("%s\n",abs_proxy_path);

    return 0;
}