about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2013-08-02 13:33:31 -0400
committerRich Felker <dalias@aerifal.cx>2013-08-02 13:33:31 -0400
commit9ca1f62b0c0d3e50480eb654ac941ff943ce0558 (patch)
tree3920a0d5db41c52b13b8a70efdb2c039aa4e4f9c
parentc8c0844f7fbcb955848ca84432e5ffcf71f1cef1 (diff)
downloadmusl-9ca1f62b0c0d3e50480eb654ac941ff943ce0558.tar.gz
musl-9ca1f62b0c0d3e50480eb654ac941ff943ce0558.tar.xz
musl-9ca1f62b0c0d3e50480eb654ac941ff943ce0558.zip
make fchdir, fchmod, fchown, and fstat support O_PATH file descriptors
on newer kernels, fchdir and fstat work anyway. this same fix should
be applied to any other syscalls that are similarly affected.

with this change, the current definitions of O_SEARCH and O_EXEC as
O_PATH are mostly conforming to POSIX requirements. the main remaining
issue is that O_NOFOLLOW has different semantics.
-rw-r--r--src/stat/fchmod.c10
-rw-r--r--src/stat/fstat.c12
-rw-r--r--src/unistd/fchdir.c10
-rw-r--r--src/unistd/fchown.c10
4 files changed, 37 insertions, 5 deletions
diff --git a/src/stat/fchmod.c b/src/stat/fchmod.c
index f9b99366..1b943d44 100644
--- a/src/stat/fchmod.c
+++ b/src/stat/fchmod.c
@@ -1,7 +1,15 @@
 #include <sys/stat.h>
+#include <errno.h>
 #include "syscall.h"
 
+void __procfdname(char *, unsigned);
+
 int fchmod(int fd, mode_t mode)
 {
-	return syscall(SYS_fchmod, fd, mode);
+	int ret = __syscall(SYS_fchmod, fd, mode);
+	if (ret != -EBADF || fd < 0) return __syscall_ret(ret);
+
+	char buf[15+3*sizeof(int)];
+	__procfdname(buf, fd);
+	return syscall(SYS_chmod, buf, mode);
 }
diff --git a/src/stat/fstat.c b/src/stat/fstat.c
index 10228f75..29b4243d 100644
--- a/src/stat/fstat.c
+++ b/src/stat/fstat.c
@@ -1,10 +1,18 @@
 #include <sys/stat.h>
+#include <errno.h>
 #include "syscall.h"
 #include "libc.h"
 
-int fstat(int fd, struct stat *buf)
+void __procfdname(char *, unsigned);
+
+int fstat(int fd, struct stat *st)
 {
-	return syscall(SYS_fstat, fd, buf);
+	int ret = __syscall(SYS_fstat, fd, st);
+	if (ret != -EBADF || fd < 0) return __syscall_ret(ret);
+
+	char buf[15+3*sizeof(int)];
+	__procfdname(buf, fd);
+	return syscall(SYS_stat, buf, st);
 }
 
 LFS64(fstat);
diff --git a/src/unistd/fchdir.c b/src/unistd/fchdir.c
index e5595f77..9fbc8154 100644
--- a/src/unistd/fchdir.c
+++ b/src/unistd/fchdir.c
@@ -1,7 +1,15 @@
 #include <unistd.h>
+#include <errno.h>
 #include "syscall.h"
 
+void __procfdname(char *, unsigned);
+
 int fchdir(int fd)
 {
-	return syscall(SYS_fchdir, fd);
+	int ret = __syscall(SYS_fchdir, fd);
+	if (ret != -EBADF || fd < 0) return __syscall_ret(ret);
+
+	char buf[15+3*sizeof(int)];
+	__procfdname(buf, fd);
+	return syscall(SYS_chdir, buf);
 }
diff --git a/src/unistd/fchown.c b/src/unistd/fchown.c
index b05f0be4..e1c3198a 100644
--- a/src/unistd/fchown.c
+++ b/src/unistd/fchown.c
@@ -1,7 +1,15 @@
 #include <unistd.h>
+#include <errno.h>
 #include "syscall.h"
 
+void __procfdname(char *, unsigned);
+
 int fchown(int fd, uid_t uid, gid_t gid)
 {
-	return syscall(SYS_fchown, fd, uid, gid);
+	int ret = __syscall(SYS_fchown, fd, uid, gid);
+	if (ret != -EBADF || fd < 0) return __syscall_ret(ret);
+
+	char buf[15+3*sizeof(int)];
+	__procfdname(buf, fd);
+	return syscall(SYS_chown, buf, uid, gid);
 }