diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-06-29 16:44:13 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-06-29 16:44:13 +0100 |
commit | 4f9c5be9191fb08d16023fb6fde1f1d802ce4b44 (patch) | |
tree | 11fea0d284e6e0bbf1e20b91371c24df18c9a550 | |
parent | 4daebe014effba37246b81d25acca5fa2df82f01 (diff) | |
parent | f63eb01ac7a5b4437d5589ad4343527534bf9d0b (diff) |
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>
-rw-r--r-- | linux-user/ioctls.h | 2 | ||||
-rw-r--r-- | linux-user/socket.h | 5 | ||||
-rw-r--r-- | linux-user/strace.list | 3 | ||||
-rw-r--r-- | linux-user/syscall.c | 215 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 9 |
5 files changed, 207 insertions, 27 deletions
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 309fb21759..07a00da727 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -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))) diff --git a/linux-user/socket.h b/linux-user/socket.h index ae17959902..4dacae6127 100644 --- a/linux-user/socket.h +++ b/linux-user/socket.h @@ -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) */ diff --git a/linux-user/strace.list b/linux-user/strace.list index cf5841af60..fcb258d348 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -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 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7d7407920b..5a272d3d08 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 69c3982ee6..856302780f 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -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; |