modify pipe2
[qemu] / linux-user / syscall.c
index 690df14..3785e2d 100644 (file)
@@ -44,6 +44,7 @@
 #include <signal.h>
 #include <sched.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/uio.h>
 #include <sys/poll.h>
 #include <sys/times.h>
@@ -76,6 +77,7 @@
 #include <linux/soundcard.h>
 #include <linux/kd.h>
 #include <linux/mtio.h>
+#include <linux/fs.h>
 #include "linux_loop.h"
 
 #include "qemu.h"
 
 //#define DEBUG
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
-    || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
-/* 16 bit uid wrappers emulation */
-#define USE_UID16
-#endif
-
 //#include <linux/msdos_fs.h>
 #define        VFAT_IOCTL_READDIR_BOTH         _IOR('r', 1, struct linux_dirent [2])
 #define        VFAT_IOCTL_READDIR_SHORT        _IOR('r', 2, struct linux_dirent [2])
@@ -158,7 +154,6 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,   \
 }
 
 
-#define __NR_sys_exit __NR_exit
 #define __NR_sys_uname __NR_uname
 #define __NR_sys_faccessat __NR_faccessat
 #define __NR_sys_fchmodat __NR_fchmodat
@@ -201,16 +196,6 @@ static int gettid(void) {
     return -ENOSYS;
 }
 #endif
-_syscall1(int,sys_exit,int,status)
-#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
-        defined(__NR_fstatat64)
-_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
-          struct stat *,buf,int,flags)
-#endif
-#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
-_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
-         const struct timeval *,times)
-#endif
 #if TARGET_ABI_BITS == 32
 _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
 #endif
@@ -222,11 +207,6 @@ _syscall2(int, sys_getpriority, int, which, int, who);
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
 #endif
-#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
-        defined(__NR_newfstatat)
-_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
-          struct stat *,buf,int,flags)
-#endif
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
@@ -241,15 +221,6 @@ _syscall1(int,exit_group,int,error_code)
 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
 _syscall1(int,set_tid_address,int *,tidptr)
 #endif
-#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
-_syscall0(int,sys_inotify_init)
-#endif
-#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
-_syscall3(int,sys_inotify_add_watch,int,fd,const char *,pathname,uint32_t,mask)
-#endif
-#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
-_syscall2(int,sys_inotify_rm_watch,int,fd,uint32_t,wd)
-#endif
 #if defined(USE_NPTL)
 #if defined(TARGET_NR_futex) && defined(__NR_futex)
 _syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
@@ -277,8 +248,14 @@ static bitmask_transtbl fcntl_flags_tbl[] = {
   { 0, 0, 0, 0 }
 };
 
-static int
-sys_uname(struct new_utsname *buf)
+#define COPY_UTSNAME_FIELD(dest, src) \
+  do { \
+      /* __NEW_UTS_LEN doesn't include terminating null */ \
+      (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+      (dest)[__NEW_UTS_LEN] = '\0'; \
+  } while (0)
+
+static int sys_uname(struct new_utsname *buf)
 {
   struct utsname uts_buf;
 
@@ -291,13 +268,6 @@ sys_uname(struct new_utsname *buf)
    * struct linux kernel uses).
    */
 
-#define COPY_UTSNAME_FIELD(dest, src) \
-  do { \
-      /* __NEW_UTS_LEN doesn't include terminating null */ \
-      (void) strncpy((dest), (src), __NEW_UTS_LEN); \
-      (dest)[__NEW_UTS_LEN] = '\0'; \
-  } while (0)
-
   bzero(buf, sizeof (*buf));
   COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
   COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
@@ -312,26 +282,83 @@ sys_uname(struct new_utsname *buf)
 #undef COPY_UTSNAME_FIELD
 }
 
-static int
-sys_getcwd1(char *buf, size_t size)
+static int sys_getcwd1(char *buf, size_t size)
 {
   if (getcwd(buf, size) == NULL) {
       /* getcwd() sets errno */
       return (-1);
   }
-  return (0);
+  return strlen(buf)+1;
 }
 
 #ifdef CONFIG_ATFILE
-
 /*
  * Host system seems to have atfile syscall stubs available.  We
  * now enable them one by one as specified by target syscall_nr.h.
  */
 
+#ifdef TARGET_NR_faccessat
+static int sys_faccessat(int dirfd, const char *pathname, int mode)
+{
+  return (faccessat(dirfd, pathname, mode, 0));
+}
+#endif
+#ifdef TARGET_NR_fchmodat
+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)
+static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
+    gid_t group, int flags)
+{
+  return (fchownat(dirfd, pathname, owner, group, flags));
+}
+#endif
+#ifdef __NR_fstatat64
+static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+    int flags)
+{
+  return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef __NR_newfstatat
+static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
+    int flags)
+{
+  return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef TARGET_NR_futimesat
+static int sys_futimesat(int dirfd, const char *pathname,
+    const struct timeval times[2])
+{
+  return (futimesat(dirfd, pathname, times));
+}
+#endif
+#ifdef TARGET_NR_linkat
+static int sys_linkat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath, int flags)
+{
+  return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+}
+#endif
+#ifdef TARGET_NR_mkdirat
+static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+  return (mkdirat(dirfd, pathname, mode));
+}
+#endif
+#ifdef TARGET_NR_mknodat
+static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
+    dev_t dev)
+{
+  return (mknodat(dirfd, pathname, mode, dev));
+}
+#endif
 #ifdef TARGET_NR_openat
