net: rock: Mirror F_SETFL flags to all FDs (XCC)
When the application attempts a fcntl + F_SETFL on a Rock FD (which is a
data FD), we'll mirror those commands to the other FDs (ctl and listen).
The motivator for this is dropbear, which sets a socket O_NONBLOCK and then
polls with connect(). It expects the O_NONBLOCK set on the socket FD to
apply to the entire socket. Recall that all of the files that make up a
Rock collectively are a socket.
Back before commit 765fc2a8270a ("Remove the O_NONBLOCK fcntl() intercept
(XCC)"), we handled O_NONBLOCK in userspace. This commit is somewhat
similar in that we need to do special Rock processing, but we still just do
fcntls.
Rebuild glibc.
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fcntl.c b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fcntl.c
index 74267b3..56e108b 100644
--- a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fcntl.c
+++ b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fcntl.c
@@ -8,6 +8,14 @@
#include <stdlib.h>
#include <ros/syscall.h>
+/* This is overridden when we're building with sockets. We need to go through
+ * these hoops since fnctl is a lower-level glibc function and is included in
+ * code that can't use sockets/rocks/stdio. */
+static void __weak_sock_mirror_fcntl(int sock_fd, int cmd, long arg)
+{
+}
+weak_alias(__weak_sock_mirror_fcntl, _sock_mirror_fcntl);
+
int __vfcntl(int fd, int cmd, va_list vl)
{
int ret, arg, advise;
@@ -20,9 +28,16 @@
case F_DUPFD:
case F_SETFD:
case F_GETFL:
+ arg = va_arg(vl, int);
+ ret = ros_syscall(SYS_fcntl, fd, cmd, arg, 0, 0, 0);
+ break;
case F_SETFL:
arg = va_arg(vl, int);
ret = ros_syscall(SYS_fcntl, fd, cmd, arg, 0, 0, 0);
+ /* For SETFL, we mirror the operation on all of the Rocks FDs. If
+ * the others fail, we won't hear about it. Similarly, we only
+ * GETFL for the data FD. */
+ _sock_mirror_fcntl(fd, cmd, arg);
break;
case F_ADVISE:
offset = va_arg(vl, __off64_t);
@@ -38,7 +53,7 @@
}
/* We used to override fcntl() with some Rock processing from within Glibc. It
- * might be useful to overrider fcntl() in the future. */
+ * might be useful to override fcntl() in the future. */
int __fcntl(int fd, int cmd, ...)
{
int ret;
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.c b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.c
index 412618f..9f2ea48 100644
--- a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.c
+++ b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/plan9_sockets.c
@@ -366,6 +366,19 @@
return _rock_open_listen_fd(r);
}
+/* Used by fcntl for F_SETFL. */
+void _sock_mirror_fcntl(int sock_fd, int cmd, long arg)
+{
+ Rock *r = _sock_findrock(sock_fd, 0);
+
+ if (!r || r->domain == PF_UNIX)
+ return;
+ if (r->ctl_fd >= 0)
+ syscall(SYS_fcntl, r->ctl_fd, cmd, arg);
+ if (r->has_listen_fd)
+ syscall(SYS_fcntl, r->listen_fd, cmd, arg);
+}
+
/* Given an FD, opens the FD with the name 'sibling' in the same directory.
* e.g., you have a data, you open a ctl. Don't use this with cloned FDs (i.e.
* open clone, get a ctl back) until we fix 9p and fd2path.
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/plan9_helpers.h b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/plan9_helpers.h
index fa18861..74d2f70 100644
--- a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/plan9_helpers.h
+++ b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/plan9_helpers.h
@@ -76,6 +76,7 @@
extern int _sock_strip_opts(int type);
extern int _sock_get_opts(int type);
extern int _sock_lookup_listen_fd(int sock_fd, bool can_open);
+extern void _sock_mirror_fcntl(int sock_fd, int cmd, long arg);
int get_sibling_fd(int fd, const char *sibling);
int write_hex_to_fd(int fd, uint64_t num);