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);