NAME |LIBRARY |SYNOPSIS |DESCRIPTION |RETURN VALUE |ERRORS |STANDARDS |HISTORY |NOTES |EXAMPLES |SEE ALSO |COLOPHON | |
readlink(2) System Calls Manualreadlink(2)readlink, readlinkat - read value of a symbolic link
Standard C library (libc,-lc)
#include <unistd.h>ssize_t readlink(size_t bufsiz;const char *restrictpath,charbuf[restrictbufsiz], size_tbufsiz);#include <fcntl.h>/* Definition ofAT_*constants */#include <unistd.h>ssize_t readlinkat(size_t bufsiz;intdirfd, const char *restrictpath,charbuf[restrictbufsiz], size_tbufsiz); Feature Test Macro Requirements for glibc (seefeature_test_macros(7)):readlink(): _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L || /* glibc <= 2.19: */ _BSD_SOURCEreadlinkat(): Since glibc 2.10: _POSIX_C_SOURCE >= 200809L Before glibc 2.10: _ATFILE_SOURCE
readlink() places the contents of the symbolic linkpath in the bufferbuf, which has sizebufsiz.readlink() does not append a terminating null byte tobuf. It will (silently) truncate the contents (to a length ofbufsiz characters), in case the buffer is too small to hold all of the contents.readlinkat() Thereadlinkat() system call operates in exactly the same way asreadlink(), except for the differences described here. Ifpath is relative, then it is interpreted relative to the directory referred to by the file descriptordirfd (rather than relative to the current working directory of the calling process, as is done byreadlink() for a relative pathname). Ifpath is relative anddirfd is the special valueAT_FDCWD, thenpath is interpreted relative to the current working directory of the calling process (likereadlink()). Ifpath is absolute, thendirfd is ignored. Since Linux 2.6.39,path can be an empty string, in which case the call operates on the symbolic link referred to bydirfd (which should have been obtained usingopen(2) with theO_PATHandO_NOFOLLOWflags). Seeopenat(2) for an explanation of the need forreadlinkat().
On success, these calls return the number of bytes placed inbuf. (If the returned value equalsbufsiz, then truncation may have occurred.) On error, -1 is returned anderrno is set to indicate the error.
EACCESSearch permission is denied for a component of the path prefix. (See alsopath_resolution(7).)EBADF(readlinkat())path is relative butdirfd is neitherAT_FDCWDnor a valid file descriptor.EFAULTbuf extends outside the process's allocated address space.EINVALbufsiz is not positive.EINVALThe named file (i.e., the final filename component ofpath) is not a symbolic link.EIOAn I/O error occurred while reading from the filesystem.ELOOPToo many symbolic links were encountered in translating the pathname.ENAMETOOLONG A pathname, or a component of a pathname, was too long.ENOENTThe named file does not exist.ENOMEMInsufficient kernel memory was available.ENOTDIR A component of the path prefix is not a directory.ENOTDIR (readlinkat())path is relative anddirfd is a file descriptor referring to a file other than a directory.
POSIX.1-2008.
readlink() 4.4BSD (first appeared in 4.2BSD), POSIX.1-2001, POSIX.1-2008.readlinkat() POSIX.1-2008. Linux 2.6.16, glibc 2.4. Up to and including glibc 2.4, the return type ofreadlink() was declared asint. Nowadays, the return type is declared asssize_t, as (newly) required in POSIX.1-2001.glibc On older kernels wherereadlinkat() is unavailable, the glibc wrapper function falls back to the use ofreadlink(). Whenpath is relative, glibc constructs a pathname based on the symbolic link in/proc/self/fd that corresponds to thedirfd argument.
Using a statically sized buffer might not provide enough room for the symbolic link contents. The required size for the buffer can be obtained from thestat.st_size value returned by a call tolstat(2) on the link. However, the number of bytes written byreadlink() andreadlinkat() should be checked to make sure that the size of the symbolic link did not increase between the calls. Dynamically allocating the buffer forreadlink() andreadlinkat() also addresses a common portability problem when usingPATH_MAX for the buffer size, as this constant is not guaranteed to be defined per POSIX if the system does not have such limit.
The following program allocates the buffer needed byreadlink() dynamically from the information provided bylstat(2), falling back to a buffer of sizePATH_MAXin cases wherelstat(2) reports a size of zero. #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char *argv[]) { char *buf; ssize_t nbytes, bufsiz; struct stat sb; if (argc != 2) { fprintf(stderr, "Usage: %s <path>\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)
This page is part of theman-pages (Linux kernel and C library user-space interface documentation) project. Information about the project can be found at ⟨https://www.kernel.org/doc/man-pages/⟩. If you have a bug report for this manual page, see ⟨https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/CONTRIBUTING⟩. This page was obtained from the tarball man-pages-6.15.tar.gz fetched from ⟨https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/⟩ on 2025-08-11. If you discover any rendering problems in this HTML version of the page, or you believe there is a better or more up- to-date source for the page, or you have corrections or improvements to the information in this COLOPHON (which isnot part of the original manual page), send a mail to man-pages@man7.orgLinux man-pages 6.15 2025-06-28readlink(2)Pages that refer to this page:readlink(1), realpath(1), mount(2), open(2), open_by_handle_at(2), ptrace(2), read(2), stat(2), statx(2), symlink(2), syscalls(2), canonicalize_file_name(3), handle(3), realpath(3), size_t(3type), proc(5), proc_pid_cwd(5), proc_pid_exe(5), proc_pid_fd(5), proc_pid_root(5), namespaces(7), path_resolution(7), pid_namespaces(7), signal-safety(7), symlink(7), lsof(8), mount(8), umount(8)
HTML rendering created 2025-09-06 byMichael Kerrisk, author ofThe Linux Programming Interface. For details of in-depthLinux/UNIX system programming training courses that I teach, lookhere. Hosting byjambit GmbH. | ![]() |