READLINK(2)

ИМЯ
readlink, readlinkat - считывает значение символьной ссылки

ОБЗОР
#include <unistd.h>

ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
#include <fcntl.h>           /* определения констант of AT_* */
#include <unistd.h>

ssize_t readlinkat(int dirfd, const char *pathname,
                   char *buf, size_t bufsiz);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

readlink():
    _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
        || /* в версиях glibc <= 2.19: */ _BSD_SOURCE

readlinkat():
    Начиная с glibc 2.10:
        _POSIX_C_SOURCE >= 200809L
    До glibc 2.10:
        _ATFILE_SOURCE

ОПИСАНИЕ
Вызов readlink() помещает содержимое символьной ссылки pathname в буфер buf размером bufsiz. readlink() не добавляет в buf байт null. Если буфер слишком мал для хранения всего содержимого, то содержимое будет урезано (без выдачи ошибки, до длины в bufsiz символов).

  readlinkat()
Системный вызов readlinkat() работает также как системный вызов readlink(), за исключением случаев, описанных здесь.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в readlink()).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как readlink()).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Начиная с Linux .6.39, pathname может быть пустой строкой; при этом вызов выполняет действие с символьной ссылкой, на которую ссылается dirfd (должна получаться с помощью вызова open(2) с флагами O_PATH и O_NOFOLLOW).

Смотрите в openat(2) объяснение необходимости readlinkat().

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении эти вызовы возвращают количество байт, помещённых в buf (если возвращаемое значение равно bufsiz, то возможно произошло обрезание). В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

EACCES
    В одном из каталогов префикса пути не разрешён поиск (см. также path_resolution(7).

EFAULT
    buf выходит за пределы адресного пространства, выделенного процессу.

EINVAL
    Аргумент bufsiz содержит отрицательное значение.

EINVAL
    Указанный файл (т. е., последний компонент имени файла pathname) не является символьной ссылкой.

EIO При чтении файловой системы произошла ошибка ввода-вывода.

ELOOP
    Во время определения pathname встретилось слишком много символьных ссылок.

ENAMETOOLONG
    Слишком длинное значение аргумента pathname или его части.

ENOENT
    Указанный файл не существует.

ENOMEM
    Недостаточное количество памяти ядра.

ENOTDIR
    Компонент в префиксе пути не является каталогом.

В readlinkat() дополнительно могут возникнуть следующие ошибки:

EBADF
    dirfd не является правильным файловым дескриптором.

ENOTDIR
    Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

ВЕРСИИ
Системный вызов readlinkat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

СООТВЕТСТВИЕ СТАНДАРТАМ
readlink(): 4.4BSD (readlink() появился в 4.2BSD), POSIX.1-2001, POSIX.1-2008.

readlinkat(): POSIX.1-2008.

ЗАМЕЧАНИЯ
В версиях glibc до glibc 2.4 включительно, тип результата readlink() был объявлен как int. В настоящее время типом возвращаемого результата является ssize_t, как (теперь) это требуется по POSIX.1-2001.

Буфера с фиксированным размером может не хватить для хранения содержимого символьной ссылки. Требуемый размер буфера можно получить как значение stat.st_size, возвращаемое на ссылку вызовом lstat(2). Однако, количество байт, записанное readlink() и readlinkat(), должно быть проверено, так как требуется убедиться, что размер символьной ссылки не увеличился между вызовами. Динамическое выделение буфера для readlink() и readlinkat() также поможет решить проблему с переносимостью, которая возникает, когда для размера буфера используется PATH_MAX, но согласно POSIX для этой константы не гарантируется, что она определена , если система не имеет такого ограничения.

  Замечания по glibc
В старых ядрах, где readlinkat() отсутствует, обёрточная функция glibc использует readlink(). Если pathname является относительным путём, то glibc собирает путь относительно символической ссылки в /proc/self/fd, которая соответствует аргументу dirfd.

ПРИМЕР
Следующая программа динамически выделяет буфер, необходимый readlink(), из информации, предоставленной lstat(2), или использует буфер размером PATH_MAX, если lstat(2) вернул нулевой размер.

    #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, "Использование: %s <путь>\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        if (lstat(argv[1], &sb) == -1) {
            perror("lstat");
            exit(EXIT_FAILURE);
        }
        /* Добавляем единицу к размеру ссылки, так чтобы можно было определить
           обрезанность буфера, возвращаемого readlink(). */
        bufsiz = sb.st_size + 1;
        /* У некоторых символьных ссылок в (например) /proc и /sys
           значение 'st_size' равно нулю. В этом случае используется
           PATH_MAX как «достаточный» размер. */
        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' указывает на '%.*s'\n", argv[1], (int) nbytes, buf);
        /* Если возвращаемое значение равно размеру буфера, то
           ссылка назначения больше чем ожидалось (возможно, из-за того,
           что цель изменилась между вызовом lstat() и readlink()).
           Предупреждаем пользователя о том, что цель может быть
           обрезана. */
        if (nbytes == bufsiz)
            printf("(Возвращённый буфер мог быть обрезан)\n");
        free(buf);
        exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
readlink(1), lstat(2), stat(2), symlink(2), realpath(3), path_resolution(7), symlink(7)