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
This commit is contained in:
Anthony Liguori 2013-03-14 14:50:21 -05:00
commit 6582d3e8be
6 changed files with 302 additions and 47 deletions

17
configure vendored
View File

@ -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

View File

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

View File

@ -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) */

View File

@ -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

View File

@ -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
@ -1436,6 +1497,12 @@ if( cmd == val ) { \
gemu_log("FUTEX_PRIVATE_FLAG|");
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)

View File

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