aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-03-14 14:50:21 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-03-14 14:50:21 -0500
commit6582d3e8be98cf8171489793e094aee94a1276ce (patch)
treed3ae2dc15e67e12002564c3ad2bdd657858c9b5c
parentc69b30e8301a49cd198d54bb740a0c9adcd2a34a (diff)
parente9a970a8316f9f86a6c800a9a90175bd593f862c (diff)
Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
# By Peter Maydell (5) and others # Via Riku Voipio * riku/linux-user-for-upstream: linux-user/syscall.c: Don't warn about unimplemented get_robust_list linux-user: Implement accept4 linux-user: Implement sendfile and sendfile64 linux-user: make bogus negative iovec lengths fail EINVAL linux-user: Fix layout of usage table to account for option text linux-user: Add more sparc syscall numbers linux-user: Support setgroups syscall with no groups linux-user: fix futex strace of FUTEX_CLOCK_REALTIME linux-user/syscall.c: handle FUTEX_WAIT_BITSET in do_futex linux-user: improve print_fcntl() linux-user: Add Alpha socket constants
-rwxr-xr-xconfigure17
-rw-r--r--linux-user/main.c24
-rw-r--r--linux-user/socket.h69
-rw-r--r--linux-user/sparc/syscall_nr.h2
-rw-r--r--linux-user/strace.c103
-rw-r--r--linux-user/syscall.c134
6 files changed, 302 insertions, 47 deletions
diff --git a/configure b/configure
index a382ff2562..46a75947cd 100755
--- a/configure
+++ b/configure
@@ -2764,6 +2764,20 @@ if compile_prog "" "" ; then
epoll_pwait=yes
fi
+# check for sendfile support
+sendfile=no
+cat > $TMPC << EOF
+#include <sys/sendfile.h>
+
+int main(void)
+{
+ return sendfile(0, 0, 0, 0);
+}
+EOF
+if compile_prog "" "" ; then
+ sendfile=yes
+fi
+
# Check if tools are available to build documentation.
if test "$docs" != "no" ; then
if has makeinfo && has pod2man; then
@@ -3633,6 +3647,9 @@ fi
if test "$epoll_pwait" = "yes" ; then
echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak
fi
+if test "$sendfile" = "yes" ; then
+ echo "CONFIG_SENDFILE=y" >> $config_host_mak
+fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
diff --git a/linux-user/main.c b/linux-user/main.c
index d8b0cd65fa..4e92a0b4c5 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3406,27 +3406,35 @@ static void usage(void)
"Options and associated environment variables:\n"
"\n");
- maxarglen = maxenvlen = 0;
+ /* Calculate column widths. We must always have at least enough space
+ * for the column header.
+ */
+ maxarglen = strlen("Argument");
+ maxenvlen = strlen("Env-variable");
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
+ int arglen = strlen(arginfo->argv);
+ if (arginfo->has_arg) {
+ arglen += strlen(arginfo->example) + 1;
+ }
if (strlen(arginfo->env) > maxenvlen) {
maxenvlen = strlen(arginfo->env);
}
- if (strlen(arginfo->argv) > maxarglen) {
- maxarglen = strlen(arginfo->argv);
+ if (arglen > maxarglen) {
+ maxarglen = arglen;
}
}
- printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
- maxenvlen+1, "Env-variable");
+ printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
+ maxenvlen, "Env-variable");
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (arginfo->has_arg) {
printf("-%s %-*s %-*s %s\n", arginfo->argv,
- (int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
- maxenvlen, arginfo->env, arginfo->help);
+ (int)(maxarglen - strlen(arginfo->argv) - 1),
+ arginfo->example, maxenvlen, arginfo->env, arginfo->help);
} else {
- printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
+ printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
maxenvlen, arginfo->env,
arginfo->help);
}
diff --git a/linux-user/socket.h b/linux-user/socket.h
index 93d47823d8..339cae5a16 100644
--- a/linux-user/socket.h
+++ b/linux-user/socket.h
@@ -87,6 +87,75 @@
#define TARGET_SOCK_MAX (SOCK_PACKET + 1)
+#elif defined(TARGET_ALPHA)
+
+ /* For setsockopt(2) */
+ #define TARGET_SOL_SOCKET 0xffff
+
+ #define TARGET_SO_DEBUG 0x0001
+ #define TARGET_SO_REUSEADDR 0x0004
+ #define TARGET_SO_KEEPALIVE 0x0008
+ #define TARGET_SO_DONTROUTE 0x0010
+ #define TARGET_SO_BROADCAST 0x0020
+ #define TARGET_SO_LINGER 0x0080
+ #define TARGET_SO_OOBINLINE 0x0100
+ /* To add :#define TARGET_SO_REUSEPORT 0x0200 */
+
+ #define TARGET_SO_TYPE 0x1008
+ #define TARGET_SO_ERROR 0x1007
+ #define TARGET_SO_SNDBUF 0x1001
+ #define TARGET_SO_RCVBUF 0x1002
+ #define TARGET_SO_SNDBUFFORCE 0x100a
+ #define TARGET_SO_RCVBUFFORCE 0x100b
+ #define TARGET_SO_RCVLOWAT 0x1010
+ #define TARGET_SO_SNDLOWAT 0x1011
+ #define TARGET_SO_RCVTIMEO 0x1012
+ #define TARGET_SO_SNDTIMEO 0x1013
+ #define TARGET_SO_ACCEPTCONN 0x1014
+ #define TARGET_SO_PROTOCOL 0x1028
+ #define TARGET_SO_DOMAIN 0x1029
+
+ /* linux-specific, might as well be the same as on i386 */
+ #define TARGET_SO_NO_CHECK 11
+ #define TARGET_SO_PRIORITY 12
+ #define TARGET_SO_BSDCOMPAT 14
+
+ #define TARGET_SO_PASSCRED 17
+ #define TARGET_SO_PEERCRED 18
+ #define TARGET_SO_BINDTODEVICE 25
+
+ /* Socket filtering */
+ #define TARGET_SO_ATTACH_FILTER 26
+ #define TARGET_SO_DETACH_FILTER 27
+
+ #define TARGET_SO_PEERNAME 28
+ #define TARGET_SO_TIMESTAMP 29
+ #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
+
+ #define TARGET_SO_PEERSEC 30
+ #define TARGET_SO_PASSSEC 34
+ #define TARGET_SO_TIMESTAMPNS 35
+ #define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
+
+ /* Security levels - as per NRL IPv6 - don't actually do anything */
+ #define TARGET_SO_SECURITY_AUTHENTICATION 19
+ #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 20
+ #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 21
+
+ #define TARGET_SO_MARK 36
+
+ #define TARGET_SO_TIMESTAMPING 37
+ #define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING
+
+ #define TARGET_SO_RXQ_OVFL 40
+
+ #define TARGET_SO_WIFI_STATUS 41
+ #define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS
+ #define TARGET_SO_PEEK_OFF 42
+
+ /* Instruct lower device to use last 4-bytes of skb data as FCS */
+ #define TARGET_SO_NOFCS 43
+
#else
/* For setsockopt(2) */
diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h
index 061711cc03..534e6e9963 100644
--- a/linux-user/sparc/syscall_nr.h
+++ b/linux-user/sparc/syscall_nr.h
@@ -200,6 +200,8 @@
#define TARGET_NR__newselect 230 /* Linux Specific */
#define TARGET_NR_time 231 /* Linux Specific */
#define TARGET_NR_stime 233 /* Linux Specific */
+#define TARGET_NR_statfs64 234 /* Linux Specific */
+#define TARGET_NR_fstatfs64 235 /* Linux Specific */
#define TARGET_NR__llseek 236 /* Linux Specific */
#define TARGET_NR_mlock 237
#define TARGET_NR_munlock 238
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 4e91a6eb9c..0fbae3c2f6 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -462,18 +462,6 @@ UNUSED static struct flags mmap_flags[] = {
FLAG_END,
};
-UNUSED static struct flags fcntl_flags[] = {
- FLAG_TARGET(F_DUPFD),
- FLAG_TARGET(F_GETFD),
- FLAG_TARGET(F_SETFD),
- FLAG_TARGET(F_GETFL),
- FLAG_TARGET(F_SETFL),
- FLAG_TARGET(F_GETLK),
- FLAG_TARGET(F_SETLK),
- FLAG_TARGET(F_SETLKW),
- FLAG_END,
-};
-
UNUSED static struct flags clone_flags[] = {
FLAG_GENERIC(CLONE_VM),
FLAG_GENERIC(CLONE_FS),
@@ -867,12 +855,85 @@ print_fcntl(const struct syscallname *name,
{
print_syscall_prologue(name);
print_raw_param("%d", arg0, 0);
- print_flags(fcntl_flags, arg1, 0);
- /*
- * TODO: check flags and print following argument only
- * when needed.
- */
- print_pointer(arg2, 1);
+ switch(arg1) {
+ case TARGET_F_DUPFD:
+ gemu_log("F_DUPFD,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+ break;
+ case TARGET_F_GETFD:
+ gemu_log("F_GETFD");
+ break;
+ case TARGET_F_SETFD:
+ gemu_log("F_SETFD,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+ break;
+ case TARGET_F_GETFL:
+ gemu_log("F_GETFL");
+ break;
+ case TARGET_F_SETFL:
+ gemu_log("F_SETFL,");
+ print_open_flags(arg2, 1);
+ break;
+ case TARGET_F_GETLK:
+ gemu_log("F_GETLK,");
+ print_pointer(arg2, 1);
+ break;
+ case TARGET_F_SETLK:
+ gemu_log("F_SETLK,");
+ print_pointer(arg2, 1);
+ break;
+ case TARGET_F_SETLKW:
+ gemu_log("F_SETLKW,");
+ print_pointer(arg2, 1);
+ break;
+ case TARGET_F_GETOWN:
+ gemu_log("F_GETOWN");
+ break;
+ case TARGET_F_SETOWN:
+ gemu_log("F_SETOWN,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+ break;
+ case TARGET_F_GETSIG:
+ gemu_log("F_GETSIG");
+ break;
+ case TARGET_F_SETSIG:
+ gemu_log("F_SETSIG,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+ break;
+#if TARGET_ABI_BITS == 32
+ case TARGET_F_GETLK64:
+ gemu_log("F_GETLK64,");
+ print_pointer(arg2, 1);
+ break;
+ case TARGET_F_SETLK64:
+ gemu_log("F_SETLK64,");
+ print_pointer(arg2, 1);
+ break;
+ case TARGET_F_SETLKW64:
+ gemu_log("F_SETLKW64,");
+ print_pointer(arg2, 1);
+ break;
+#endif
+ case TARGET_F_SETLEASE:
+ gemu_log("F_SETLEASE,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+ break;
+ case TARGET_F_GETLEASE:
+ gemu_log("F_GETLEASE");
+ break;
+ case TARGET_F_DUPFD_CLOEXEC:
+ gemu_log("F_DUPFD_CLOEXEC,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 1);
+ break;
+ case TARGET_F_NOTIFY:
+ gemu_log("F_NOTIFY,");
+ print_raw_param(TARGET_ABI_FMT_ld, arg2, 0);
+ break;
+ default:
+ print_raw_param(TARGET_ABI_FMT_ld, arg1, 0);
+ print_pointer(arg2, 1);
+ break;
+ }
print_syscall_epilogue(name);
}
#define print_fcntl64 print_fcntl
@@ -1437,6 +1498,12 @@ if( cmd == val ) { \
cmd &= ~FUTEX_PRIVATE_FLAG;
}
#endif
+#ifdef FUTEX_CLOCK_REALTIME
+ if (cmd & FUTEX_CLOCK_REALTIME) {
+ gemu_log("FUTEX_CLOCK_REALTIME|");
+ cmd &= ~FUTEX_CLOCK_REALTIME;
+ }
+#endif
print_op(FUTEX_WAIT)
print_op(FUTEX_WAKE)
print_op(FUTEX_FD)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 19630eaf20..ee82a2da4e 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -78,6 +78,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#ifdef CONFIG_ATTR
#include "qemu/xattr.h"
#endif
+#ifdef CONFIG_SENDFILE
+#include <sys/sendfile.h>
+#endif
#define termios host_termios
#define winsize host_winsize
@@ -1776,7 +1779,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr,
errno = 0;
return NULL;
}
- if (count > IOV_MAX) {
+ if (count < 0 || count > IOV_MAX) {
errno = EINVAL;
return NULL;
}
@@ -2001,16 +2004,30 @@ out2:
return ret;
}
-/* do_accept() Must return target values and target errnos. */
-static abi_long do_accept(int fd, abi_ulong target_addr,
- abi_ulong target_addrlen_addr)
+/* If we don't have a system accept4() then just call accept.
+ * The callsites to do_accept4() will ensure that they don't
+ * pass a non-zero flags argument in this config.
+ */
+#ifndef CONFIG_ACCEPT4
+static inline int accept4(int sockfd, struct sockaddr *addr,
+ socklen_t *addrlen, int flags)
+{
+ assert(flags == 0);
+ return accept(sockfd, addr, addrlen);
+}
+#endif
+
+/* do_accept4() Must return target values and target errnos. */
+static abi_long do_accept4(int fd, abi_ulong target_addr,
+ abi_ulong target_addrlen_addr, int flags)
{
socklen_t addrlen;
void *addr;
abi_long ret;
- if (target_addr == 0)
- return get_errno(accept(fd, NULL, NULL));
+ if (target_addr == 0) {
+ return get_errno(accept4(fd, NULL, NULL, flags));
+ }
/* linux returns EINVAL if addrlen pointer is invalid */
if (get_user_u32(addrlen, target_addrlen_addr))
@@ -2025,7 +2042,7 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
addr = alloca(addrlen);
- ret = get_errno(accept(fd, addr, &addrlen));
+ ret = get_errno(accept4(fd, addr, &addrlen, flags));
if (!is_error(ret)) {
host_to_target_sockaddr(target_addr, addr, addrlen);
if (put_user_u32(addrlen, target_addrlen_addr))
@@ -2251,7 +2268,7 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
|| get_user_ual(target_addrlen, vptr + 2 * n))
return -TARGET_EFAULT;
- ret = do_accept(sockfd, target_addr, target_addrlen);
+ ret = do_accept4(sockfd, target_addr, target_addrlen, 0);
}
break;
case SOCKOP_getsockname:
@@ -4922,6 +4939,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
#endif
switch (base_op) {
case FUTEX_WAIT:
+ case FUTEX_WAIT_BITSET:
if (timeout) {
pts = &ts;
target_to_host_timespec(pts, timeout);
@@ -4929,7 +4947,7 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
pts = NULL;
}
return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
- pts, NULL, 0));
+ pts, NULL, val3));
case FUTEX_WAKE:
return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
case FUTEX_FD:
@@ -6673,7 +6691,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_accept
case TARGET_NR_accept:
- ret = do_accept(arg1, arg2, arg3);
+ ret = do_accept4(arg1, arg2, arg3, 0);
+ break;
+#endif
+#ifdef TARGET_NR_accept4
+ case TARGET_NR_accept4:
+#ifdef CONFIG_ACCEPT4
+ ret = do_accept4(arg1, arg2, arg3, arg4);
+#else
+ goto unimplemented;
+#endif
break;
#endif
#ifdef TARGET_NR_bind
@@ -7530,8 +7557,58 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#else
goto unimplemented;
#endif
+
+#ifdef CONFIG_SENDFILE
+ case TARGET_NR_sendfile:
+ {
+ off_t *offp = NULL;
+ off_t off;
+ if (arg3) {
+ ret = get_user_sal(off, arg3);
+ if (is_error(ret)) {
+ break;
+ }
+ offp = &off;
+ }
+ ret = get_errno(sendfile(arg1, arg2, offp, arg4));
+ if (!is_error(ret) && arg3) {
+ abi_long ret2 = put_user_sal(off, arg3);
+ if (is_error(ret2)) {
+ ret = ret2;
+ }
+ }
+ break;
+ }
+#ifdef TARGET_NR_sendfile64
+ case TARGET_NR_sendfile64:
+ {
+ off_t *offp = NULL;
+ off_t off;
+ if (arg3) {
+ ret = get_user_s64(off, arg3);
+ if (is_error(ret)) {
+ break;
+ }
+ offp = &off;
+ }
+ ret = get_errno(sendfile(arg1, arg2, offp, arg4));
+ if (!is_error(ret) && arg3) {
+ abi_long ret2 = put_user_s64(off, arg3);
+ if (is_error(ret2)) {
+ ret = ret2;
+ }
+ }
+ break;
+ }
+#endif
+#else
case TARGET_NR_sendfile:
+#ifdef TARGET_NR_sendfile64:
+ case TARGET_NR_sendfile64:
+#endif
goto unimplemented;
+#endif
+
#ifdef TARGET_NR_getpmsg
case TARGET_NR_getpmsg:
goto unimplemented;
@@ -7679,18 +7756,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
int gidsetsize = arg1;
target_id *target_grouplist;
- gid_t *grouplist;
+ gid_t *grouplist = NULL;
int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
- if (!target_grouplist) {
- ret = -TARGET_EFAULT;
- goto fail;
+ if (gidsetsize) {
+ grouplist = alloca(gidsetsize * sizeof(gid_t));
+ target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 2, 1);
+ if (!target_grouplist) {
+ ret = -TARGET_EFAULT;
+ goto fail;
+ }
+ for (i = 0; i < gidsetsize; i++) {
+ grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
+ }
+ unlock_user(target_grouplist, arg2, 0);
}
- for(i = 0;i < gidsetsize; i++)
- grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
- unlock_user(target_grouplist, arg2, 0);
ret = get_errno(setgroups(gidsetsize, grouplist));
}
break;
@@ -8552,7 +8631,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_set_robust_list
case TARGET_NR_set_robust_list:
- goto unimplemented_nowarn;
+ case TARGET_NR_get_robust_list:
+ /* The ABI for supporting robust futexes has userspace pass
+ * the kernel a pointer to a linked list which is updated by
+ * userspace after the syscall; the list is walked by the kernel
+ * when the thread exits. Since the linked list in QEMU guest
+ * memory isn't a valid linked list for the host and we have
+ * no way to reliably intercept the thread-death event, we can't
+ * support these. Silently return ENOSYS so that guest userspace
+ * falls back to a non-robust futex implementation (which should
+ * be OK except in the corner case of the guest crashing while
+ * holding a mutex that is shared with another process via
+ * shared memory).
+ */
+ goto unimplemented_nowarn;
#endif
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)