Merge remote-tracking branch 'remotes/riku/linux-user-for-upstream' into staging

* remotes/riku/linux-user-for-upstream:
  linux-user: support the SIOCGIFINDEX ioctl
  linux-user: support the KDSIGACCEPT ioctl
  linux-user: allow NULL tv argument for settimeofday
  linux-user: respect timezone for settimeofday
  linux-user: fix struct target_epoll_event layout for MIPS
  linux-user: support strace of epoll_create1
  linux-user: allow NULL arguments to mount
  linux-user: support SO_PASSSEC setsockopt option
  linux-user: support SO_{SND, RCV}BUFFORCE setsockopt options
  linux-user: support SO_ACCEPTCONN getsockopt option
  linux-user: translate the result of getsockopt SO_TYPE
  linux-user: added fake open() for /proc/self/cmdline
  Add support for MAP_NORESERVE mmap flag.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-06-29 16:44:13 +01:00
commit 4f9c5be919
5 changed files with 207 additions and 27 deletions

View File

@ -64,6 +64,7 @@
IOCTL(KDSKBLED, 0, TYPE_INT)
IOCTL(KDGETLED, 0, TYPE_INT)
IOCTL(KDSETLED, 0, TYPE_INT)
IOCTL_SPECIAL(KDSIGACCEPT, 0, do_ioctl_kdsigaccept, TYPE_INT)
IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
@ -117,6 +118,7 @@
IOCTL(SIOCSIFMEM, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq)))
IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
IOCTL(SIOCGIFINDEX, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
IOCTL_SPECIAL(SIOCGIFCONF, IOC_W | IOC_R, do_ioctl_ifconf,
MK_PTR(MK_STRUCT(STRUCT_ifconf)))

View File

@ -63,6 +63,7 @@
#define TARGET_SO_PEERSEC 30
#define TARGET_SO_SNDBUFFORCE 31
#define TARGET_SO_RCVBUFFORCE 33
#define TARGET_SO_PASSSEC 34
/** sock_type - Socket types
*
@ -242,6 +243,10 @@
#define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
#define TARGET_SOCK_TYPE_MASK 0xf /* Covers up to TARGET_SOCK_MAX-1. */
#define TARGET_SO_PASSSEC 31
#else
#define TARGET_SO_PASSSEC 34
#endif
/* For setsockopt(2) */

View File

@ -114,6 +114,9 @@
#ifdef TARGET_NR_epoll_create
{ TARGET_NR_epoll_create, "epoll_create" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_epoll_create1
{ TARGET_NR_epoll_create1, "epoll_create1" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_epoll_ctl
{ TARGET_NR_epoll_ctl, "epoll_ctl" , NULL, NULL, NULL },
#endif

View File

@ -592,6 +592,37 @@ char *target_strerror(int err)
return strerror(target_to_host_errno(err));
}
static inline int host_to_target_sock_type(int host_type)
{
int target_type;
switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
case SOCK_DGRAM:
target_type = TARGET_SOCK_DGRAM;
break;
case SOCK_STREAM:
target_type = TARGET_SOCK_STREAM;
break;
default:
target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
break;
}
#if defined(SOCK_CLOEXEC)
if (host_type & SOCK_CLOEXEC) {
target_type |= TARGET_SOCK_CLOEXEC;
}
#endif
#if defined(SOCK_NONBLOCK)
if (host_type & SOCK_NONBLOCK) {
target_type |= TARGET_SOCK_NONBLOCK;
}
#endif
return target_type;
}
static abi_ulong target_brk;
static abi_ulong target_original_brk;
static abi_ulong brk_page;
@ -904,6 +935,23 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
return 0;
}
static inline abi_long copy_from_user_timezone(struct timezone *tz,
abi_ulong target_tz_addr)
{
struct target_timezone *target_tz;
if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
__get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
unlock_user_struct(target_tz, target_tz_addr, 0);
return 0;
}
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
#include <mqueue.h>
@ -1471,9 +1519,15 @@ set_timeout:
case TARGET_SO_SNDBUF:
optname = SO_SNDBUF;
break;
case TARGET_SO_SNDBUFFORCE:
optname = SO_SNDBUFFORCE;
break;
case TARGET_SO_RCVBUF:
optname = SO_RCVBUF;
break;
case TARGET_SO_RCVBUFFORCE:
optname = SO_RCVBUFFORCE;
break;
case TARGET_SO_KEEPALIVE:
optname = SO_KEEPALIVE;
break;
@ -1494,6 +1548,9 @@ set_timeout:
case TARGET_SO_PASSCRED:
optname = SO_PASSCRED;
break;
case TARGET_SO_PASSSEC:
optname = SO_PASSSEC;
break;
case TARGET_SO_TIMESTAMP:
optname = SO_TIMESTAMP;
break;
@ -1621,6 +1678,9 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
case TARGET_SO_RCVLOWAT:
optname = SO_RCVLOWAT;
goto int_case;
case TARGET_SO_ACCEPTCONN:
optname = SO_ACCEPTCONN;
goto int_case;
default:
goto int_case;
}
@ -1636,6 +1696,9 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
if (ret < 0)
return ret;
if (optname == SO_TYPE) {
val = host_to_target_sock_type(val);
}
if (len > lv)
len = lv;
if (len == 4) {
@ -3626,6 +3689,13 @@ static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
return ret;
}
static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, abi_long cmd, abi_long arg)
{
int sig = target_to_host_signal(arg);
return get_errno(ioctl(fd, ie->host_cmd, sig));
}
static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
@ -3908,6 +3978,8 @@ static bitmask_transtbl mmap_flags_tbl[] = {
{ TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
{ TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
{ TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
{ TARGET_MAP_NORESERVE, TARGET_MAP_NORESERVE, MAP_NORESERVE,
MAP_NORESERVE },
{ 0, 0, 0, 0 }
};
@ -4947,6 +5019,51 @@ int host_to_target_waitstatus(int status)
return status;
}
static int open_self_cmdline(void *cpu_env, int fd)
{
int fd_orig = -1;
bool word_skipped = false;
fd_orig = open("/proc/self/cmdline", O_RDONLY);
if (fd_orig < 0) {
return fd_orig;
}
while (true) {
ssize_t nb_read;
char buf[128];
char *cp_buf = buf;
nb_read = read(fd_orig, buf, sizeof(buf));
if (nb_read < 0) {
fd_orig = close(fd_orig);
return -1;
} else if (nb_read == 0) {
break;
}
if (!word_skipped) {
/* Skip the first string, which is the path to qemu-*-static
instead of the actual command. */
cp_buf = memchr(buf, 0, sizeof(buf));
if (cp_buf) {
/* Null byte found, skip one string */
cp_buf++;
nb_read -= cp_buf - buf;
word_skipped = true;
}
}
if (word_skipped) {
if (write(fd, cp_buf, nb_read) != nb_read) {
return -1;
}
}
}
return close(fd_orig);
}
static int open_self_maps(void *cpu_env, int fd)
{
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
@ -5148,6 +5265,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
{ "maps", open_self_maps, is_proc_myself },
{ "stat", open_self_stat, is_proc_myself },
{ "auxv", open_self_auxv, is_proc_myself },
{ "cmdline", open_self_cmdline, is_proc_myself },
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
{ "/proc/net/route", open_net_route, is_proc },
#endif
@ -5520,29 +5638,60 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
#endif
case TARGET_NR_mount:
{
/* need to look at the data field */
void *p2, *p3;
p = lock_user_string(arg1);
p2 = lock_user_string(arg2);
p3 = lock_user_string(arg3);
if (!p || !p2 || !p3)
ret = -TARGET_EFAULT;
else {
/* FIXME - arg5 should be locked, but it isn't clear how to
* do that since it's not guaranteed to be a NULL-terminated
* string.
*/
if ( ! arg5 )
ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL));
else
ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5)));
}
{
/* need to look at the data field */
void *p2, *p3;
if (arg1) {
p = lock_user_string(arg1);
if (!p) {
goto efault;
}
} else {
p = NULL;
}
p2 = lock_user_string(arg2);
if (!p2) {
if (arg1) {
unlock_user(p, arg1, 0);
}
goto efault;
}
if (arg3) {
p3 = lock_user_string(arg3);
if (!p3) {
if (arg1) {
unlock_user(p, arg1, 0);
unlock_user(p2, arg2, 0);
unlock_user(p3, arg3, 0);
break;
}
}
unlock_user(p2, arg2, 0);
goto efault;
}
} else {
p3 = NULL;
}
/* FIXME - arg5 should be locked, but it isn't clear how to
* do that since it's not guaranteed to be a NULL-terminated
* string.
*/
if (!arg5) {
ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
} else {
ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
}
ret = get_errno(ret);
if (arg1) {
unlock_user(p, arg1, 0);
}
unlock_user(p2, arg2, 0);
if (arg3) {
unlock_user(p3, arg3, 0);
}
}
break;
#ifdef TARGET_NR_umount
case TARGET_NR_umount:
if (!(p = lock_user_string(arg1)))
@ -6259,10 +6408,24 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
case TARGET_NR_settimeofday:
{
struct timeval tv;
if (copy_from_user_timeval(&tv, arg1))
goto efault;
ret = get_errno(settimeofday(&tv, NULL));
struct timeval tv, *ptv = NULL;
struct timezone tz, *ptz = NULL;
if (arg1) {
if (copy_from_user_timeval(&tv, arg1)) {
goto efault;
}
ptv = &tv;
}
if (arg2) {
if (copy_from_user_timezone(&tz, arg2)) {
goto efault;
}
ptz = &tz;
}
ret = get_errno(settimeofday(ptv, ptz));
}
break;
#if defined(TARGET_NR_select)

