#include <unistd.h> ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); #include <fcntl.h> /* AT_* 定数の定義 */ #include <unistd.h> ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照):
readlink():
readlinkat():
pathname で指定されたパス名が相対パスの場合、このパス名はファイルディスクリプター dirfd が参照するディレクトリに対する相対パスと解釈される (readlink() に相対パス名を渡した場合のように、呼び出したプロセスのカレントワーキングディレクトリに対する相対パスではない)。
pathname で指定されたパス名が相対パスで、 dirfd が特別な値 AT_FDCWD の場合、 (readlink() と同様に) pathname は呼び出したプロセスのカレントワーキングディレクトリに対する相対パスと解釈される。
pathname で指定されたパス名が絶対パスの場合、 dirfd は無視される。
Linux 2.6.39 以降では、 pathname に空文字列を指定できる。 その場合、呼び出しは dirfd が参照するシンボリックリンクに対して行われる (dirfd はフラグ O_PATH と O_NOFOLLOW を指定した open(2) を使って取得すべきである)。
readlinkat() の必要性についての説明については openat(2) を参照。
readlinkat() では以下のエラーも発生する。
静的な大きさのバッファーを使うと、 シンボリックリンクの内容を格納するのに十分な領域がない場合がある。 バッファーに必要なサイズは、 そのシンボリックリンクに対して lstat(2) の呼び出しで返される stat.st_size の値から取得できる。 ただし、 readlink() や readlinkat() が書き込んだバイト数をチェックして、 シンボリックリンクのサイズが二つの呼び出しの間で増えていないことを確認すべきである。 readlink() や readlinkat() 用のバッファーを動的に割り当てる方法でも、 バッファーサイズとして PATH_MAX を使用する場合に共通する移植性の問題を解決することができる。 なぜなら、POSIX では、 システムがそのような上限値を定義していない場合には、 PATH_MAX が定義されることが保証されていないからである。
#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);
}