aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux/recvmsg.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/recvmsg.c')
-rw-r--r--sysdeps/unix/sysv/linux/recvmsg.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/sysdeps/unix/sysv/linux/recvmsg.c b/sysdeps/unix/sysv/linux/recvmsg.c
index 4caf22e8bf..25a319358b 100644
--- a/sysdeps/unix/sysv/linux/recvmsg.c
+++ b/sysdeps/unix/sysv/linux/recvmsg.c
@@ -15,23 +15,43 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <errno.h>
-#include <signal.h>
#include <sys/socket.h>
-
#include <sysdep-cancel.h>
#include <socketcall.h>
-#include <kernel-features.h>
-#include <sys/syscall.h>
+#include <shlib-compat.h>
ssize_t
__libc_recvmsg (int fd, struct msghdr *msg, int flags)
{
+ ssize_t ret;
+
+ /* POSIX specifies that both msghdr::msg_iovlen and msghdr::msg_controllen
+ to be int and socklen_t respectively. However Linux defines it as
+ both size_t. So for 64-bit it requires some adjustments by copying to
+ temporary header and zeroing the pad fields. */
+#if __WORDSIZE == 64
+ struct msghdr hdr, *orig = msg;
+ if (msg != NULL)
+ {
+ hdr = *msg;
+ hdr.__glibc_reserved1 = 0;
+ hdr.__glibc_reserved2 = 0;
+ msg = &hdr;
+ }
+#endif
+
#ifdef __ASSUME_RECVMSG_SYSCALL
- return SYSCALL_CANCEL (recvmsg, fd, msg, flags);
+ ret = SYSCALL_CANCEL (recvmsg, fd, msg, flags);
#else
- return SOCKETCALL_CANCEL (recvmsg, fd, msg, flags);
+ ret = SOCKETCALL_CANCEL (recvmsg, fd, msg, flags);
#endif
+
+#if __WORDSIZE == 64
+ if (orig != NULL)
+ *orig = hdr;
+#endif
+
+ return ret;
}
-weak_alias (__libc_recvmsg, recvmsg)
weak_alias (__libc_recvmsg, __recvmsg)
+versioned_symbol (libc, __libc_recvmsg, recvmsg, GLIBC_2_24);