From 19f59bcef91cd4abc04d10c9ecbf5183b71f1b06 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 22 Sep 2016 18:56:50 +0200 Subject: linux-user: Add support for adjtimex() syscall This patch implements Qemu user mode adjtimex() syscall support. Syscall adjtimex() reads and optionally sets parameters for a clock adjustment algorithm used in network synchonization or similar scenarios. Its declaration is: int adjtimex(struct timex *buf); The correspondent source code in the Linux kernel is at kernel/time.c, line 206. The Qemu implementation is based on invocation of host's adjtimex(), and its key part is in the "TARGET_NR_adjtimex" case segment of the the main switch statement of the function do_syscall(), in linux-user/syscalls.c. All necessary conversions of the data structures from target to host and from host to target are covered. Two new functions, target_to_host_timex() and host_to_target_timex(), are provided for the purpose of such conversions. For that purpose, the support for related structure "timex" had tp be added to the file linux-user/syscall_defs.h, based on its definition in Linux kernel. Also, the relevant support for "-strace" Qemu option is included in files linux-user/strace.c and linux-user/strace.list. This patch also fixes failures of LTP tests adjtimex01 and adjtimex02, if executed in Qemu user mode. Signed-off-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Signed-off-by: Riku Voipio --- linux-user/syscall.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 03339ba0de..0379b8a21b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef __ia64__ int __clone2(int (*fn)(void *), void *child_stack_base, size_t stack_size, int flags, void *arg, ...); @@ -6770,6 +6771,77 @@ static inline abi_long host_to_target_itimerspec(abi_ulong target_addr, return 0; } +static inline abi_long target_to_host_timex(struct timex *host_tx, + abi_long target_addr) +{ + struct target_timex *target_tx; + + if (!lock_user_struct(VERIFY_READ, target_tx, target_addr, 1)) { + return -TARGET_EFAULT; + } + + __get_user(host_tx->modes, &target_tx->modes); + __get_user(host_tx->offset, &target_tx->offset); + __get_user(host_tx->freq, &target_tx->freq); + __get_user(host_tx->maxerror, &target_tx->maxerror); + __get_user(host_tx->esterror, &target_tx->esterror); + __get_user(host_tx->status, &target_tx->status); + __get_user(host_tx->constant, &target_tx->constant); + __get_user(host_tx->precision, &target_tx->precision); + __get_user(host_tx->tolerance, &target_tx->tolerance); + __get_user(host_tx->time.tv_sec, &target_tx->time.tv_sec); + __get_user(host_tx->time.tv_usec, &target_tx->time.tv_usec); + __get_user(host_tx->tick, &target_tx->tick); + __get_user(host_tx->ppsfreq, &target_tx->ppsfreq); + __get_user(host_tx->jitter, &target_tx->jitter); + __get_user(host_tx->shift, &target_tx->shift); + __get_user(host_tx->stabil, &target_tx->stabil); + __get_user(host_tx->jitcnt, &target_tx->jitcnt); + __get_user(host_tx->calcnt, &target_tx->calcnt); + __get_user(host_tx->errcnt, &target_tx->errcnt); + __get_user(host_tx->stbcnt, &target_tx->stbcnt); + __get_user(host_tx->tai, &target_tx->tai); + + unlock_user_struct(target_tx, target_addr, 0); + return 0; +} + +static inline abi_long host_to_target_timex(abi_long target_addr, + struct timex *host_tx) +{ + struct target_timex *target_tx; + + if (!lock_user_struct(VERIFY_WRITE, target_tx, target_addr, 0)) { + return -TARGET_EFAULT; + } + + __put_user(host_tx->modes, &target_tx->modes); + __put_user(host_tx->offset, &target_tx->offset); + __put_user(host_tx->freq, &target_tx->freq); + __put_user(host_tx->maxerror, &target_tx->maxerror); + __put_user(host_tx->esterror, &target_tx->esterror); + __put_user(host_tx->status, &target_tx->status); + __put_user(host_tx->constant, &target_tx->constant); + __put_user(host_tx->precision, &target_tx->precision); + __put_user(host_tx->tolerance, &target_tx->tolerance); + __put_user(host_tx->time.tv_sec, &target_tx->time.tv_sec); + __put_user(host_tx->time.tv_usec, &target_tx->time.tv_usec); + __put_user(host_tx->tick, &target_tx->tick); + __put_user(host_tx->ppsfreq, &target_tx->ppsfreq); + __put_user(host_tx->jitter, &target_tx->jitter); + __put_user(host_tx->shift, &target_tx->shift); + __put_user(host_tx->stabil, &target_tx->stabil); + __put_user(host_tx->jitcnt, &target_tx->jitcnt); + __put_user(host_tx->calcnt, &target_tx->calcnt); + __put_user(host_tx->errcnt, &target_tx->errcnt); + __put_user(host_tx->stbcnt, &target_tx->stbcnt); + __put_user(host_tx->tai, &target_tx->tai); + + unlock_user_struct(target_tx, target_addr, 1); + return 0; +} + + static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp, abi_ulong target_addr) { @@ -9543,7 +9615,20 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #endif case TARGET_NR_adjtimex: - goto unimplemented; + { + struct timex host_buf; + + if (target_to_host_timex(&host_buf, arg1) != 0) { + goto efault; + } + ret = get_errno(adjtimex(&host_buf)); + if (!is_error(ret)) { + if (host_to_target_timex(arg1, &host_buf) != 0) { + goto efault; + } + } + } + break; #ifdef TARGET_NR_create_module case TARGET_NR_create_module: #endif -- cgit 1.4.1 From c7536ab679049ee90f94f5a18da451afeb41003c Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 22 Sep 2016 18:56:55 +0200 Subject: linux-user: Fix mq_open() syscall support Conversion of file creation flags (O_CREAT, ...) from target to host was missing. Also, this patch implements better error handling. Signed-off-by: Aleksandar Markovic Signed-off-by: Riku Voipio --- linux-user/syscall.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 0379b8a21b..99be4f2f3e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11457,16 +11457,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) case TARGET_NR_mq_open: { - struct mq_attr posix_mq_attr, *attrp; + struct mq_attr posix_mq_attr; + int host_flags; + host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl); + if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) { + goto efault; + } p = lock_user_string(arg1 - 1); - if (arg4 != 0) { - copy_from_user_mq_attr (&posix_mq_attr, arg4); - attrp = &posix_mq_attr; - } else { - attrp = 0; + if (!p) { + goto efault; } - ret = get_errno(mq_open(p, arg2, arg3, attrp)); + ret = get_errno(mq_open(p, host_flags, arg3, &posix_mq_attr)); unlock_user (p, arg1, 0); } break; -- cgit 1.4.1 From da39db63e4468e39bb56d04d191866c5276aa7fa Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 22 Sep 2016 18:56:56 +0200 Subject: linux-user: Fix msgrcv() and msgsnd() syscalls support If syscalls msgrcv() and msgsnd() fail, they return E2BIG, EACCES, EAGAIN, EFAULT, EIDRM, EINTR, EINVAL, ENOMEM, or ENOMSG. By examining negative scenarios of these syscalls for Mips, it was established that ENOMSG does not have the same value accross all platforms, but it is nevertheless not included for conversion in the correspondant conversion table defined in linux-user/syscall.c. This is certainly a bug, since it leads to the incorrect emulation of msgrcv() and msgsnd() for scenarios involving ENOMSG. This patch fixes this by extending the conversion table to include ENOMSG. Also, LTP test msgrcv04 will be fixed for some platforms. Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/syscall.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 99be4f2f3e..36ca921a7e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -789,6 +789,9 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = { #ifdef ENOTRECOVERABLE [ENOTRECOVERABLE] = TARGET_ENOTRECOVERABLE, #endif +#ifdef ENOMSG + [ENOMSG] = TARGET_ENOMSG, +#endif }; static inline int host_to_target_errno(int err) -- cgit 1.4.1 From ff71a4545c0d9b452e77a91ab1c46f79a10a9eca Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 22 Sep 2016 18:56:57 +0200 Subject: linux-user: Fix socketcall() syscall support Since not all Linux host platforms support socketcall() (most notably Intel), do_socketcall() function in Qemu's syscalls.c is implemented to mirror the corespondant implementation of socketcall() in Linux kernel, and to utilise individual socket operations that are supported on all Linux platforms. (see kernel source file net/socket.c, definition of socketcall). However, error codes produced by Qemu implementation are wrong for the cases of invalid values of the first argument. Also, naming of constants is not consistent with kernel one, and not consistant with Qemu convention of prefixing such constants with "TARGET_". This patch in that light brings do_socketcall() closer to its kernel counterpart, and in that way fixes the errors and yields more consisrtent Qemu code. There were also three missing cases (among 20) for strace support for socketcall(). The array that contains pointers for appropriate printing functions is updated with 3 elements, however pointers to functions are left NULL, and its implementation is left for future. Also, this patch fixes failure of LTP test socketcall02, if executed on some Qemu emulated sywstems (uer mode). Signed-off-by: Aleksandar Markovic Signed-off-by: Riku Voipio --- linux-user/strace.c | 39 ++++++++------- linux-user/syscall.c | 119 ++++++++++++++++++++++++---------------------- linux-user/syscall_defs.h | 42 ++++++++-------- 3 files changed, 105 insertions(+), 95 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/strace.c b/linux-user/strace.c index f37b386bda..a0e45b55d1 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1675,29 +1675,32 @@ print_optint: } #define PRINT_SOCKOP(name, func) \ - [SOCKOP_##name] = { #name, func } + [TARGET_SYS_##name] = { #name, func } static struct { const char *name; void (*print)(const char *, abi_long); } scall[] = { - PRINT_SOCKOP(socket, do_print_socket), - PRINT_SOCKOP(bind, do_print_sockaddr), - PRINT_SOCKOP(connect, do_print_sockaddr), - PRINT_SOCKOP(listen, do_print_listen), - PRINT_SOCKOP(accept, do_print_sockaddr), - PRINT_SOCKOP(getsockname, do_print_sockaddr), - PRINT_SOCKOP(getpeername, do_print_sockaddr), - PRINT_SOCKOP(socketpair, do_print_socketpair), - PRINT_SOCKOP(send, do_print_sendrecv), - PRINT_SOCKOP(recv, do_print_sendrecv), - PRINT_SOCKOP(sendto, do_print_msgaddr), - PRINT_SOCKOP(recvfrom, do_print_msgaddr), - PRINT_SOCKOP(shutdown, do_print_shutdown), - PRINT_SOCKOP(sendmsg, do_print_msg), - PRINT_SOCKOP(recvmsg, do_print_msg), - PRINT_SOCKOP(setsockopt, do_print_sockopt), - PRINT_SOCKOP(getsockopt, do_print_sockopt), + PRINT_SOCKOP(SOCKET, do_print_socket), + PRINT_SOCKOP(BIND, do_print_sockaddr), + PRINT_SOCKOP(CONNECT, do_print_sockaddr), + PRINT_SOCKOP(LISTEN, do_print_listen), + PRINT_SOCKOP(ACCEPT, do_print_sockaddr), + PRINT_SOCKOP(GETSOCKNAME, do_print_sockaddr), + PRINT_SOCKOP(GETPEERNAME, do_print_sockaddr), + PRINT_SOCKOP(SOCKETPAIR, do_print_socketpair), + PRINT_SOCKOP(SEND, do_print_sendrecv), + PRINT_SOCKOP(RECV, do_print_sendrecv), + PRINT_SOCKOP(SENDTO, do_print_msgaddr), + PRINT_SOCKOP(RECVFROM, do_print_msgaddr), + PRINT_SOCKOP(SHUTDOWN, do_print_shutdown), + PRINT_SOCKOP(SETSOCKOPT, do_print_sockopt), + PRINT_SOCKOP(GETSOCKOPT, do_print_sockopt), + PRINT_SOCKOP(SENDMSG, do_print_msg), + PRINT_SOCKOP(RECVMSG, do_print_msg), + PRINT_SOCKOP(ACCEPT4, NULL), + PRINT_SOCKOP(RECVMMSG, NULL), + PRINT_SOCKOP(SENDMMSG, NULL), }; static void diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 36ca921a7e..7ea23ad6ce 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3897,89 +3897,94 @@ fail: } #ifdef TARGET_NR_socketcall -/* do_socketcall() Must return target values and target errnos. */ +/* do_socketcall() must return target values and target errnos. */ static abi_long do_socketcall(int num, abi_ulong vptr) { - static const unsigned ac[] = { /* number of arguments per call */ - [SOCKOP_socket] = 3, /* domain, type, protocol */ - [SOCKOP_bind] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_connect] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_listen] = 2, /* sockfd, backlog */ - [SOCKOP_accept] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_accept4] = 4, /* sockfd, addr, addrlen, flags */ - [SOCKOP_getsockname] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_getpeername] = 3, /* sockfd, addr, addrlen */ - [SOCKOP_socketpair] = 4, /* domain, type, protocol, tab */ - [SOCKOP_send] = 4, /* sockfd, msg, len, flags */ - [SOCKOP_recv] = 4, /* sockfd, msg, len, flags */ - [SOCKOP_sendto] = 6, /* sockfd, msg, len, flags, addr, addrlen */ - [SOCKOP_recvfrom] = 6, /* sockfd, msg, len, flags, addr, addrlen */ - [SOCKOP_shutdown] = 2, /* sockfd, how */ - [SOCKOP_sendmsg] = 3, /* sockfd, msg, flags */ - [SOCKOP_recvmsg] = 3, /* sockfd, msg, flags */ - [SOCKOP_sendmmsg] = 4, /* sockfd, msgvec, vlen, flags */ - [SOCKOP_recvmmsg] = 4, /* sockfd, msgvec, vlen, flags */ - [SOCKOP_setsockopt] = 5, /* sockfd, level, optname, optval, optlen */ - [SOCKOP_getsockopt] = 5, /* sockfd, level, optname, optval, optlen */ + static const unsigned nargs[] = { /* number of arguments per operation */ + [TARGET_SYS_SOCKET] = 3, /* domain, type, protocol */ + [TARGET_SYS_BIND] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_CONNECT] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_LISTEN] = 2, /* fd, backlog */ + [TARGET_SYS_ACCEPT] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_GETSOCKNAME] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_GETPEERNAME] = 3, /* fd, addr, addrlen */ + [TARGET_SYS_SOCKETPAIR] = 4, /* domain, type, protocol, tab */ + [TARGET_SYS_SEND] = 4, /* fd, msg, len, flags */ + [TARGET_SYS_RECV] = 4, /* fd, msg, len, flags */ + [TARGET_SYS_SENDTO] = 6, /* fd, msg, len, flags, addr, addrlen */ + [TARGET_SYS_RECVFROM] = 6, /* fd, msg, len, flags, addr, addrlen */ + [TARGET_SYS_SHUTDOWN] = 2, /* fd, how */ + [TARGET_SYS_SETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */ + [TARGET_SYS_GETSOCKOPT] = 5, /* fd, level, optname, optval, optlen */ + [TARGET_SYS_SENDMSG] = 3, /* fd, msg, flags */ + [TARGET_SYS_RECVMSG] = 3, /* fd, msg, flags */ + [TARGET_SYS_ACCEPT4] = 4, /* fd, addr, addrlen, flags */ + [TARGET_SYS_RECVMMSG] = 4, /* fd, msgvec, vlen, flags */ + [TARGET_SYS_SENDMMSG] = 4, /* fd, msgvec, vlen, flags */ }; abi_long a[6]; /* max 6 args */ + unsigned i; - /* first, collect the arguments in a[] according to ac[] */ - if (num >= 0 && num < ARRAY_SIZE(ac)) { - unsigned i; - assert(ARRAY_SIZE(a) >= ac[num]); /* ensure we have space for args */ - for (i = 0; i < ac[num]; ++i) { - if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) { - return -TARGET_EFAULT; - } + /* check the range of the first argument num */ + /* (TARGET_SYS_SENDMMSG is the highest among TARGET_SYS_xxx) */ + if (num < 1 || num > TARGET_SYS_SENDMMSG) { + return -TARGET_EINVAL; + } + /* ensure we have space for args */ + if (nargs[num] > ARRAY_SIZE(a)) { + return -TARGET_EINVAL; + } + /* collect the arguments in a[] according to nargs[] */ + for (i = 0; i < nargs[num]; ++i) { + if (get_user_ual(a[i], vptr + i * sizeof(abi_long)) != 0) { + return -TARGET_EFAULT; } } - - /* now when we have the args, actually handle the call */ + /* now when we have the args, invoke the appropriate underlying function */ switch (num) { - case SOCKOP_socket: /* domain, type, protocol */ + case TARGET_SYS_SOCKET: /* domain, type, protocol */ return do_socket(a[0], a[1], a[2]); - case SOCKOP_bind: /* sockfd, addr, addrlen */ + case TARGET_SYS_BIND: /* sockfd, addr, addrlen */ return do_bind(a[0], a[1], a[2]); - case SOCKOP_connect: /* sockfd, addr, addrlen */ + case TARGET_SYS_CONNECT: /* sockfd, addr, addrlen */ return do_connect(a[0], a[1], a[2]); - case SOCKOP_listen: /* sockfd, backlog */ + case TARGET_SYS_LISTEN: /* sockfd, backlog */ return get_errno(listen(a[0], a[1])); - case SOCKOP_accept: /* sockfd, addr, addrlen */ + case TARGET_SYS_ACCEPT: /* sockfd, addr, addrlen */ return do_accept4(a[0], a[1], a[2], 0); - case SOCKOP_accept4: /* sockfd, addr, addrlen, flags */ - return do_accept4(a[0], a[1], a[2], a[3]); - case SOCKOP_getsockname: /* sockfd, addr, addrlen */ + case TARGET_SYS_GETSOCKNAME: /* sockfd, addr, addrlen */ return do_getsockname(a[0], a[1], a[2]); - case SOCKOP_getpeername: /* sockfd, addr, addrlen */ + case TARGET_SYS_GETPEERNAME: /* sockfd, addr, addrlen */ return do_getpeername(a[0], a[1], a[2]); - case SOCKOP_socketpair: /* domain, type, protocol, tab */ + case TARGET_SYS_SOCKETPAIR: /* domain, type, protocol, tab */ return do_socketpair(a[0], a[1], a[2], a[3]); - case SOCKOP_send: /* sockfd, msg, len, flags */ + case TARGET_SYS_SEND: /* sockfd, msg, len, flags */ return do_sendto(a[0], a[1], a[2], a[3], 0, 0); - case SOCKOP_recv: /* sockfd, msg, len, flags */ + case TARGET_SYS_RECV: /* sockfd, msg, len, flags */ return do_recvfrom(a[0], a[1], a[2], a[3], 0, 0); - case SOCKOP_sendto: /* sockfd, msg, len, flags, addr, addrlen */ + case TARGET_SYS_SENDTO: /* sockfd, msg, len, flags, addr, addrlen */ return do_sendto(a[0], a[1], a[2], a[3], a[4], a[5]); - case SOCKOP_recvfrom: /* sockfd, msg, len, flags, addr, addrlen */ + case TARGET_SYS_RECVFROM: /* sockfd, msg, len, flags, addr, addrlen */ return do_recvfrom(a[0], a[1], a[2], a[3], a[4], a[5]); - case SOCKOP_shutdown: /* sockfd, how */ + case TARGET_SYS_SHUTDOWN: /* sockfd, how */ return get_errno(shutdown(a[0], a[1])); - case SOCKOP_sendmsg: /* sockfd, msg, flags */ + case TARGET_SYS_SETSOCKOPT: /* sockfd, level, optname, optval, optlen */ + return do_setsockopt(a[0], a[1], a[2], a[3], a[4]); + case TARGET_SYS_GETSOCKOPT: /* sockfd, level, optname, optval, optlen */ + return do_getsockopt(a[0], a[1], a[2], a[3], a[4]); + case TARGET_SYS_SENDMSG: /* sockfd, msg, flags */ return do_sendrecvmsg(a[0], a[1], a[2], 1); - case SOCKOP_recvmsg: /* sockfd, msg, flags */ + case TARGET_SYS_RECVMSG: /* sockfd, msg, flags */ return do_sendrecvmsg(a[0], a[1], a[2], 0); - case SOCKOP_sendmmsg: /* sockfd, msgvec, vlen, flags */ - return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1); - case SOCKOP_recvmmsg: /* sockfd, msgvec, vlen, flags */ + case TARGET_SYS_ACCEPT4: /* sockfd, addr, addrlen, flags */ + return do_accept4(a[0], a[1], a[2], a[3]); + case TARGET_SYS_RECVMMSG: /* sockfd, msgvec, vlen, flags */ return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 0); - case SOCKOP_setsockopt: /* sockfd, level, optname, optval, optlen */ - return do_setsockopt(a[0], a[1], a[2], a[3], a[4]); - case SOCKOP_getsockopt: /* sockfd, level, optname, optval, optlen */ - return do_getsockopt(a[0], a[1], a[2], a[3], a[4]); + case TARGET_SYS_SENDMMSG: /* sockfd, msgvec, vlen, flags */ + return do_sendrecvmmsg(a[0], a[1], a[2], a[3], 1); default: gemu_log("Unsupported socketcall: %d\n", num); - return -TARGET_ENOSYS; + return -TARGET_EINVAL; } } #endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index ca8fa6ee91..e70977169f 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -9,26 +9,28 @@ #include "syscall_nr.h" -#define SOCKOP_socket 1 -#define SOCKOP_bind 2 -#define SOCKOP_connect 3 -#define SOCKOP_listen 4 -#define SOCKOP_accept 5 -#define SOCKOP_getsockname 6 -#define SOCKOP_getpeername 7 -#define SOCKOP_socketpair 8 -#define SOCKOP_send 9 -#define SOCKOP_recv 10 -#define SOCKOP_sendto 11 -#define SOCKOP_recvfrom 12 -#define SOCKOP_shutdown 13 -#define SOCKOP_setsockopt 14 -#define SOCKOP_getsockopt 15 -#define SOCKOP_sendmsg 16 -#define SOCKOP_recvmsg 17 -#define SOCKOP_accept4 18 -#define SOCKOP_recvmmsg 19 -#define SOCKOP_sendmmsg 20 + +/* socket operations for socketcall() */ +#define TARGET_SYS_SOCKET 1 /* socket() */ +#define TARGET_SYS_BIND 2 /* bind() */ +#define TARGET_SYS_CONNECT 3 /* connect() */ +#define TARGET_SYS_LISTEN 4 /* listen() */ +#define TARGET_SYS_ACCEPT 5 /* accept() */ +#define TARGET_SYS_GETSOCKNAME 6 /* getsockname() */ +#define TARGET_SYS_GETPEERNAME 7 /* getpeername() */ +#define TARGET_SYS_SOCKETPAIR 8 /* socketpair() */ +#define TARGET_SYS_SEND 9 /* send() */ +#define TARGET_SYS_RECV 10 /* recv() */ +#define TARGET_SYS_SENDTO 11 /* sendto() */ +#define TARGET_SYS_RECVFROM 12 /* recvfrom() */ +#define TARGET_SYS_SHUTDOWN 13 /* shutdown() */ +#define TARGET_SYS_SETSOCKOPT 14 /* setsockopt() */ +#define TARGET_SYS_GETSOCKOPT 15 /* getsockopt() */ +#define TARGET_SYS_SENDMSG 16 /* sendmsg() */ +#define TARGET_SYS_RECVMSG 17 /* recvmsg() */ +#define TARGET_SYS_ACCEPT4 18 /* accept4() */ +#define TARGET_SYS_RECVMMSG 19 /* recvmmsg() */ +#define TARGET_SYS_SENDMMSG 20 /* sendmmsg() */ #define IPCOP_semop 1 #define IPCOP_semget 2 -- cgit 1.4.1 From da2c8ad7a51651b5409eca5439783c09d5863752 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Thu, 22 Sep 2016 18:56:58 +0200 Subject: linux-user: Fix syslog() syscall support There are currently several problems related to syslog() support. For example, if the second argument "bufp" of target syslog() syscall is NULL, the current implementation always returns error code EFAULT. However, NULL is a perfectly valid value for the second argument for many use cases of this syscall. This is, for example, visible from this excerpt of man page for syslog(2): > EINVAL Bad arguments (e.g., bad type; or for type 2, 3, or 4, buf is > NULL, or len is less than zero; or for type 8, the level is > outside the range 1 to 8). Moreover, the argument "bufp" is ignored for all cases of values of the first argument, except 2, 3 and 4. This means that for such cases (the first argument is not 2, 3 or 4), there is no need to pass "buf" between host and target, and it can be set to NULL while calling host's syslog(), without loss of emulation accuracy. Note also that if "bufp" is NULL and the first argument is 2, 3 or 4, the correct returned error code is EINVAL, not EFAULT. All these details are reflected in this patch. "#ifdef TARGET_NR_syslog" is also proprerly inserted when needed. Support for Qemu's "-strace" switch for syslog() syscall is included too. LTP tests syslog11 and syslog12 pass with this patch (while fail without it), on any platform. Changes to original patch by Riku Voipio: fixed error paths in TARGET_SYSLOG_ACTION_READ_ALL to match http://lxr.free-electrons.com/source/kernel/printk/printk.c?v=4.7#L1335 Should fix also the build error in: https://lists.gnu.org/archive/html/qemu-devel/2016-10/msg03721.html Signed-off-by: Aleksandar Markovic Signed-off-by: Riku Voipio --- linux-user/strace.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 2 +- linux-user/syscall.c | 50 ++++++++++++++++++++++++++++---- linux-user/syscall_defs.h | 25 ++++++++++++++++ 4 files changed, 142 insertions(+), 7 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/strace.c b/linux-user/strace.c index a0e45b55d1..679f840fea 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1827,6 +1827,78 @@ print_rt_sigprocmask(const struct syscallname *name, } #endif +#ifdef TARGET_NR_syslog +static void +print_syslog_action(abi_ulong arg, int last) +{ + const char *type; + + switch (arg) { + case TARGET_SYSLOG_ACTION_CLOSE: { + type = "SYSLOG_ACTION_CLOSE"; + break; + } + case TARGET_SYSLOG_ACTION_OPEN: { + type = "SYSLOG_ACTION_OPEN"; + break; + } + case TARGET_SYSLOG_ACTION_READ: { + type = "SYSLOG_ACTION_READ"; + break; + } + case TARGET_SYSLOG_ACTION_READ_ALL: { + type = "SYSLOG_ACTION_READ_ALL"; + break; + } + case TARGET_SYSLOG_ACTION_READ_CLEAR: { + type = "SYSLOG_ACTION_READ_CLEAR"; + break; + } + case TARGET_SYSLOG_ACTION_CLEAR: { + type = "SYSLOG_ACTION_CLEAR"; + break; + } + case TARGET_SYSLOG_ACTION_CONSOLE_OFF: { + type = "SYSLOG_ACTION_CONSOLE_OFF"; + break; + } + case TARGET_SYSLOG_ACTION_CONSOLE_ON: { + type = "SYSLOG_ACTION_CONSOLE_ON"; + break; + } + case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: { + type = "SYSLOG_ACTION_CONSOLE_LEVEL"; + break; + } + case TARGET_SYSLOG_ACTION_SIZE_UNREAD: { + type = "SYSLOG_ACTION_SIZE_UNREAD"; + break; + } + case TARGET_SYSLOG_ACTION_SIZE_BUFFER: { + type = "SYSLOG_ACTION_SIZE_BUFFER"; + break; + } + default: { + print_raw_param("%ld", arg, last); + return; + } + } + gemu_log("%s%s", type, get_comma(last)); +} + +static void +print_syslog(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_syslog_action(arg0, 0); + print_pointer(arg1, 0); + print_raw_param("%d", arg2, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_mknod static void print_mknod(const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index f6dd044d76..2c7ad2b718 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1486,7 +1486,7 @@ { TARGET_NR_sys_kexec_load, "sys_kexec_load" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_syslog -{ TARGET_NR_syslog, "syslog" , NULL, NULL, NULL }, +{ TARGET_NR_syslog, "syslog" , NULL, print_syslog, NULL }, #endif #ifdef TARGET_NR_sysmips { TARGET_NR_sysmips, "sysmips" , NULL, NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7ea23ad6ce..eb904012fa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9320,14 +9320,52 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5); break; #endif - +#if defined(TARGET_NR_syslog) case TARGET_NR_syslog: - if (!(p = lock_user_string(arg2))) - goto efault; - ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); - unlock_user(p, arg2, 0); - break; + { + int len = arg2; + switch (arg1) { + case TARGET_SYSLOG_ACTION_CLOSE: /* Close log */ + case TARGET_SYSLOG_ACTION_OPEN: /* Open log */ + case TARGET_SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ + case TARGET_SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging */ + case TARGET_SYSLOG_ACTION_CONSOLE_ON: /* Enable logging */ + case TARGET_SYSLOG_ACTION_CONSOLE_LEVEL: /* Set messages level */ + case TARGET_SYSLOG_ACTION_SIZE_UNREAD: /* Number of chars */ + case TARGET_SYSLOG_ACTION_SIZE_BUFFER: /* Size of the buffer */ + { + ret = get_errno(sys_syslog((int)arg1, NULL, (int)arg3)); + } + break; + case TARGET_SYSLOG_ACTION_READ: /* Read from log */ + case TARGET_SYSLOG_ACTION_READ_CLEAR: /* Read/clear msgs */ + case TARGET_SYSLOG_ACTION_READ_ALL: /* Read last messages */ + { + ret = -TARGET_EINVAL; + if (len < 0) { + goto fail; + } + ret = 0; + if (len == 0) { + break; + } + p = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p) { + ret = -TARGET_EFAULT; + goto fail; + } + ret = get_errno(sys_syslog((int)arg1, p, (int)arg3)); + unlock_user(p, arg2, arg3); + } + break; + default: + ret = -EINVAL; + break; + } + } + break; +#endif case TARGET_NR_setitimer: { struct itimerval value, ovalue, *pvalue; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index e70977169f..8fc316dcf5 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2682,4 +2682,29 @@ struct target_user_cap_data { uint32_t inheritable; }; +/* from kernel's include/linux/syslog.h */ + +/* Close the log. Currently a NOP. */ +#define TARGET_SYSLOG_ACTION_CLOSE 0 +/* Open the log. Currently a NOP. */ +#define TARGET_SYSLOG_ACTION_OPEN 1 +/* Read from the log. */ +#define TARGET_SYSLOG_ACTION_READ 2 +/* Read all messages remaining in the ring buffer. */ +#define TARGET_SYSLOG_ACTION_READ_ALL 3 +/* Read and clear all messages remaining in the ring buffer */ +#define TARGET_SYSLOG_ACTION_READ_CLEAR 4 +/* Clear ring buffer. */ +#define TARGET_SYSLOG_ACTION_CLEAR 5 +/* Disable printk's to console */ +#define TARGET_SYSLOG_ACTION_CONSOLE_OFF 6 +/* Enable printk's to console */ +#define TARGET_SYSLOG_ACTION_CONSOLE_ON 7 +/* Set level of messages printed to console */ +#define TARGET_SYSLOG_ACTION_CONSOLE_LEVEL 8 +/* Return number of unread characters in the log buffer */ +#define TARGET_SYSLOG_ACTION_SIZE_UNREAD 9 +/* Return size of the log buffer */ +#define TARGET_SYSLOG_ACTION_SIZE_BUFFER 10 + #endif -- cgit 1.4.1 From 2f14788c542fcdc7fc2eb4a93db7facb39c43463 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 25 Sep 2016 22:20:20 +0200 Subject: linux-user: add kcmp() syscall Signed-off-by: Laurent Vivier Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index eb904012fa..beeb23d5dc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -305,6 +305,11 @@ _syscall3(int, ioprio_set, int, which, int, who, int, ioprio) _syscall3(int, getrandom, void *, buf, size_t, buflen, unsigned int, flags) #endif +#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp) +_syscall5(int, kcmp, pid_t, pid1, pid_t, pid2, int, type, + unsigned long, idx1, unsigned long, idx2) +#endif + static bitmask_transtbl fcntl_flags_tbl[] = { { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, }, @@ -12080,6 +12085,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(unshare(arg1)); break; #endif +#if defined(TARGET_NR_kcmp) && defined(__NR_kcmp) + case TARGET_NR_kcmp: + ret = get_errno(kcmp(arg1, arg2, arg3, arg4, arg5)); + break; +#endif default: unimplemented: -- cgit 1.4.1 From 434f286bbc1570b204ac2a450d92890578594773 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 6 Oct 2016 14:55:10 +0200 Subject: linux-user: add RTA_PRIORITY in netlink Used by fedora21 on ppc64 in the network initialization Signed-off-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/syscall.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index beeb23d5dc..31143b38fe 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2600,6 +2600,7 @@ static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr) case RTA_GATEWAY: break; /* u32 */ + case RTA_PRIORITY: case RTA_OIF: u32 = RTA_DATA(rtattr); *u32 = tswap32(*u32); -- cgit 1.4.1 From 04c95f4da7f657a0bef17d115d0a5ca2ac0e2d22 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 18 Jul 2016 15:36:00 +0100 Subject: linux-user: Don't use alloca() for epoll_wait's epoll event array The epoll event array which epoll_wait() allocates has a size determined by the guest which could potentially be quite large. Use g_try_new() rather than alloca() so that we can fail more cleanly if the guest hands us an oversize value. (ENOMEM is not a documented return value for epoll_wait() but in practice some kernel configurations can return it -- see for instance sys_oabi_epoll_wait() on ARM.) This rearrangement includes fixing a bug where we were incorrectly passing a negative length to unlock_user() in the error-exit codepath. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 31143b38fe..932d0ecec3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11777,7 +11777,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto efault; } - ep = alloca(maxevents * sizeof(struct epoll_event)); + ep = g_try_new(struct epoll_event, maxevents); + if (!ep) { + unlock_user(target_ep, arg2, 0); + ret = -TARGET_ENOMEM; + break; + } switch (num) { #if defined(TARGET_NR_epoll_pwait) @@ -11795,8 +11800,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, target_set = lock_user(VERIFY_READ, arg5, sizeof(target_sigset_t), 1); if (!target_set) { - unlock_user(target_ep, arg2, 0); - goto efault; + ret = -TARGET_EFAULT; + break; } target_to_host_sigset(set, target_set); unlock_user(target_set, arg5, 0); @@ -11824,8 +11829,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, target_ep[i].events = tswap32(ep[i].events); target_ep[i].data.u64 = tswap64(ep[i].data.u64); } + unlock_user(target_ep, arg2, + ret * sizeof(struct target_epoll_event)); + } else { + unlock_user(target_ep, arg2, 0); } - unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event)); + g_free(ep); break; } #endif -- cgit 1.4.1 From 38860a0343df894a1c3371597eb4d305078642fb Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 10 Oct 2016 13:23:29 +0200 Subject: linux-user: Add support for clock_adjtime() syscall This patch implements Qemu user mode clock_adjtime() syscall support. The implementation is based on invocation of host's clock_adjtime(). Signed-off-by: Aleksandar Rikalo Signed-off-by: Aleksandar Markovic Signed-off-by: Riku Voipio --- configure | 18 ++++++++++++ linux-user/strace.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 3 ++ linux-user/syscall.c | 18 ++++++++++++ 4 files changed, 115 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/configure b/configure index dd9e6792bb..1ce3d002ed 100755 --- a/configure +++ b/configure @@ -3911,6 +3911,21 @@ if compile_prog "" "" ; then setns=yes fi +# clock_adjtime probe +clock_adjtime=no +cat > $TMPC < + +int main(void) +{ + return clock_adjtime(0, 0); +} +EOF +clock_adjtime=no +if compile_prog "" "" ; then + clock_adjtime=yes +fi + # Check if tools are available to build documentation. if test "$docs" != "no" ; then if has makeinfo && has pod2man; then @@ -5196,6 +5211,9 @@ fi if test "$setns" = "yes" ; then echo "CONFIG_SETNS=y" >> $config_host_mak fi +if test "$clock_adjtime" = "yes" ; then + echo "CONFIG_CLOCK_ADJTIME=y" >> $config_host_mak +fi if test "$inotify" = "yes" ; then echo "CONFIG_INOTIFY=y" >> $config_host_mak fi diff --git a/linux-user/strace.c b/linux-user/strace.c index 679f840fea..489dbc9583 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -435,6 +435,69 @@ print_fdset(int n, abi_ulong target_fds_addr) } #endif +#ifdef TARGET_NR_clock_adjtime +/* IDs of the various system clocks */ +#define TARGET_CLOCK_REALTIME 0 +#define TARGET_CLOCK_MONOTONIC 1 +#define TARGET_CLOCK_PROCESS_CPUTIME_ID 2 +#define TARGET_CLOCK_THREAD_CPUTIME_ID 3 +#define TARGET_CLOCK_MONOTONIC_RAW 4 +#define TARGET_CLOCK_REALTIME_COARSE 5 +#define TARGET_CLOCK_MONOTONIC_COARSE 6 +#define TARGET_CLOCK_BOOTTIME 7 +#define TARGET_CLOCK_REALTIME_ALARM 8 +#define TARGET_CLOCK_BOOTTIME_ALARM 9 +#define TARGET_CLOCK_SGI_CYCLE 10 +#define TARGET_CLOCK_TAI 11 + +static void +print_clockid(int clockid, int last) +{ + switch (clockid) { + case TARGET_CLOCK_REALTIME: + gemu_log("CLOCK_REALTIME"); + break; + case TARGET_CLOCK_MONOTONIC: + gemu_log("CLOCK_MONOTONIC"); + break; + case TARGET_CLOCK_PROCESS_CPUTIME_ID: + gemu_log("CLOCK_PROCESS_CPUTIME_ID"); + break; + case TARGET_CLOCK_THREAD_CPUTIME_ID: + gemu_log("CLOCK_THREAD_CPUTIME_ID"); + break; + case TARGET_CLOCK_MONOTONIC_RAW: + gemu_log("CLOCK_MONOTONIC_RAW"); + break; + case TARGET_CLOCK_REALTIME_COARSE: + gemu_log("CLOCK_REALTIME_COARSE"); + break; + case TARGET_CLOCK_MONOTONIC_COARSE: + gemu_log("CLOCK_MONOTONIC_COARSE"); + break; + case TARGET_CLOCK_BOOTTIME: + gemu_log("CLOCK_BOOTTIME"); + break; + case TARGET_CLOCK_REALTIME_ALARM: + gemu_log("CLOCK_REALTIME_ALARM"); + break; + case TARGET_CLOCK_BOOTTIME_ALARM: + gemu_log("CLOCK_BOOTTIME_ALARM"); + break; + case TARGET_CLOCK_SGI_CYCLE: + gemu_log("CLOCK_SGI_CYCLE"); + break; + case TARGET_CLOCK_TAI: + gemu_log("CLOCK_TAI"); + break; + default: + gemu_log("%d", clockid); + break; + } + gemu_log("%s", get_comma(last)); +} +#endif + /* * Sysycall specific output functions */ @@ -1096,6 +1159,19 @@ print_chmod(const struct syscallname *name, } #endif +#ifdef TARGET_NR_clock_adjtime +static void +print_clock_adjtime(const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_clockid(arg0, 0); + print_pointer(arg1, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_clone static void do_print_clone(unsigned int flags, abi_ulong newsp, abi_ulong parent_tidptr, target_ulong newtls, diff --git a/linux-user/strace.list b/linux-user/strace.list index 4bbe0d3ef6..dcd3812cad 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -79,6 +79,9 @@ #ifdef TARGET_NR_chroot { TARGET_NR_chroot, "chroot" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_clock_adjtime +{ TARGET_NR_clock_adjtime, "clock_adjtime" , NULL, print_clock_adjtime, NULL }, +#endif #ifdef TARGET_NR_clock_getres { TARGET_NR_clock_getres, "clock_getres" , NULL, NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 932d0ecec3..14929965ff 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -48,6 +48,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include +#include #include #include #include @@ -9681,6 +9682,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#if defined(TARGET_NR_clock_adjtime) && defined(CONFIG_CLOCK_ADJTIME) + case TARGET_NR_clock_adjtime: + { + struct timex htx, *phtx = &htx; + + if (target_to_host_timex(phtx, arg2) != 0) { + goto efault; + } + ret = get_errno(clock_adjtime(arg1, phtx)); + if (!is_error(ret) && phtx) { + if (host_to_target_timex(arg2, phtx) != 0) { + goto efault; + } + } + } + break; +#endif #ifdef TARGET_NR_create_module case TARGET_NR_create_module: #endif -- cgit 1.4.1 From 5a03cd009ae8d9c819c3f24f16695f8a334b8ad9 Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 10 Oct 2016 13:23:30 +0200 Subject: linux-user: Add support for syncfs() syscall This patch implements Qemu user mode syncfs() syscall support. Syscall syncfs() syncs the filesystem containing file determined by the open file descriptor passed as the argument to syncfs(). The implementation consists of a straightforward invocation of host's syncfs(). Configure and strace support is included as well. Signed-off-by: Aleksandar Markovic Signed-off-by: Riku Voipio --- configure | 18 ++++++++++++++++++ linux-user/strace.list | 2 +- linux-user/syscall.c | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/configure b/configure index 1ce3d002ed..d3dafcbb37 100755 --- a/configure +++ b/configure @@ -3926,6 +3926,21 @@ if compile_prog "" "" ; then clock_adjtime=yes fi +# syncfs probe +syncfs=no +cat > $TMPC < + +int main(void) +{ + return syncfs(0); +} +EOF +syncfs=no +if compile_prog "" "" ; then + syncfs=yes +fi + # Check if tools are available to build documentation. if test "$docs" != "no" ; then if has makeinfo && has pod2man; then @@ -5214,6 +5229,9 @@ fi if test "$clock_adjtime" = "yes" ; then echo "CONFIG_CLOCK_ADJTIME=y" >> $config_host_mak fi +if test "$syncfs" = "yes" ; then + echo "CONFIG_SYNCFS=y" >> $config_host_mak +fi if test "$inotify" = "yes" ; then echo "CONFIG_INOTIFY=y" >> $config_host_mak fi diff --git a/linux-user/strace.list b/linux-user/strace.list index dcd3812cad..3b1282ec1a 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1459,7 +1459,7 @@ { TARGET_NR_sync, "sync" , NULL, NULL, NULL }, #endif #ifdef TARGET_NR_syncfs -{ TARGET_NR_syncfs, "syncfs" , NULL, NULL, NULL }, +{ TARGET_NR_syncfs, "syncfs" , "%s(%d)", NULL, NULL }, #endif #ifdef TARGET_NR_syscall { TARGET_NR_syscall, "syscall" , NULL, NULL, NULL }, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 14929965ff..14c52072f9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8090,6 +8090,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, sync(); ret = 0; break; +#if defined(TARGET_NR_syncfs) && defined(CONFIG_SYNCFS) + case TARGET_NR_syncfs: + ret = get_errno(syncfs(arg1)); + break; +#endif case TARGET_NR_kill: ret = get_errno(safe_kill(arg1, target_to_host_signal(arg2))); break; -- cgit 1.4.1 From 0f26386c27d977d523c1e88410414af7739a1730 Mon Sep 17 00:00:00 2001 From: Dejan Jovicevic Date: Tue, 11 Oct 2016 11:52:46 +0200 Subject: linux-user: added support for preadv() system call. This system call performs the same task as the readv() system call, with the exception of having the fourth argument, offset, which specifes the file offset at which the input operation is to be performed. Because of this, the preadv() implementation is based on the readv() implementation in linux-user mode. But, since preadv() is implemented in the kernel as a 5-argument syscall, 5 arguments are needed to be handled as input and passed to the host syscall. The pos_l and pos_h argument of the safe_preadv() are of type unsigned long, which can be of different sizes on different platforms. The input arguments are converted to the appropriate host size when passed to safe_preadv(). Signed-off-by: Dejan Jovicevic Signed-off-by: Riku Voipio --- linux-user/syscall.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 14c52072f9..fb6eaa28fc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -918,6 +918,8 @@ safe_syscall2(int, tkill, int, tid, int, sig) safe_syscall3(int, tgkill, int, tgid, int, pid, int, sig) safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt) safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt) +safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt, + unsigned long, pos_l, unsigned long, pos_h) safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr, socklen_t, addrlen) safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, @@ -10059,6 +10061,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#if defined(TARGET_NR_preadv) + case TARGET_NR_preadv: + { + struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0); + if (vec != NULL) { + ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5)); + unlock_iovec(vec, arg2, arg3, 1); + } else { + ret = -host_to_target_errno(errno); + } + } + break; +#endif case TARGET_NR_getsid: ret = get_errno(getsid(arg1)); break; -- cgit 1.4.1 From f8d00fba27b8667c86b2277af9c2efede28c93c3 Mon Sep 17 00:00:00 2001 From: Dejan Jovicevic Date: Tue, 11 Oct 2016 11:52:47 +0200 Subject: linux-user: added support for pwritev() system call. This system call performs the same task as the writev() system call, with the exception of having the fourth argument, offset, which specifes the file offset at which the input operation is to be performed. Because of this, the pwritev() implementation is based on the writev() implementation in linux-user mode. But, since pwritev() is implemented in the kernel as a 5-argument syscall, 5 arguments are needed to be handled as input and passed to the host syscall. The pos_l and pos_h argument of the safe_pwritev() are of type unsigned long, which can be of different sizes on different platforms. The input arguments are converted to the appropriate host size when passed to safe_pwritev(). Signed-off-by: Dejan Jovicevic Signed-off-by: Riku Voipio --- linux-user/syscall.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fb6eaa28fc..db697c0bf3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -920,6 +920,8 @@ safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt) safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt) safe_syscall5(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt, unsigned long, pos_l, unsigned long, pos_h) +safe_syscall5(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt, + unsigned long, pos_l, unsigned long, pos_h) safe_syscall3(int, connect, int, fd, const struct sockaddr *, addr, socklen_t, addrlen) safe_syscall6(ssize_t, sendto, int, fd, const void *, buf, size_t, len, @@ -10073,6 +10075,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } } break; +#endif +#if defined(TARGET_NR_pwritev) + case TARGET_NR_pwritev: + { + struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1); + if (vec != NULL) { + ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5)); + unlock_iovec(vec, arg2, arg3, 0); + } else { + ret = -host_to_target_errno(errno); + } + } + break; #endif case TARGET_NR_getsid: ret = get_errno(getsid(arg1)); -- cgit 1.4.1