readlink(2) System Calls Manual readlink(2) readlink, readlinkat - (libc -lc) #include ssize_t readlink(size_t bufsiz; const char *restrict path, char buf[restrict bufsiz], size_t bufsiz); #include /* AT_* */ #include ssize_t readlinkat(size_t bufsiz; int dirfd, const char *restrict path, char buf[restrict bufsiz], 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() path buf bufsiz. readlink() buf. () ( bufsiz ) . readlinkat() readlinkat() readlink() . path dirfd ( readlink() ). path dirfd AT_FDCWD path ( readlink()). path dirfd. Linux 2.6.39 path dirfd ( open(2) O_PATH O_NOFOLLOW). openat(2) readlinkat(). buf. ( bufsiz .) -1 errno . EACCES . ( path_resolution(7).) EBADF (readlinkat()) path dirfd AT_FDCWD . EFAULT buf . EINVAL bufsiz . EINVAL ( path) . EIO / . ELOOP . ENAMETOOLONG . ENOENT . ENOMEM . ENOTDIR . ENOTDIR (readlinkat()) path dirfd . POSIX.1-2024. readlink() 4.4BSD ( 4.2BSD) POSIX.1-2001 POSIX.1-2008. readlinkat() POSIX.1-2008. 2.6.16 glibc 2.4. glibc 2.4 readlink() int. ssize_t () POSIX.1-2001. glibc readlinkat() glibc readlink(). path glibc /proc/self/fd dirfd. . stat.st_size lstat(2) . readlink() readlinkat() . readlink() readlinkat() PATH_MAX POSIX . readlink() lstat(2) PATH_MAX lstat(2) . #include #include #include #include #include #include int main(int argc, char *argv[]) { char *buf; ssize_t nbytes, bufsiz; struct stat sb; if (argc != 2) { fprintf(stderr, "Usage: %s \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); } /* Print only 'nbytes' of 'buf', as it doesn't contain a terminating null byte ('\0'). */ printf("'%s' points to '%.*s'\n", argv[1], (int) nbytes, buf); /* If the return value was equal to the buffer size, then 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); } readlink(1), lstat(2), stat(2), symlink(2), realpath(3), path_resolution(7), symlink(7) 3 . . : . 6.18 8 2026 readlink(2)