View File

@ -165,6 +165,11 @@ struct target_timespec {
abi_long tv_nsec;
};
struct target_timezone {
abi_int tz_minuteswest;
abi_int tz_dsttime;
};
struct target_itimerval {
struct target_timeval it_interval;
struct target_timeval it_value;
@ -826,6 +831,7 @@ struct target_pollfd {
#define TARGET_KDSKBLED 0x4B65 /* set led flags (not lights) */
#define TARGET_KDGETLED 0x4B31 /* return current led state */
#define TARGET_KDSETLED 0x4B32 /* set led state [lights, not flags] */
#define TARGET_KDSIGACCEPT 0x4B4E
#define TARGET_SIOCATMARK 0x8905
@ -859,6 +865,7 @@ struct target_pollfd {
#define TARGET_SIOCSIFSLAVE 0x8930
#define TARGET_SIOCADDMULTI 0x8931 /* Multicast address lists */
#define TARGET_SIOCDELMULTI 0x8932
#define TARGET_SIOCGIFINDEX 0x8933
/* Bridging control calls */
#define TARGET_SIOCGIFBR 0x8940 /* Bridging support */
@ -2528,7 +2535,7 @@ typedef union target_epoll_data {
struct target_epoll_event {
uint32_t events;
#ifdef TARGET_ARM
#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_MIPS64)
uint32_t __pad;
#endif
target_epoll_data_t data;