diff options
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r-- | linux-user/syscall.c | 215 |
1 files changed, 189 insertions, 26 deletions
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) |