summaryrefslogtreecommitdiffstats
path: root/man2/readlink.2
diff options
context:
space:
mode:
Diffstat (limited to 'man2/readlink.2')
-rw-r--r--man2/readlink.2331
1 files changed, 331 insertions, 0 deletions
diff --git a/man2/readlink.2 b/man2/readlink.2
new file mode 100644
index 0000000..fe2369d
--- /dev/null
+++ b/man2/readlink.2
@@ -0,0 +1,331 @@
+.\" Copyright (c) 1983, 1991 The Regents of the University of California.
+.\" And Copyright (C) 2011 Guillem Jover <guillem@hadrons.org>
+.\" And Copyright (C) 2006, 2014 Michael Kerrisk
+.\" All rights reserved.
+.\"
+.\" SPDX-License-Identifier: BSD-4-Clause-UC
+.\"
+.\" @(#)readlink.2 6.8 (Berkeley) 3/10/91
+.\"
+.\" Modified Sat Jul 24 00:10:21 1993 by Rik Faith (faith@cs.unc.edu)
+.\" Modified Tue Jul 9 23:55:17 1996 by aeb
+.\" Modified Fri Jan 24 00:26:00 1997 by aeb
+.\" 2011-09-20, Guillem Jover <guillem@hadrons.org>:
+.\" Added text on dynamically allocating buffer + example program
+.\"
+.TH readlink 2 2023-05-03 "Linux man-pages 6.05.01"
+.SH NAME
+readlink, readlinkat \- read value of a symbolic link
+.SH LIBRARY
+Standard C library
+.RI ( libc ", " \-lc )
+.SH SYNOPSIS
+.nf
+.B #include <unistd.h>
+.PP
+.BI "ssize_t readlink(const char *restrict " pathname ", char *restrict " buf ,
+.BI " size_t " bufsiz );
+.PP
+.BR "#include <fcntl.h> " "/* Definition of " AT_* " constants */"
+.B #include <unistd.h>
+.PP
+.BI "ssize_t readlinkat(int " dirfd ", const char *restrict " pathname ,
+.BI " char *restrict " buf ", size_t " bufsiz );
+.PP
+.fi
+.RS -4
+Feature Test Macro Requirements for glibc (see
+.BR feature_test_macros (7)):
+.RE
+.PP
+.BR readlink ():
+.nf
+ _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
+.\" || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
+ || /* glibc <= 2.19: */ _BSD_SOURCE
+.fi
+.PP
+.BR readlinkat ():
+.nf
+ Since glibc 2.10:
+ _POSIX_C_SOURCE >= 200809L
+ Before glibc 2.10:
+ _ATFILE_SOURCE
+.fi
+.SH DESCRIPTION
+.BR readlink ()
+places the contents of the symbolic link
+.I pathname
+in the buffer
+.IR buf ,
+which has size
+.IR bufsiz .
+.BR readlink ()
+does not append a terminating null byte to
+.IR buf .
+It will (silently) truncate the contents (to a length of
+.I bufsiz
+characters), in case the buffer is too small to hold all of the contents.
+.SS readlinkat()
+The
+.BR readlinkat ()
+system call operates in exactly the same way as
+.BR readlink (),
+except for the differences described here.
+.PP
+If the pathname given in
+.I pathname
+is relative, then it is interpreted relative to the directory
+referred to by the file descriptor
+.I dirfd
+(rather than relative to the current working directory of
+the calling process, as is done by
+.BR readlink ()
+for a relative pathname).
+.PP
+If
+.I pathname
+is relative and
+.I dirfd
+is the special value
+.BR AT_FDCWD ,
+then
+.I pathname
+is interpreted relative to the current working
+directory of the calling process (like
+.BR readlink ()).
+.PP
+If
+.I pathname
+is absolute, then
+.I dirfd
+is ignored.
+.PP
+Since Linux 2.6.39,
+.\" commit 65cfc6722361570bfe255698d9cd4dccaf47570d
+.I pathname
+can be an empty string,
+in which case the call operates on the symbolic link referred to by
+.I dirfd
+(which should have been obtained using
+.BR open (2)
+with the
+.B O_PATH
+and
+.B O_NOFOLLOW
+flags).
+.PP
+See
+.BR openat (2)
+for an explanation of the need for
+.BR readlinkat ().
+.SH RETURN VALUE
+On success, these calls return the number of bytes placed in
+.IR buf .
+(If the returned value equals
+.IR bufsiz ,
+then truncation may have occurred.)
+On error, \-1 is returned and
+.I errno
+is set to indicate the error.
+.SH ERRORS
+.TP
+.B EACCES
+Search permission is denied for a component of the path prefix.
+(See also
+.BR path_resolution (7).)
+.TP
+.B EBADF
+.RB ( readlinkat ())
+.I pathname
+is relative but
+.I dirfd
+is neither
+.B AT_FDCWD
+nor a valid file descriptor.
+.TP
+.B EFAULT
+.I buf
+extends outside the process's allocated address space.
+.TP
+.B EINVAL
+.I bufsiz
+is not positive.
+.\" At the glibc level, bufsiz is unsigned, so this error can only occur
+.\" if bufsiz==0. However, the in the kernel syscall, bufsiz is signed,
+.\" and this error can also occur if bufsiz < 0.
+.\" See: http://thread.gmane.org/gmane.linux.man/380
+.\" Subject: [patch 0/3] [RFC] kernel/glibc mismatch of "readlink" syscall?
+.TP
+.B EINVAL
+The named file (i.e., the final filename component of
+.IR pathname )
+is not a symbolic link.
+.TP
+.B EIO
+An I/O error occurred while reading from the filesystem.
+.TP
+.B ELOOP
+Too many symbolic links were encountered in translating the pathname.
+.TP
+.B ENAMETOOLONG
+A pathname, or a component of a pathname, was too long.
+.TP
+.B ENOENT
+The named file does not exist.
+.TP
+.B ENOMEM
+Insufficient kernel memory was available.
+.TP
+.B ENOTDIR
+A component of the path prefix is not a directory.
+.TP
+.B ENOTDIR
+.RB ( readlinkat ())
+.I pathname
+is relative and
+.I dirfd
+is a file descriptor referring to a file other than a directory.
+.SH STANDARDS
+POSIX.1-2008.
+.SH HISTORY
+.TP
+.BR readlink ()
+4.4BSD
+(first appeared in 4.2BSD),
+POSIX.1-2001, POSIX.1-2008.
+.TP
+.BR readlinkat ()
+POSIX.1-2008.
+Linux 2.6.16,
+glibc 2.4.
+.PP
+Up to and including glibc 2.4, the return type of
+.BR readlink ()
+was declared as
+.IR int .
+Nowadays, the return type is declared as
+.IR ssize_t ,
+as (newly) required in POSIX.1-2001.
+.SS glibc
+On older kernels where
+.BR readlinkat ()
+is unavailable, the glibc wrapper function falls back to the use of
+.BR readlink ().
+When
+.I pathname
+is a relative pathname,
+glibc constructs a pathname based on the symbolic link in
+.I /proc/self/fd
+that corresponds to the
+.I dirfd
+argument.
+.SH NOTES
+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 the
+.I stat.st_size
+value returned by a call to
+.BR lstat (2)
+on the link.
+However, the number of bytes written by
+.BR readlink ()
+and
+.BR readlinkat ()
+should be checked to make sure that the size of the
+symbolic link did not increase between the calls.
+Dynamically allocating the buffer for
+.BR readlink ()
+and
+.BR readlinkat ()
+also addresses a common portability problem when using
+.B PATH_MAX
+for the buffer size,
+as this constant is not guaranteed to be defined per POSIX
+if the system does not have such limit.
+.SH EXAMPLES
+The following program allocates the buffer needed by
+.BR readlink ()
+dynamically from the information provided by
+.BR lstat (2),
+falling back to a buffer of size
+.B PATH_MAX
+in cases where
+.BR lstat (2)
+reports a size of zero.
+.PP
+.\" SRC BEGIN (readlink.c)
+.EX
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.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 <pathname>\en", 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 \[aq]st_size\[aq] 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 \[aq]nbytes\[aq] of \[aq]buf\[aq], as it doesn't contain a terminating
+ null byte (\[aq]\e0\[aq]). */
+ printf("\[aq]%s\[aq] points to \[aq]%.*s\[aq]\en", 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)\en");
+\&
+ free(buf);
+ exit(EXIT_SUCCESS);
+}
+.EE
+.\" SRC END
+.SH SEE ALSO
+.BR readlink (1),
+.BR lstat (2),
+.BR stat (2),
+.BR symlink (2),
+.BR realpath (3),
+.BR path_resolution (7),
+.BR symlink (7)