-static int
-sys_openat(int dirfd, const char *pathname, int flags, ...)
+static int sys_openat(int dirfd, const char *pathname, int flags, ...)
 {
   /*
    * open(2) has extra parameter 'mode' when called with
@@ -355,130 +382,140 @@ sys_openat(int dirfd, const char *pathname, int flags, ...)
   return (openat(dirfd, pathname, flags));
 }
 #endif
-
-#ifdef TARGET_NR_mkdirat
-static int
-sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
-{
-  return (mkdirat(dirfd, pathname, mode));
-}
-#endif
-
-#ifdef TARGET_NR_mknodat
-static int
-sys_mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev)
+#ifdef TARGET_NR_readlinkat
+static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
 {
-  return (mknodat(dirfd, pathname, mode, dev));
+  return (readlinkat(dirfd, pathname, buf, bufsiz));
 }
 #endif
-
-#ifdef TARGET_NR_fchownat
-static int
-sys_fchownat(int dirfd, const char *pathname, uid_t owner,
-    gid_t group, int flags)
+#ifdef TARGET_NR_renameat
+static int sys_renameat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath)
 {
-  return (fchownat(dirfd, pathname, owner, group, flags));
+  return (renameat(olddirfd, oldpath, newdirfd, newpath));
 }
 #endif
-
-#ifdef TARGET_NR_fstatat
-static int
-sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
-    int flags)
+#ifdef TARGET_NR_symlinkat
+static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
 {
-  return (fstatat64(dirfd, pathname, buf, flags));
+  return (symlinkat(oldpath, newdirfd, newpath));
 }
 #endif
-
 #ifdef TARGET_NR_unlinkat
-static int
-sys_unlinkat(int dirfd, const char *pathname, int flags)
+static int sys_unlinkat(int dirfd, const char *pathname, int flags)
 {
   return (unlinkat(dirfd, pathname, flags));
 }
 #endif
+#else /* !CONFIG_ATFILE */
 
-#ifdef TARGET_NR_renameat
-static int
-sys_renameat(int olddirfd, const char *oldpath,
-    int newdirfd, const char *newpath)
-{
-  return (renameat(olddirfd, oldpath, newdirfd, newpath));
-}
+/*
+ * Try direct syscalls instead
+ */
+#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
+_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
 #endif
-
-#ifdef TARGET_NR_linkat
-static int
-sys_linkat(int olddirfd, const char *oldpath,
-    int newdirfd, const char *newpath, int flags)
-{
-  return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
-}
+#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
+_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
 #endif
-
-#ifdef TARGET_NR_symlinkat
-static int
-sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
-{
-  return (symlinkat(oldpath, newdirfd, newpath));
-}
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
+_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
+          uid_t,owner,gid_t,group,int,flags)
+#endif
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+        defined(__NR_fstatat64)
+_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
+#endif
+#if defined(TARGET_NR_futimesat) && defined(__NR_futimesat)
+_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
+         const struct timeval *,times)
+#endif
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+        defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
+#endif
+#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
+_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
+      int,newdirfd,const char *,newpath,int,flags)
+#endif
+#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
+_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
+#endif
+#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
+_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
+          mode_t,mode,dev_t,dev)
+#endif
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+        defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+          struct stat *,buf,int,flags)
+#endif
+#if defined(TARGET_NR_openat) && defined(__NR_openat)
+_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
+#endif
+#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
+_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
+          char *,buf,size_t,bufsize)
+#endif
+#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
+_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
+          int,newdirfd,const char *,newpath)
+#endif
+#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
+_syscall3(int,sys_symlinkat,const char *,oldpath,
+          int,newdirfd,const char *,newpath)
+#endif
+#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
+_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 #endif
 
-#ifdef TARGET_NR_readlinkat
-static int
-sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_UTIMENSAT
+static int sys_utimensat(int dirfd, const char *pathname,
+    const struct timespec times[2], int flags)
 {
-  return (readlinkat(dirfd, pathname, buf, bufsiz));
+    if (pathname == NULL)
+        return futimens(dirfd, times);
+    else
+        return utimensat(dirfd, pathname, times, flags);
 }
+#else
+#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
+_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
+          const struct timespec *,tsp,int,flags)
 #endif
+#endif /* CONFIG_UTIMENSAT  */
 
-#ifdef TARGET_NR_fchmodat
-static int
-sys_fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
+#ifdef CONFIG_INOTIFY
+#include <sys/inotify.h>
+
+#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
+static int sys_inotify_init(void)
 {
-  return (fchmodat(dirfd, pathname, mode, flags));
+  return (inotify_init());
 }
 #endif
-
-#ifdef TARGET_NR_faccessat
-static int
-sys_faccessat(int dirfd, const char *pathname, int mode, int flags)
+#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
+static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
 {
-  return (faccessat(dirfd, pathname, mode, flags));
+  return (inotify_add_watch(fd, pathname, mask));
 }
 #endif
-
-#ifdef TARGET_NR_utimensat
-static int
-sys_utimensat(int dirfd, const char *pathname,
-    const struct timespec times[2], int flags)
+#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
+static int sys_inotify_rm_watch(int fd, int32_t wd)
 {
-  return (utimensat(dirfd, pathname, times, flags));
+  return (inotify_rm_watch(fd, wd));
 }
 #endif
-
-#else /* !CONFIG_ATFILE */
-
-/*
- * Host system doesn't have these available so we don't try
- * to implement them.
- */
-
-#undef TARGET_NR_openat
-#undef TARGET_NR_mkdirat
-#undef TARGET_NR_mknodat
-#undef TARGET_NR_fchownat
-#undef TARGET_NR_fstatat
-#undef TARGET_NR_unlinkat
-#undef TARGET_NR_renameat
-#undef TARGET_NR_linkat
-#undef TARGET_NR_symlinkat
-#undef TARGET_NR_readlinkat
-#undef TARGET_NR_fchmodat
-#undef TARGET_NR_faccessat
-#undef TARGET_NR_utimensat
-
-#endif /* CONFIG_ATFILE */
+#else
+/* Userspace can usually survive runtime without inotify */
+#undef TARGET_NR_inotify_init
+#undef TARGET_NR_inotify_add_watch
+#undef TARGET_NR_inotify_rm_watch
+#endif /* CONFIG_INOTIFY  */
 
 
 extern int personality(int);
@@ -912,17 +949,90 @@ static abi_long do_select(int n,
     return ret;
 }
 
+static abi_long do_pipe2(int host_pipe[], int flags)
+{
+#ifdef CONFIG_PIPE2
+    return pipe2(host_pipe, flags);
+#else
+    return -ENOSYS;
+#endif
+}
+
+static abi_long do_pipe(void *cpu_env, int pipedes, int flags)
+{
+    int host_pipe[2];
+    abi_long ret;
+    ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
+
+    if (is_error(ret))
+        return get_errno(ret);
+#if defined(TARGET_MIPS)
+    ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
+    ret = host_pipe[0];
+#elif defined(TARGET_SH4)
+    ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
+    ret = host_pipe[0];
+#else
+    if (put_user_s32(host_pipe[0], pipedes)
+        || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
+        return -TARGET_EFAULT;
+#endif
+    return get_errno(ret);
+}
+
+static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
+                                              abi_ulong target_addr,
+                                              socklen_t len)
+{
+    struct target_ip_mreqn *target_smreqn;
+
+    target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
+    if (!target_smreqn)
+        return -TARGET_EFAULT;
+    mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+    mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+    if (len == sizeof(struct target_ip_mreqn))
+        mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
+    unlock_user(target_smreqn, target_addr, 0);
+
+    return 0;
+}
+
 static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
                                                abi_ulong target_addr,
                                                socklen_t len)
 {
+    const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
+    sa_family_t sa_family;
     struct target_sockaddr *target_saddr;
 
     target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
     if (!target_saddr)
         return -TARGET_EFAULT;
+
+    sa_family = tswap16(target_saddr->sa_family);
+
+    /* Oops. The caller might send a incomplete sun_path; sun_path
+     * must be terminated by \0 (see the manual page), but
+     * unfortunately it is quite common to specify sockaddr_un
+     * length as "strlen(x->sun_path)" while it should be
+     * "strlen(...) + 1". We'll fix that here if needed.
+     * Linux kernel has a similar feature.
+     */
+
+    if (sa_family == AF_UNIX) {
+        if (len < unix_maxlen && len > 0) {
+            char *cp = (char*)target_saddr;
+
+            if ( cp[len-1] && !cp[len] )
+                len++;
+        }
+        if (len > unix_maxlen)
+            len = unix_maxlen;
+    }
+
     memcpy(addr, target_saddr, len);
-    addr->sa_family = tswap16(target_saddr->sa_family);
+    addr->sa_family = sa_family;
     unlock_user(target_saddr, target_addr, 0);
 
     return 0;
@@ -1063,6 +1173,8 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
 {
     abi_long ret;
     int val;
+    struct ip_mreqn *ip_mreq;
+    struct ip_mreq_source *ip_mreq_source;
 
     switch(level) {
     case SOL_TCP:
@@ -1101,6 +1213,29 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
             }
             ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
             break;
+        case IP_ADD_MEMBERSHIP:
+        case IP_DROP_MEMBERSHIP:
+            if (optlen < sizeof (struct target_ip_mreq) ||
+                optlen > sizeof (struct target_ip_mreqn))
+                return -TARGET_EINVAL;
+
+            ip_mreq = (struct ip_mreqn *) alloca(optlen);
+            target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
+            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
+            break;
+
+        case IP_BLOCK_SOURCE:
+        case IP_UNBLOCK_SOURCE:
+        case IP_ADD_SOURCE_MEMBERSHIP:
+        case IP_DROP_SOURCE_MEMBERSHIP:
+            if (optlen != sizeof (struct target_ip_mreq_source))
+                return -TARGET_EINVAL;
+
+            ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
+            ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
+            unlock_user (ip_mreq_source, optval_addr, 0);
+            break;
+
         default:
             goto unimplemented;
         }
@@ -1364,19 +1499,16 @@ static abi_long do_socket(int domain, int type, int protocol)
     return get_errno(socket(domain, type, protocol));
 }
 
-/* MAX_SOCK_ADDR from linux/net/socket.c */
-#define MAX_SOCK_ADDR  128
-
 /* do_bind() Must return target values and target errnos. */
 static abi_long do_bind(int sockfd, abi_ulong target_addr,
                         socklen_t addrlen)
 {
     void *addr;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
-    addr = alloca(addrlen);
+    addr = alloca(addrlen+1);
 
     target_to_host_sockaddr(addr, target_addr, addrlen);
     return get_errno(bind(sockfd, addr, addrlen));
@@ -1388,7 +1520,7 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr,
 {
     void *addr;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1466,7 +1598,7 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1491,7 +1623,7 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1513,10 +1645,13 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
     void *addr;
     abi_long ret;
 
+    if (target_addr == 0)
+       return get_errno(accept(fd, NULL, NULL));
+
     if (get_user_u32(addrlen, target_addrlen_addr))
         return -TARGET_EFAULT;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     addr = alloca(addrlen);
@@ -1554,7 +1689,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
     void *host_msg;
     abi_long ret;
 
-    if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+    if (addrlen < 0)
         return -TARGET_EINVAL;
 
     host_msg = lock_user(VERIFY_READ, msg, len, 1);
@@ -1589,7 +1724,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
             ret = -TARGET_EFAULT;
             goto fail;
         }
-        if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) {
+        if (addrlen < 0) {
             ret = -TARGET_EINVAL;
             goto fail;
         }
@@ -1895,14 +2030,14 @@ struct target_ipc_perm
 
 struct target_semid_ds
 {
-    struct target_ipc_perm sem_perm;
-    abi_ulong sem_otime;
-    abi_ulong __unused1;
-    abi_ulong sem_ctime;
-    abi_ulong __unused2;
-    abi_ulong sem_nsems;
-    abi_ulong __unused3;
-    abi_ulong __unused4;
+  struct target_ipc_perm sem_perm;
+  abi_ulong sem_otime;
+  abi_ulong __unused1;
+  abi_ulong sem_ctime;
+  abi_ulong __unused2;
+  abi_ulong sem_nsems;
+  abi_ulong __unused3;
+  abi_ulong __unused4;
 };
 
 static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip,
@@ -2009,17 +2144,17 @@ static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
 }
 
 union semun {
-    int val;
-    struct semid_ds *buf;
-    unsigned short *array;
-    struct seminfo *__buf;
+       int val;
+       struct semid_ds *buf;
+       unsigned short *array;
+       struct seminfo *__buf;
 };
 
 union target_semun {
-    int val;
-    abi_ulong buf;
-    abi_ulong array;
-    abi_ulong __buf;
+       int val;
+       abi_ulong buf;
+       abi_ulong array;
+       abi_ulong __buf;
 };
 
 static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
@@ -2093,53 +2228,52 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd,
     struct seminfo seminfo;
     abi_long ret = -TARGET_EINVAL;
     abi_long err;
-
     cmd &= 0xff;
 
-    switch (cmd) {
-    case IPC_STAT:
-    case IPC_SET:
-    case SEM_STAT:
-        err = target_to_host_semid_ds(&dsarg, target_su.buf);
-        if (err)
-            return err;
-        arg.buf = &dsarg;
-        ret = get_errno(semctl(semid, semnum, cmd, arg));
-        err = host_to_target_semid_ds(target_su.buf, &dsarg);
-        if (err)
-            return err;
-        break;
-    case GETVAL:
-    case SETVAL:
-        arg.val = tswapl(target_su.val);
-        ret = get_errno(semctl(semid, semnum, cmd, arg));
-        target_su.val = tswapl(arg.val);
-        break;
-    case GETALL:
-    case SETALL:
-        err = target_to_host_semarray(semid, &array, target_su.array);
-        if (err)
-            return err;
-        arg.array = array;
-        ret = get_errno(semctl(semid, semnum, cmd, arg));
-        err = host_to_target_semarray(semid, target_su.array, &array);
-        if (err)
-            return err;
-        break;
-    case IPC_INFO:
-    case SEM_INFO:
-        arg.__buf = &seminfo;
-        ret = get_errno(semctl(semid, semnum, cmd, arg));
-        err = host_to_target_seminfo(target_su.__buf, &seminfo);
-        if (err)
-            return err;
-        break;
-    case IPC_RMID:
-    case GETPID:
-    case GETNCNT:
-    case GETZCNT:
-        ret = get_errno(semctl(semid, semnum, cmd, NULL));
-        break;
+    switch( cmd ) {
+       case GETVAL:
+       case SETVAL:
+            arg.val = tswapl(target_su.val);
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            target_su.val = tswapl(arg.val);
+            break;
+       case GETALL:
+       case SETALL:
+            err = target_to_host_semarray(semid, &array, target_su.array);
+            if (err)
+                return err;
+            arg.array = array;
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            err = host_to_target_semarray(semid, target_su.array, &array);
+            if (err)
+                return err;
+            break;
+       case IPC_STAT:
+       case IPC_SET:
+       case SEM_STAT:
+            err = target_to_host_semid_ds(&dsarg, target_su.buf);
+            if (err)
+                return err;
+            arg.buf = &dsarg;
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            err = host_to_target_semid_ds(target_su.buf, &dsarg);
+            if (err)
+                return err;
+            break;
+       case IPC_INFO:
+       case SEM_INFO:
+            arg.__buf = &seminfo;
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            err = host_to_target_seminfo(target_su.__buf, &seminfo);
+            if (err)
+                return err;
+            break;
+       case IPC_RMID:
+       case GETPID:
+       case GETNCNT:
+       case GETZCNT:
+            ret = get_errno(semctl(semid, semnum, cmd, NULL));
+            break;
     }
 
     return ret;
@@ -2164,9 +2298,9 @@ static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
         return -TARGET_EFAULT;
 
     for(i=0; i<nsops; i++) {
-        __put_user(target_sembuf[i].sem_num, &host_sembuf[i].sem_num);
-        __put_user(target_sembuf[i].sem_op, &host_sembuf[i].sem_op);
-        __put_user(target_sembuf[i].sem_flg, &host_sembuf[i].sem_flg);
+        __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
+        __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
+        __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
     }
 
     unlock_user(target_sembuf, target_addr, 0);
@@ -2520,25 +2654,24 @@ static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
     return ret;
 }
 
-static inline abi_long do_shmat(int shmid, abi_ulong shmaddr, int shmflg,
-                                unsigned long *raddr)
+static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
 {
-    abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
-    abi_long ret;
+    abi_long raddr;
+    void *host_raddr;
     struct shmid_ds shm_info;
-    int i;
+    int i,ret;
 
     /* find out the length of the shared memory segment */
     ret = get_errno(shmctl(shmid, IPC_STAT, &shm_info));
     if (is_error(ret)) {
         /* can't get length, bail out */
-        return get_errno(ret);
+        return ret;
     }
 
     mmap_lock();
 
     if (shmaddr)
-        *raddr = (unsigned long) shmat(shmid, g2h(shmaddr), shmflg);
+        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
     else {
         abi_ulong mmap_start;
 
@@ -2546,31 +2679,32 @@ static inline abi_long do_shmat(int shmid, abi_ulong shmaddr, int shmflg,
 
         if (mmap_start == -1) {
             errno = ENOMEM;
-            *raddr = -1;
+            host_raddr = (void *)-1;
         } else
-            *raddr = (unsigned long) shmat(shmid, g2h(mmap_start),
-                                           shmflg | SHM_REMAP);
+            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
     }
 
-    if (*raddr == -1) {
+    if (host_raddr == (void *)-1) {
         mmap_unlock();
-        return get_errno(*raddr);
+        return get_errno((long)host_raddr);
     }
+    raddr=h2g((unsigned long)host_raddr);
 
-    page_set_flags(h2g(*raddr), h2g(*raddr) + shm_info.shm_segsz,
+    page_set_flags(raddr, raddr + shm_info.shm_segsz,
                    PAGE_VALID | PAGE_READ |
                    ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
 
     for (i = 0; i < N_SHM_REGIONS; i++) {
         if (shm_regions[i].start == 0) {
-            shm_regions[i].start = h2g(*raddr);
+            shm_regions[i].start = raddr;
             shm_regions[i].size = shm_info.shm_segsz;
             break;
         }
     }
 
     mmap_unlock();
-    return 0;
+    return raddr;
+
 }
 
 static inline abi_long do_shmdt(abi_ulong shmaddr)
@@ -2653,38 +2787,37 @@ static abi_long do_ipc(unsigned int call, int first,
     case IPCOP_shmat:
         switch (version) {
         default:
-            {
-                unsigned long raddr;
-
-                ret = do_shmat(first, ptr, second, &raddr);
-                if (ret)
-                    break;
-
-                ret = put_user_ual(raddr, third);
-                break;
-            }
+        {
+            abi_ulong raddr;
+            raddr = do_shmat(first, ptr, second);
+            if (is_error(raddr))
+                return get_errno(raddr);
+            if (put_user_ual(raddr, third))
+                return -TARGET_EFAULT;
+            break;
+        }
         case 1:
             ret = -TARGET_EINVAL;
             break;
         }
-        break;
-
+       break;
     case IPCOP_shmdt:
         ret = do_shmdt(ptr);
-        break;
+       break;
 
     case IPCOP_shmget:
-        ret = get_errno(shmget(first, second, third));
-        break;
+       /* IPC_* flag values are the same on all linux platforms */
+       ret = get_errno(shmget(first, second, third));
+       break;
 
+       /* IPC_* and SHM_* command values are the same on all linux platforms */
     case IPCOP_shmctl:
         ret = do_shmctl(first, second, third);
         break;
-
     default:
-        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-        ret = -TARGET_ENOSYS;
-        break;
+       gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
+       ret = -TARGET_ENOSYS;
+       break;
     }
     return ret;
 }
@@ -2927,6 +3060,7 @@ static void target_to_host_termios (void *dst, const void *src)
         target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
     host->c_line = target->c_line;
 
+    memset(host->c_cc, 0, sizeof(host->c_cc));
     host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
     host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
     host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
@@ -2961,6 +3095,7 @@ static void host_to_target_termios (void *dst, const void *src)
         tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
     target->c_line = host->c_line;
 
+    memset(target->c_cc, 0, sizeof(target->c_cc));
     target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
     target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
     target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
@@ -3319,6 +3454,7 @@ typedef struct {
     pthread_cond_t cond;
     pthread_t thread;
     uint32_t tid;
+    unsigned int flags;
     abi_ulong child_tidptr;
     abi_ulong parent_tidptr;
     sigset_t sigmask;
@@ -3328,10 +3464,13 @@ static void *clone_func(void *arg)
 {
     new_thread_info *info = arg;
     CPUState *env;
+    TaskState *ts;
 
     env = info->env;
     thread_env = env;
+    ts = (TaskState *)thread_env->opaque;
     info->tid = gettid();
+    task_settid(ts);
     if (info->child_tidptr)
         put_user_u32(info->tid, info->child_tidptr);
     if (info->parent_tidptr)
@@ -3383,6 +3522,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         flags &= ~(CLONE_VFORK | CLONE_VM);
 
     if (flags & CLONE_VM) {
+        TaskState *parent_ts = (TaskState *)env->opaque;
 #if defined(USE_NPTL)
         new_thread_info info;
         pthread_attr_t attr;
@@ -3395,11 +3535,16 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         /* Init regs that differ from the parent.  */
         cpu_clone_regs(new_env, newsp);
         new_env->opaque = ts;
+        ts->bprm = parent_ts->bprm;
+        ts->info = parent_ts->info;
 #if defined(USE_NPTL)
         nptl_flags = flags;
         flags &= ~CLONE_NPTL_FLAGS2;
 
-        /* TODO: Implement CLONE_CHILD_CLEARTID.  */
+        if (nptl_flags & CLONE_CHILD_CLEARTID) {
+            ts->child_tidptr = child_tidptr;
+        }
+
         if (nptl_flags & CLONE_SETTLS)
             cpu_set_tls (new_env, newtls);
 
@@ -3424,6 +3569,7 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
         sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
 
         ret = pthread_create(&info.thread, &attr, clone_func, &info);
+        /* TODO: Free new CPU state if thread creation failed.  */
 
         sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
         pthread_attr_destroy(&attr);
@@ -3474,7 +3620,8 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
             ts = (TaskState *)env->opaque;
             if (flags & CLONE_SETTLS)
                 cpu_set_tls (env, newtls);
-            /* TODO: Implement CLONE_CHILD_CLEARTID.  */
+            if (flags & CLONE_CHILD_CLEARTID)
+                ts->child_tidptr = child_tidptr;
 #endif
         } else {
             fork_end(0);
@@ -3501,7 +3648,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl.l_len = tswapl(target_fl->l_len);
         fl.l_pid = tswapl(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
-        ret = get_errno(fcntl(fd, cmd, &fl));
+        ret = get_errno(fcntl(fd, F_GETLK, &fl));
         if (ret == 0) {
             if (!lock_user_struct(VERIFY_WRITE, target_fl, arg, 0))
                 return -TARGET_EFAULT;
@@ -3524,7 +3671,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl.l_len = tswapl(target_fl->l_len);
         fl.l_pid = tswapl(target_fl->l_pid);
         unlock_user_struct(target_fl, arg, 0);
-        ret = get_errno(fcntl(fd, cmd, &fl));
+        ret = get_errno(fcntl(fd, F_SETLK+(cmd-TARGET_F_SETLK), &fl));
         break;
 
     case TARGET_F_GETLK64:
@@ -3536,7 +3683,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl64.l_len = tswapl(target_fl64->l_len);
         fl64.l_pid = tswap16(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
-        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
+        ret = get_errno(fcntl(fd, F_GETLK64, &fl64));
         if (ret == 0) {
             if (!lock_user_struct(VERIFY_WRITE, target_fl64, arg, 0))
                 return -TARGET_EFAULT;
@@ -3558,7 +3705,7 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong arg)
         fl64.l_len = tswapl(target_fl64->l_len);
         fl64.l_pid = tswap16(target_fl64->l_pid);
         unlock_user_struct(target_fl64, arg, 0);
-        ret = get_errno(fcntl(fd, cmd >> 1, &fl64));
+        ret = get_errno(fcntl(fd, F_SETLK64+(cmd-TARGET_F_SETLK64), &fl64));
         break;
 
     case F_GETFL:
@@ -3818,7 +3965,11 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
 
     /* ??? We assume FUTEX_* constants are the same on both host
        and target.  */
+#ifdef FUTEX_CMD_MASK
+    switch ((op&FUTEX_CMD_MASK)) {
+#else
     switch (op) {
+#endif
     case FUTEX_WAIT:
         if (timeout) {
             pts = &ts;
@@ -3826,17 +3977,17 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
         } else {
             pts = NULL;
         }
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val),
+        return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
                          pts, NULL, 0));
     case FUTEX_WAKE:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0));
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
     case FUTEX_FD:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0));
+        return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
     case FUTEX_REQUEUE:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val,
+        return get_errno(sys_futex(g2h(uaddr), op, val,
                          NULL, g2h(uaddr2), 0));
     case FUTEX_CMP_REQUEUE:
-        return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val,
+        return get_errno(sys_futex(g2h(uaddr), op, val,
                          NULL, g2h(uaddr2), tswap32(val3)));
     default:
         return -TARGET_ENOSYS;
@@ -3844,6 +3995,20 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
 }
 #endif
 
+/* Map host to target signal numbers for the wait family of syscalls.
+   Assume all other status bits are the same.  */
+static int host_to_target_waitstatus(int status)
+{
+    if (WIFSIGNALED(status)) {
+        return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
+    }
+    if (WIFSTOPPED(status)) {
+        return (host_to_target_signal(WSTOPSIG(status)) << 8)
+               | (status & 0xff);
+    }
+    return status;
+}
+
 int get_osversion(void)
 {
     static int osversion;
@@ -3895,12 +4060,46 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
     switch(num) {
     case TARGET_NR_exit:
+#ifdef USE_NPTL
+      /* In old applications this may be used to implement _exit(2).
+         However in threaded applictions it is used for thread termination,
+         and _exit_group is used for application termination.
+         Do thread termination if we have more then one thread.  */
+      /* FIXME: This probably breaks if a signal arrives.  We should probably
+         be disabling signals.  */
+      if (first_cpu->next_cpu) {
+          CPUState **lastp;
+          CPUState *p;
+
+          cpu_list_lock();
+          lastp = &first_cpu;
+          p = first_cpu;
+          while (p && p != (CPUState *)cpu_env) {
+              lastp = &p->next_cpu;
+              p = p->next_cpu;
+          }
+          /* If we didn't find the CPU for this thread then something is
+             horribly wrong.  */
+          if (!p)
+              abort();
+          /* Remove the CPU from the list.  */
+          *lastp = p->next_cpu;
+          cpu_list_unlock();
+          TaskState *ts = ((CPUState *)cpu_env)->opaque;
+          if (ts->child_tidptr) {
+              put_user_u32(0, ts->child_tidptr);
+              sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+                        NULL, NULL, 0);
+          }
+          /* TODO: Free CPU state.  */
+          pthread_exit(NULL);
+      }
+#endif
 #ifdef HAVE_GPROF
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
-        sys_exit(arg1);
+        _exit(arg1);
         ret = 0; /* avoid warning */
         break;
     case TARGET_NR_read:
@@ -3953,7 +4152,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             int status;
             ret = get_errno(waitpid(arg1, &status, arg3));
             if (!is_error(ret) && arg2
-                && put_user_s32(status, arg2))
+                && put_user_s32(host_to_target_waitstatus(status), arg2))
                 goto efault;
         }
         break;
@@ -4294,7 +4493,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_faccessat:
         if (!(p = lock_user_string(arg2)))
             goto efault;
-        ret = get_errno(sys_faccessat(arg1, p, arg3, arg4));
+        ret = get_errno(sys_faccessat(arg1, p, arg3));
         unlock_user(p, arg2, 0);
         break;
 #endif
@@ -4366,25 +4565,13 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(dup(arg1));
         break;
     case TARGET_NR_pipe:
-        {
-            int host_pipe[2];
-            ret = get_errno(pipe(host_pipe));
-            if (!is_error(ret)) {
-#if defined(TARGET_MIPS)
-                CPUMIPSState *env = (CPUMIPSState*)cpu_env;
-               env->active_tc.gpr[3] = host_pipe[1];
-               ret = host_pipe[0];
-#elif defined(TARGET_SH4)
-               ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
-               ret = host_pipe[0];
-#else
-                if (put_user_s32(host_pipe[0], arg1)
-                    || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0])))
-                    goto efault;
-#endif
-            }
-        }
+        ret = do_pipe(cpu_env, arg1, 0);
+        break;
+#ifdef TARGET_NR_pipe2
+    case TARGET_NR_pipe2:
+        ret = do_pipe(cpu_env, arg1, arg2);
         break;
+#endif
     case TARGET_NR_times:
         {
             struct target_tms *tmsp;
@@ -4877,13 +5064,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
     case TARGET_NR_readlink:
         {
-            void *p2;
+            void *p2, *temp;
             p = lock_user_string(arg1);
             p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
             if (!p || !p2)
                 ret = -TARGET_EFAULT;
-            else
-                ret = get_errno(readlink(path(p), p2, arg3));
+            else {
+                if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
+                    char real[PATH_MAX];
+                    temp = realpath(exec_path,real);
+                    ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
+                    snprintf((char *)p2, arg3, "%s", real);
+                    }
+                else
+                    ret = get_errno(readlink(path(p), p2, arg3));
+            }
             unlock_user(p2, arg2, ret);
             unlock_user(p, arg1, 0);
         }
@@ -5012,7 +5207,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_fchmodat:
         if (!(p = lock_user_string(arg2)))
             goto efault;
-        ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4));
+        ret = get_errno(sys_fchmodat(arg1, p, arg3));
         unlock_user(p, arg2, 0);
         break;
 #endif
@@ -5295,6 +5490,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
             if (!is_error(ret)) {
                 if (status_ptr) {
+                    status = host_to_target_waitstatus(status);
                     if (put_user_s32(status, status_ptr))
                         goto efault;
                 }
@@ -5390,13 +5586,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_shmat
     case TARGET_NR_shmat:
-        {
-            abi_long err;
-            unsigned long _ret;
-
-            err = do_shmat(arg1, arg2, arg3, &_ret);
-            ret = err ? err : _ret;
-        }
+        ret = do_shmat(arg1, arg2, arg3);
         break;
 #endif
 #ifdef TARGET_NR_shmdt
@@ -6409,7 +6599,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = get_errno(fcntl(arg1, cmd, &fl));
            break;
         default:
-            ret = do_fcntl(arg1, cmd, arg3);
+            ret = do_fcntl(arg1, arg2, arg3);
             break;
         }
        break;
