summaryrefslogtreecommitdiff
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c167
1 files changed, 139 insertions, 28 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index bb0999d1a..279cef3cd 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -59,6 +59,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
//#include <sys/user.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
+#include <linux/wireless.h>
#include <qemu-common.h>
#ifdef TARGET_GPROF
#include <sys/gmon.h>
@@ -196,7 +197,8 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
-#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
+#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__) || \
+ defined(__s390x__)
#define __NR__llseek __NR_lseek
#endif
@@ -326,7 +328,7 @@ static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
return (fchmodat(dirfd, pathname, mode, 0));
}
#endif
-#if defined(TARGET_NR_fchownat) && defined(USE_UID16)
+#if defined(TARGET_NR_fchownat)
static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
gid_t group, int flags)
{
@@ -435,7 +437,7 @@ _syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
#endif
-#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
uid_t,owner,gid_t,group,int,flags)
#endif
@@ -2970,7 +2972,6 @@ static abi_long do_ipc(unsigned int call, int first,
#endif
/* kernel structure types definitions */
-#define IFNAMSIZ 16
#define STRUCT(name, ...) STRUCT_ ## name,
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
@@ -3095,6 +3096,100 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
}
#endif
+static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
+ int fd, abi_long cmd, abi_long arg)
+{
+ const argtype *arg_type = ie->arg_type;
+ int target_size;
+ void *argptr;
+ int ret;
+ struct ifconf *host_ifconf;
+ uint32_t outbufsz;
+ const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
+ int target_ifreq_size;
+ int nb_ifreq;
+ int free_buf = 0;
+ int i;
+ int target_ifc_len;
+ abi_long target_ifc_buf;
+ int host_ifc_len;
+ char *host_ifc_buf;
+
+ assert(arg_type[0] == TYPE_PTR);
+ assert(ie->access == IOC_RW);
+
+ arg_type++;
+ target_size = thunk_type_size(arg_type, 0);
+
+ argptr = lock_user(VERIFY_READ, arg, target_size, 1);
+ if (!argptr)
+ return -TARGET_EFAULT;
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+
+ host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
+ target_ifc_len = host_ifconf->ifc_len;
+ target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
+
+ target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
+ nb_ifreq = target_ifc_len / target_ifreq_size;
+ host_ifc_len = nb_ifreq * sizeof(struct ifreq);
+
+ outbufsz = sizeof(*host_ifconf) + host_ifc_len;
+ if (outbufsz > MAX_STRUCT_SIZE) {
+ /* We can't fit all the extents into the fixed size buffer.
+ * Allocate one that is large enough and use it instead.
+ */
+ host_ifconf = malloc(outbufsz);
+ if (!host_ifconf) {
+ return -TARGET_ENOMEM;
+ }
+ memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
+ free_buf = 1;
+ }
+ host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
+
+ host_ifconf->ifc_len = host_ifc_len;
+ host_ifconf->ifc_buf = host_ifc_buf;
+
+ ret = get_errno(ioctl(fd, ie->host_cmd, host_ifconf));
+ if (!is_error(ret)) {
+ /* convert host ifc_len to target ifc_len */
+
+ nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
+ target_ifc_len = nb_ifreq * target_ifreq_size;
+ host_ifconf->ifc_len = target_ifc_len;
+
+ /* restore target ifc_buf */
+
+ host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
+
+ /* copy struct ifconf to target user */
+
+ argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
+ if (!argptr)
+ return -TARGET_EFAULT;
+ thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+
+ /* copy ifreq[] to target user */
+
+ argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
+ for (i = 0; i < nb_ifreq ; i++) {
+ thunk_convert(argptr + i * target_ifreq_size,
+ host_ifc_buf + i * sizeof(struct ifreq),
+ ifreq_arg_type, THUNK_TARGET);
+ }
+ unlock_user(argptr, target_ifc_buf, target_ifc_len);
+ }
+
+ if (free_buf) {
+ free(host_ifconf);
+ }
+
+ return ret;
+}
+
static IOCTLEntry ioctl_entries[] = {
#define IOCTL(cmd, access, ...) \
{ TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } },
@@ -3690,9 +3785,9 @@ static abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
#endif /* defined(TARGET_I386) */
-#if defined(CONFIG_USE_NPTL)
+#define NEW_STACK_SIZE 0x40000
-#define NEW_STACK_SIZE PTHREAD_STACK_MIN
+#if defined(CONFIG_USE_NPTL)
static pthread_mutex_t clone_lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct {
@@ -3736,9 +3831,6 @@ static void *clone_func(void *arg)
return NULL;
}
#else
-/* this stack is the equivalent of the kernel stack associated with a
- thread/process */
-#define NEW_STACK_SIZE 8192
static int clone_func(void *arg)
{
@@ -4072,7 +4164,31 @@ static inline int low2highgid(int gid)
else
return gid;
}
-
+static inline int tswapid(int id)
+{
+ return tswap16(id);
+}
+#else /* !USE_UID16 */
+static inline int high2lowuid(int uid)
+{
+ return uid;
+}
+static inline int high2lowgid(int gid)
+{
+ return gid;
+}
+static inline int low2highuid(int uid)
+{
+ return uid;
+}
+static inline int low2highgid(int gid)
+{
+ return gid;
+}
+static inline int tswapid(int id)
+{
+ return tswap32(id);
+}
#endif /* USE_UID16 */
void syscall_init(void)
@@ -6384,20 +6500,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(sys_sched_getaffinity(arg1, mask_size, mask));
if (!is_error(ret)) {
- if (arg2 > ret) {
- /* Zero out any extra space kernel didn't fill */
- unsigned long zero = arg2 - ret;
- p = alloca(zero);
- memset(p, 0, zero);
- if (copy_to_user(arg3 + zero, p, zero)) {
- goto efault;
- }
- arg2 = ret;
- }
- if (copy_to_user(arg3, mask, arg2)) {
+ if (copy_to_user(arg3, mask, ret)) {
goto efault;
}
- ret = arg2;
}
}
break;
@@ -6673,25 +6778,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = host_to_target_stat64(cpu_env, arg3, &st);
break;
#endif
-#ifdef USE_UID16
case TARGET_NR_lchown:
if (!(p = lock_user_string(arg1)))
goto efault;
ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
unlock_user(p, arg1, 0);
break;
+#ifdef TARGET_NR_getuid
case TARGET_NR_getuid:
ret = get_errno(high2lowuid(getuid()));
break;
+#endif
+#ifdef TARGET_NR_getgid
case TARGET_NR_getgid:
ret = get_errno(high2lowgid(getgid()));
break;
+#endif
+#ifdef TARGET_NR_geteuid
case TARGET_NR_geteuid:
ret = get_errno(high2lowuid(geteuid()));
break;
+#endif
+#ifdef TARGET_NR_getegid
case TARGET_NR_getegid:
ret = get_errno(high2lowgid(getegid()));
break;
+#endif
case TARGET_NR_setreuid:
ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
break;
@@ -6701,7 +6813,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_getgroups:
{
int gidsetsize = arg1;
- uint16_t *target_grouplist;
+ target_id *target_grouplist;
gid_t *grouplist;
int i;
@@ -6714,7 +6826,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!target_grouplist)
goto efault;
for(i = 0;i < ret; i++)
- target_grouplist[i] = tswap16(grouplist[i]);
+ target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
unlock_user(target_grouplist, arg2, gidsetsize * 2);
}
}
@@ -6722,7 +6834,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_setgroups:
{
int gidsetsize = arg1;
- uint16_t *target_grouplist;
+ target_id *target_grouplist;
gid_t *grouplist;
int i;
@@ -6733,7 +6845,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
goto fail;
}
for(i = 0;i < gidsetsize; i++)
- grouplist[i] = tswap16(target_grouplist[i]);
+ grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
unlock_user(target_grouplist, arg2, 0);
ret = get_errno(setgroups(gidsetsize, grouplist));
}
@@ -6809,7 +6921,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_setfsgid:
ret = get_errno(setfsgid(arg1));
break;
-#endif /* USE_UID16 */
#ifdef TARGET_NR_lchown32
case TARGET_NR_lchown32: