aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2016-01-06 01:08:47 +0000
committerH. Peter Anvin <hpa@linux.intel.com>2016-01-05 17:48:43 -0800
commit32b36eb98fafad924f3f69904d74d2f2168a4753 (patch)
tree2a7acf96c589792dc534db8efd0646e9c052182e
parentce358438679db7488f36706feaf64d6d5ab84ad6 (diff)
downloadklibc-32b36eb98fafad924f3f69904d74d2f2168a4753.tar.gz
[klibc] Implement realpath()
This is needed as the basis for the readlink -f option. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--usr/include/stdlib.h2
-rw-r--r--usr/klibc/Kbuild2
-rw-r--r--usr/klibc/realpath.c49
3 files changed, 52 insertions, 1 deletions
diff --git a/usr/include/stdlib.h b/usr/include/stdlib.h
index 406f44600f28dd..856c64721976e0 100644
--- a/usr/include/stdlib.h
+++ b/usr/include/stdlib.h
@@ -92,4 +92,6 @@ static __inline__ int grantpt(int __fd)
return 0; /* devpts does this all for us! */
}
+__extern char *realpath(const char *, char *);
+
#endif /* _STDLIB_H */
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index d3e2b9fbc99b15..7d95e8755286c1 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -61,7 +61,7 @@ klib-y += vsnprintf.o snprintf.o vsprintf.o sprintf.o \
send.o recv.o \
access.o chmod.o chown.o dup2.o mknod.o poll.o rename.o stat.o \
lchown.o link.o rmdir.o unlink.o utimes.o lstat.o mkdir.o \
- readlink.o select.o symlink.o pipe.o \
+ readlink.o realpath.o select.o symlink.o pipe.o \
ctype/isalnum.o ctype/isalpha.o ctype/isascii.o \
ctype/isblank.o ctype/iscntrl.o ctype/isdigit.o \
ctype/isgraph.o ctype/islower.o ctype/isprint.o \
diff --git a/usr/klibc/realpath.c b/usr/klibc/realpath.c
new file mode 100644
index 00000000000000..1474b1e501c159
--- /dev/null
+++ b/usr/klibc/realpath.c
@@ -0,0 +1,49 @@
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * Note that this requires name to refer to an existing file. This is
+ * correct according to POSIX. However, BSD and GNU implementations
+ * also allow name to refer to a non-existing file in an existing
+ * directory.
+ */
+
+char *realpath(const char *name, char *resolved_name)
+{
+ static const char proc_fd_prefix[] = "/proc/self/fd/";
+ char proc_fd_name[sizeof(proc_fd_prefix) + sizeof(int) * 3];
+ int allocated = 0;
+ int fd;
+ ssize_t len;
+
+ /* Open for path lookup only */
+ fd = open(name, O_PATH);
+ if (fd < 0)
+ return NULL;
+
+ if (!resolved_name) {
+ resolved_name = malloc(PATH_MAX);
+ if (!resolved_name)
+ goto out_close;
+ allocated = 1;
+ }
+
+ /* Use procfs to read back the resolved name */
+ sprintf(proc_fd_name, "%s%d", proc_fd_prefix, fd);
+ len = readlink(proc_fd_name, resolved_name, PATH_MAX - 1);
+ if (len < 0) {
+ if (allocated)
+ free(resolved_name);
+ resolved_name = NULL;
+ } else {
+ resolved_name[len] = 0;
+ }
+
+out_close:
+ close(fd);
+ return resolved_name;
+}