@@ -6463,7 +6653,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_NR_removexattr:
     case TARGET_NR_lremovexattr:
     case TARGET_NR_fremovexattr:
-        goto unimplemented_nowarn;
+        ret = -TARGET_EOPNOTSUPP;
+        break;
 #endif
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
@@ -6560,17 +6751,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
     case TARGET_NR_utimensat:
         {
-            struct timespec ts[2];
-            target_to_host_timespec(ts, arg3);
-            target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+            struct timespec *tsp, ts[2];
+            if (!arg3) {
+                tsp = NULL;
+            } else {
+                target_to_host_timespec(ts, arg3);
+                target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+                tsp = ts;
+            }
             if (!arg2)
-                ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
+                ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
             else {
                 if (!(p = lock_user_string(arg2))) {
                     ret = -TARGET_EFAULT;
                     goto fail;
                 }
-                ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
+                ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
                 unlock_user(p, arg2, 0);
             }
         }
@@ -6581,19 +6777,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 #endif
-#ifdef TARGET_NR_inotify_init
+#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
     case TARGET_NR_inotify_init:
         ret = get_errno(sys_inotify_init());
         break;
 #endif
-#ifdef TARGET_NR_inotify_add_watch
+#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
     case TARGET_NR_inotify_add_watch:
         p = lock_user_string(arg2);
         ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
         unlock_user(p, arg2, 0);
         break;
 #endif
-#ifdef TARGET_NR_inotify_rm_watch
+#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
     case TARGET_NR_inotify_rm_watch:
         ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
         break;
@@ -6601,16 +6797,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 
 #ifdef TARGET_NR_mq_open
     case TARGET_NR_mq_open:
-    {
-        struct mq_attr posix_mq_attr;
+        {
+            struct mq_attr posix_mq_attr;
 
-        p = lock_user_string(arg1 - 1);
-        if (arg4 != 0)
-            copy_from_user_mq_attr (&posix_mq_attr, arg4);
-        ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
-        unlock_user (p, arg1, 0);
+            p = lock_user_string(arg1 - 1);
+            if (arg4 != 0)
+                copy_from_user_mq_attr (&posix_mq_attr, arg4);
+            ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr));
+            unlock_user (p, arg1, 0);
+        }
         break;
-    }
 
     case TARGET_NR_mq_unlink:
         p = lock_user_string(arg1 - 1);
@@ -6619,59 +6815,59 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 
     case TARGET_NR_mq_timedsend:
-    {
-        struct timespec ts;
+        {
+            struct timespec ts;
 
-        p = lock_user (VERIFY_READ, arg2, arg3, 1);
-        if (arg5 != 0) {
-            target_to_host_timespec(&ts, arg5);
-            ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
-            host_to_target_timespec(arg5, &ts);
+            p = lock_user (VERIFY_READ, arg2, arg3, 1);
+            if (arg5 != 0) {
+                target_to_host_timespec(&ts, arg5);
+                ret = get_errno(mq_timedsend(arg1, p, arg3, arg4, &ts));
+                host_to_target_timespec(arg5, &ts);
+            }
+            else
+                ret = get_errno(mq_send(arg1, p, arg3, arg4));
+            unlock_user (p, arg2, arg3);
         }
-        else
-            ret = get_errno(mq_send(arg1, p, arg3, arg4));
-        unlock_user (p, arg2, arg3);
         break;
-    }
 
     case TARGET_NR_mq_timedreceive:
-    {
-        struct timespec ts;
-        unsigned int prio;
+        {
+            struct timespec ts;
+            unsigned int prio;
 
-        p = lock_user (VERIFY_READ, arg2, arg3, 1);
-        if (arg5 != 0) {
-            target_to_host_timespec(&ts, arg5);
-            ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
-            host_to_target_timespec(arg5, &ts);
+            p = lock_user (VERIFY_READ, arg2, arg3, 1);
+            if (arg5 != 0) {
+                target_to_host_timespec(&ts, arg5);
+                ret = get_errno(mq_timedreceive(arg1, p, arg3, &prio, &ts));
+                host_to_target_timespec(arg5, &ts);
+            }
+            else
+                ret = get_errno(mq_receive(arg1, p, arg3, &prio));
+            unlock_user (p, arg2, arg3);
+            if (arg4 != 0)
+                put_user_u32(prio, arg4);
         }
-        else
-            ret = get_errno(mq_receive(arg1, p, arg3, &prio));
-        unlock_user (p, arg2, arg3);
-        if (arg4 != 0)
-            put_user_u32(prio, arg4);
         break;
-    }
 
     /* Not implemented for now... */
 /*     case TARGET_NR_mq_notify: */
 /*         break; */
 
     case TARGET_NR_mq_getsetattr:
-    {
-        struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
-        ret = 0;
-        if (arg3 != 0) {
-            ret = mq_getattr(arg1, &posix_mq_attr_out);
-            copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
-        }
-        if (arg2 != 0) {
-            copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
-            ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
-        }
+        {
+            struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
+            ret = 0;
+            if (arg3 != 0) {
+                ret = mq_getattr(arg1, &posix_mq_attr_out);
+                copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
+            }
+            if (arg2 != 0) {
+                copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
+                ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
+            }
 
+        }
         break;
-    }
 #endif
 
     default: