All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/10] misc userland patches [v2]
@ 2009-04-05 20:59 riku.voipio
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 01/10] Fix fstatat64()/newfstatat() syscall implementation riku.voipio
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@iki.fi>

Resending, now all patches should be independent (with
the exception of 0003 which depends on 0004). The guest-base
patches are left from the series as Mika is still writing
the strace code to be implemented more in the way real
strace is done.

Kirill A. Shutemov (2):
  Fix fstatat64()/newfstatat() syscall implementation
  Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit
    targets

Lionel Landwerlin (1):
  Added posix message queue syscalls except mq_notify

Mika Westerberg (1):
  linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket
    syscalls
  Add support for passing contents of argv0

Riku Voipio (6):
  fix IPCOP_sem* and implement sem*
  Implement shm* syscalls and fix 64/32bit errors
  linux-user: unix sockets - fix running dbus
  Prefer glibc over direct syscalls
  linux-user: Proper exit code for uncaught signals

 configure                 |   53 +++
 linux-user/main.c         |   38 ++-
 linux-user/mmap.c         |   81 ++--
 linux-user/qemu.h         |    1 +
 linux-user/signal.c       |   37 +-
 linux-user/strace.list    |   12 +-
 linux-user/syscall.c      | 1077 ++++++++++++++++++++++++++++++++++++---------
 linux-user/syscall_defs.h |    7 +
 8 files changed, 1031 insertions(+), 275 deletions(-)

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 01/10] Fix fstatat64()/newfstatat() syscall implementation
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets riku.voipio
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Kirill A. Shutemov <kirill@shutemov.name>

There are two different syscall names for the same goal.

On systems with sizeof(long) == 64 it calls newfstatat.
On systems with sizeof(long) == 32 it calls fstatat64.

From: Kirill A. Shutemov <kirill@shutemov.name>

Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/syscall.c |   29 +++++++++++++++++++++++++----
 1 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 226ee6c..16cf89c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -169,6 +169,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,	\
 #define __NR_sys_linkat __NR_linkat
 #define __NR_sys_mkdirat __NR_mkdirat
 #define __NR_sys_mknodat __NR_mknodat
+#define __NR_sys_newfstatat __NR_newfstatat
 #define __NR_sys_openat __NR_openat
 #define __NR_sys_readlinkat __NR_readlinkat
 #define __NR_sys_renameat __NR_renameat
@@ -209,7 +210,8 @@ _syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
 _syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
           uid_t,owner,gid_t,group,int,flags)
 #endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#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
@@ -240,6 +242,11 @@ _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
 _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
@@ -3280,7 +3287,7 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
     return 0;
 }
 
-#ifdef TARGET_NR_stat64
+#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
 static inline abi_long host_to_target_stat64(void *cpu_env,
                                              abi_ulong target_addr,
                                              struct stat *host_st)
@@ -3312,11 +3319,15 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
     } else
 #endif
     {
+#if TARGET_LONG_BITS == 64
+        struct target_stat *target_st;
+#else
         struct target_stat64 *target_st;
+#endif
 
         if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
             return -TARGET_EFAULT;
-        memset(target_st, 0, sizeof(struct target_stat64));
+        memset(target_st, 0, sizeof(*target_st));
         __put_user(host_st->st_dev, &target_st->st_dev);
         __put_user(host_st->st_ino, &target_st->st_ino);
 #ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
@@ -5459,11 +5470,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             ret = host_to_target_stat64(cpu_env, arg2, &st);
         break;
 #endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+        (defined(__NR_fstatat64) || defined(__NR_newfstatat))
+#ifdef TARGET_NR_fstatat64
     case TARGET_NR_fstatat64:
+#endif
+#ifdef TARGET_NR_newfstatat
+    case TARGET_NR_newfstatat:
+#endif
         if (!(p = lock_user_string(arg2)))
             goto efault;
+#ifdef __NR_fstatat64
         ret = get_errno(sys_fstatat64(arg1, path(p), &st, arg4));
+#else
+        ret = get_errno(sys_newfstatat(arg1, path(p), &st, arg4));
+#endif
         if (!is_error(ret))
             ret = host_to_target_stat64(cpu_env, arg3, &st);
         break;
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 01/10] Fix fstatat64()/newfstatat() syscall implementation riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-05 20:59   ` [Qemu-devel] [PATCH 03/10] Implement shm* syscalls and fix 64/32bit errors riku.voipio
  2009-04-15 16:21   ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem* riku.voipio
                   ` (6 subsequent siblings)
  8 siblings, 2 replies; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Kirill A. Shutemov <kirill@shutemov.name>

qemu's page table can be incomple if /proc/self/maps is unavailable or
host allocating a memory with mmap(), so we can't use it to find free
memory area.

New version mmap_find_vma() uses mmap() without MAP_FIXED to find free
memory.

From: Kirill A. Shutemov <kirill@shutemov.name>

Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/mmap.c |   81 ++++++++++++++++++++++++++++------------------------
 linux-user/qemu.h |    1 +
 2 files changed, 45 insertions(+), 37 deletions(-)

diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index 6f300a0..8cec230 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -275,52 +275,59 @@ static abi_ulong mmap_next_start = 0x40000000;
 
 unsigned long last_brk;
 
-/* find a free memory area of size 'size'. The search starts at
-   'start'. If 'start' == 0, then a default start address is used.
-   Return -1 if error.
-*/
-/* page_init() marks pages used by the host as reserved to be sure not
-   to use them. */
-static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
+/*
+ * Find and reserve a free memory area of size 'size'. The search
+ * starts at 'start'.
+ * It must be called with mmap_lock() held.
+ * Return -1 if error.
+ */
+abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
 {
-    abi_ulong addr, addr1, addr_start;
-    int prot;
-    unsigned long new_brk;
-
-    new_brk = (unsigned long)sbrk(0);
-    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
-        /* This is a hack to catch the host allocating memory with brk().
-           If it uses mmap then we loose.
-           FIXME: We really want to avoid the host allocating memory in
-           the first place, and maybe leave some slack to avoid switching
-           to mmap.  */
-        page_set_flags(last_brk & TARGET_PAGE_MASK,
-                       TARGET_PAGE_ALIGN(new_brk),
-                       PAGE_RESERVED); 
-    }
-    last_brk = new_brk;
+    void *ptr;
+    abi_ulong addr;
 
     size = HOST_PAGE_ALIGN(size);
-    start = start & qemu_host_page_mask;
+    start &= qemu_host_page_mask;
+
+    /* If 'start' == 0, then a default start address is used. */
+    if (start == 0)
+        start = mmap_next_start;
+
     addr = start;
-    if (addr == 0)
-        addr = mmap_next_start;
-    addr_start = addr;
+
     for(;;) {
-        prot = 0;
-        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
-            prot |= page_get_flags(addr1);
-        }
-        if (prot == 0)
+        /*
+         * Reserve needed memory area to avoid a race.
+         * It should be discarded using:
+         *  - mmap() with MAP_FIXED flag
+         *  - mremap() with MREMAP_FIXED flag
+         *  - shmat() with SHM_REMAP flag
+         */
+        ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
+                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
+
+        /* ENOMEM, if host address space has no memory */
+        if (ptr == MAP_FAILED)
+            return (abi_ulong)-1;
+
+        /* If address fits target address space we've found what we need */
+        if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
             break;
+
+        /* Unmap and try again with new page */
+        munmap(ptr, size);
         addr += qemu_host_page_size;
-        /* we found nothing */
-        if (addr == addr_start)
+
+        /* ENOMEM if we check whole of target address space */
+        if (addr == start)
             return (abi_ulong)-1;
     }
-    if (start == 0)
-        mmap_next_start = addr + size;
-    return addr;
+
+    /* Update default start address */
+    if (start == mmap_next_start)
+        mmap_next_start = (unsigned long)ptr + size;
+
+    return h2g(ptr);
 }
 
 /* NOTE: all the constants are the HOST ones */
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 94ae333..2bef14a 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -228,6 +228,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
 extern unsigned long last_brk;
 void mmap_lock(void);
 void mmap_unlock(void);
+abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
 void cpu_list_lock(void);
 void cpu_list_unlock(void);
 #if defined(USE_NPTL)
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 03/10] Implement shm* syscalls and fix 64/32bit errors
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets riku.voipio
@ 2009-04-05 20:59   ` riku.voipio
  2009-04-15 16:21   ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets Aurelien Jarno
  1 sibling, 0 replies; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@iki.fi>

Verified with ltp shm* tests. Following test still
fails

shmt09      3  FAIL

No regressions were observed on either 64bit or 32bit
IA hosts.

Patch based on original patches by:
Kirill A. Shutemov <kirill@shutemov.name>

  - Implement shm* syscalls
  - Fix and cleanup IPCOP_shm* ipc calls handling

This patch depends on "Rewrite mmap_find_vma()" patch.

Various whitespace uglifications applied to minimize
patch size.

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/syscall.c |  299 +++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 250 insertions(+), 49 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ddcc656..88ed46c 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1652,14 +1652,12 @@ static abi_long do_socketcall(int num, abi_ulong vptr)
 }
 #endif
 
-#ifdef TARGET_NR_ipc
 #define N_SHM_REGIONS	32
 
 static struct shm_region {
     abi_ulong	start;
     abi_ulong	size;
 } shm_regions[N_SHM_REGIONS];
-#endif
 
 struct target_ipc_perm
 {
@@ -2152,6 +2150,224 @@ end:
     return ret;
 }
 
+struct target_shmid_ds
+{
+    struct target_ipc_perm shm_perm;
+    abi_ulong shm_segsz;
+    abi_ulong shm_atime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused1;
+#endif
+    abi_ulong shm_dtime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused2;
+#endif
+    abi_ulong shm_ctime;
+#if TARGET_ABI_BITS == 32
+    abi_ulong __unused3;
+#endif
+    int shm_cpid;
+    int shm_lpid;
+    abi_ulong shm_nattch;
+    unsigned long int __unused4;
+    unsigned long int __unused5;
+};
+
+static inline abi_long target_to_host_shmid_ds(struct shmid_ds *host_sd,
+                                               abi_ulong target_addr)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
+        return -TARGET_EFAULT;
+    if (target_to_host_ipc_perm(&(host_sd->shm_perm), target_addr))
+        return -TARGET_EFAULT;
+    __put_user(target_sd->shm_segsz, &host_sd->shm_segsz);
+    __put_user(target_sd->shm_atime, &host_sd->shm_atime);
+    __put_user(target_sd->shm_dtime, &host_sd->shm_dtime);
+    __put_user(target_sd->shm_ctime, &host_sd->shm_ctime);
+    __put_user(target_sd->shm_cpid, &host_sd->shm_cpid);
+    __put_user(target_sd->shm_lpid, &host_sd->shm_lpid);
+    __put_user(target_sd->shm_nattch, &host_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 0);
+    return 0;
+}
+
+static inline abi_long host_to_target_shmid_ds(abi_ulong target_addr,
+                                               struct shmid_ds *host_sd)
+{
+    struct target_shmid_ds *target_sd;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
+        return -TARGET_EFAULT;
+    if (host_to_target_ipc_perm(target_addr, &(host_sd->shm_perm)))
+        return -TARGET_EFAULT;
+    __put_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+    __put_user(host_sd->shm_atime, &target_sd->shm_atime);
+    __put_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+    __put_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+    __put_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+    __put_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+    __put_user(host_sd->shm_nattch, &target_sd->shm_nattch);
+    unlock_user_struct(target_sd, target_addr, 1);
+    return 0;
+}
+
+struct  target_shminfo {
+    abi_ulong shmmax;
+    abi_ulong shmmin;
+    abi_ulong shmmni;
+    abi_ulong shmseg;
+    abi_ulong shmall;
+};
+
+static inline abi_long host_to_target_shminfo(abi_ulong target_addr,
+                                              struct shminfo *host_shminfo)
+{
+    struct target_shminfo *target_shminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_shminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shminfo->shmmax, &target_shminfo->shmmax);
+    __put_user(host_shminfo->shmmin, &target_shminfo->shmmin);
+    __put_user(host_shminfo->shmmni, &target_shminfo->shmmni);
+    __put_user(host_shminfo->shmseg, &target_shminfo->shmseg);
+    __put_user(host_shminfo->shmall, &target_shminfo->shmall);
+    unlock_user_struct(target_shminfo, target_addr, 1);
+    return 0;
+}
+
+struct target_shm_info {
+    int used_ids;
+    abi_ulong shm_tot;
+    abi_ulong shm_rss;
+    abi_ulong shm_swp;
+    abi_ulong swap_attempts;
+    abi_ulong swap_successes;
+};
+
+static inline abi_long host_to_target_shm_info(abi_ulong target_addr,
+                                               struct shm_info *host_shm_info)
+{
+    struct target_shm_info *target_shm_info;
+    if (!lock_user_struct(VERIFY_WRITE, target_shm_info, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_shm_info->used_ids, &target_shm_info->used_ids);
+    __put_user(host_shm_info->shm_tot, &target_shm_info->shm_tot);
+    __put_user(host_shm_info->shm_rss, &target_shm_info->shm_rss);
+    __put_user(host_shm_info->shm_swp, &target_shm_info->shm_swp);
+    __put_user(host_shm_info->swap_attempts, &target_shm_info->swap_attempts);
+    __put_user(host_shm_info->swap_successes, &target_shm_info->swap_successes);
+    unlock_user_struct(target_shm_info, target_addr, 1);
+    return 0;
+}
+
+static inline abi_long do_shmctl(int shmid, int cmd, abi_long buf)
+{
+    struct shmid_ds dsarg;
+    struct shminfo shminfo;
+    struct shm_info shm_info;
+    abi_long ret = -TARGET_EINVAL;
+
+    cmd &= 0xff;
+
+    switch(cmd) {
+    case IPC_STAT:
+    case IPC_SET:
+    case SHM_STAT:
+        if (target_to_host_shmid_ds(&dsarg, buf))
+            return -TARGET_EFAULT;
+        ret = get_errno(shmctl(shmid, cmd, &dsarg));
+        if (host_to_target_shmid_ds(buf, &dsarg))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shminfo));
+        if (host_to_target_shminfo(buf, &shminfo))
+            return -TARGET_EFAULT;
+        break;
+    case SHM_INFO:
+        ret = get_errno(shmctl(shmid, cmd, (struct shmid_ds *)&shm_info));
+        if (host_to_target_shm_info(buf, &shm_info))
+            return -TARGET_EFAULT;
+        break;
+    case IPC_RMID:
+    case SHM_LOCK:
+    case SHM_UNLOCK:
+        ret = get_errno(shmctl(shmid, cmd, NULL));
+        break;
+    }
+
+    return ret;
+}
+
+static inline abi_ulong do_shmat(int shmid, abi_ulong shmaddr, int shmflg)
+{
+    abi_long raddr;
+    void *host_raddr;
+    struct shmid_ds shm_info;
+    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 ret;
+    }
+
+    mmap_lock();
+
+    if (shmaddr)
+        host_raddr = shmat(shmid, (void *)g2h(shmaddr), shmflg);
+    else {
+        abi_ulong mmap_start;
+
+        mmap_start = mmap_find_vma(0, shm_info.shm_segsz);
+
+        if (mmap_start == -1) {
+            errno = ENOMEM;
+            host_raddr = (void *)-1;
+        } else
+            host_raddr = shmat(shmid, g2h(mmap_start), shmflg | SHM_REMAP);
+    }
+
+    if (host_raddr == (void *)-1) {
+        mmap_unlock();
+        return get_errno((long)host_raddr);
+    }
+    raddr=h2g((unsigned long)host_raddr);
+
+    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 = raddr;
+            shm_regions[i].size = shm_info.shm_segsz;
+            break;
+        }
+    }
+
+    mmap_unlock();
+    return raddr;
+
+}
+
+static inline abi_long do_shmdt(abi_ulong shmaddr)
+{
+    int i;
+
+    for (i = 0; i < N_SHM_REGIONS; ++i) {
+        if (shm_regions[i].start == shmaddr) {
+            shm_regions[i].start = 0;
+            page_set_flags(shmaddr, shm_regions[i].size, 0);
+            break;
+        }
+    }
+
+    return get_errno(shmdt(g2h(shmaddr)));
+}
+
 #ifdef TARGET_NR_ipc
 /* ??? This only works with linear mappings.  */
 /* do_ipc() must return target values and target errnos. */
@@ -2161,8 +2377,6 @@ static abi_long do_ipc(unsigned int call, int first,
 {
     int version;
     abi_long ret = 0;
-    struct shmid_ds shm_info;
-    int i;
 
     version = call >> 16;
     call &= 0xffff;
@@ -2217,48 +2431,24 @@ static abi_long do_ipc(unsigned int call, int first,
         break;
 
     case IPCOP_shmat:
+        switch (version) {
+        default:
         {
             abi_ulong raddr;
-            void *host_addr;
-            /* SHM_* flags are the same on all linux platforms */
-            host_addr = shmat(first, (void *)g2h(ptr), second);
-            if (host_addr == (void *)-1) {
-                ret = get_errno((long)host_addr);
-                break;
-            }
-            raddr = h2g((unsigned long)host_addr);
-            /* find out the length of the shared memory segment */
-            
-            ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
-            if (is_error(ret)) {
-                /* can't get length, bail out */
-                shmdt(host_addr);
-                break;
-            }
-            page_set_flags(raddr, raddr + shm_info.shm_segsz,
-                           PAGE_VALID | PAGE_READ |
-                           ((second & SHM_RDONLY)? 0: PAGE_WRITE));
-            for (i = 0; i < N_SHM_REGIONS; ++i) {
-                if (shm_regions[i].start == 0) {
-                    shm_regions[i].start = raddr;
-                    shm_regions[i].size = shm_info.shm_segsz;
-                    break;
-                }
-            }
+            raddr = do_shmat(first, ptr, second);
+            if (is_error(raddr))
+                return get_errno(raddr);
             if (put_user_ual(raddr, third))
                 return -TARGET_EFAULT;
-            ret = 0;
+            break;
+        }
+        case 1:
+            ret = -TARGET_EINVAL;
+            break;
         }
 	break;
     case IPCOP_shmdt:
-	for (i = 0; i < N_SHM_REGIONS; ++i) {
-	    if (shm_regions[i].start == ptr) {
-		shm_regions[i].start = 0;
-		page_set_flags(ptr, shm_regions[i].size, 0);
-		break;
-	    }
-	}
-	ret = get_errno(shmdt((void *)g2h(ptr)));
+        ret = do_shmdt(ptr);
 	break;
 
     case IPCOP_shmget:
@@ -2268,18 +2458,9 @@ static abi_long do_ipc(unsigned int call, int first,
 
 	/* IPC_* and SHM_* command values are the same on all linux platforms */
     case IPCOP_shmctl:
-        switch(second) {
-        case IPC_RMID:
-        case SHM_LOCK:
-        case SHM_UNLOCK:
-            ret = get_errno(shmctl(first, second, NULL));
-            break;
-        default:
-            goto unimplemented;
-        }
+        ret = do_shmctl(first, second, third);
         break;
     default:
-    unimplemented:
 	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
 	ret = -TARGET_ENOSYS;
 	break;
@@ -5043,6 +5224,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_msgsnd(arg1, arg2, arg3, arg4);
         break;
 #endif
+#ifdef TARGET_NR_shmget
+    case TARGET_NR_shmget:
+        ret = get_errno(shmget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_shmctl
+    case TARGET_NR_shmctl:
+        ret = do_shmctl(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmat
+    case TARGET_NR_shmat:
+        ret = do_shmat(arg1, arg2, arg3);
+        break;
+#endif
+#ifdef TARGET_NR_shmdt
+    case TARGET_NR_shmdt:
+        ret = do_shmdt(arg1);
+        break;
+#endif
     case TARGET_NR_fsync:
         ret = get_errno(fsync(arg1));
         break;
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 01/10] Fix fstatat64()/newfstatat() syscall implementation riku.voipio
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-06  9:06   ` Arnaud Patard
  2009-04-15 15:28   ` Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 05/10] Added posix message queue syscalls except mq_notify riku.voipio
                   ` (5 subsequent siblings)
  8 siblings, 2 replies; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@iki.fi>

From: Kirill A. Shutemov <kirill@shutemov.name>

Fix and cleanup IPCOP_sem* ipc calls handling and
implement sem* syscalls.

Uglify whitespace so that diff gets smaller and easier
to review - Riku

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/syscall.c |  286 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 188 insertions(+), 98 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 16cf89c..ddcc656 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1733,7 +1733,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
 
     if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
         return -TARGET_EFAULT;
-    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
+        return -TARGET_EFAULT;
     host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
     host_sd->sem_otime = tswapl(target_sd->sem_otime);
     host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
@@ -1748,7 +1749,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
         return -TARGET_EFAULT;
-    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
+        return -TARGET_EFAULT;;
     target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
     target_sd->sem_otime = tswapl(host_sd->sem_otime);
     target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
@@ -1756,135 +1758,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
     return 0;
 }
 
+struct target_seminfo {
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
+};
+
+static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
+                                              struct seminfo *host_seminfo)
+{
+    struct target_seminfo *target_seminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+    __put_user(host_seminfo->semume, &target_seminfo->semume);
+    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+    unlock_user_struct(target_seminfo, target_addr, 1);
+    return 0;
+}
+
 union semun {
 	int val;
 	struct semid_ds *buf;
 	unsigned short *array;
+	struct seminfo *__buf;
 };
 
 union target_semun {
 	int val;
-	abi_long buf;
-	unsigned short int *array;
+	abi_ulong buf;
+	abi_ulong array;
+	abi_ulong __buf;
 };
 
-static inline abi_long target_to_host_semun(int cmd,
-                                            union semun *host_su,
-                                            abi_ulong target_addr,
-                                            struct semid_ds *ds)
+static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+                                               abi_ulong target_addr)
 {
-    union target_semun *target_su;
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
 
-    switch( cmd ) {
-	case IPC_STAT:
-	case IPC_SET:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-	   target_to_host_semid_ds(ds,target_su->buf);
-	   host_su->buf = ds;
-           unlock_user_struct(target_su, target_addr, 0);
-	   break;
-	case GETVAL:
-	case SETVAL:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-	   host_su->val = tswapl(target_su->val);
-           unlock_user_struct(target_su, target_addr, 0);
-	   break;
-	case GETALL:
-	case SETALL:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-	   *host_su->array = tswap16(*target_su->array);
-           unlock_user_struct(target_su, target_addr, 0);
-	   break;
-	default:
-           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    *host_array = malloc(nsems*sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+                      nsems*sizeof(unsigned short), 1);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __get_user((*host_array)[i], &array[i]);
     }
+    unlock_user(array, target_addr, 0);
+
     return 0;
 }
 
-static inline abi_long host_to_target_semun(int cmd,
-                                            abi_ulong target_addr,
-                                            union semun *host_su,
-                                            struct semid_ds *ds)
+static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+                                               unsigned short **host_array)
 {
-    union target_semun *target_su;
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
 
-    switch( cmd ) {
-	case IPC_STAT:
-	case IPC_SET:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-	   host_to_target_semid_ds(target_su->buf,ds);
-           unlock_user_struct(target_su, target_addr, 1);
-	   break;
-	case GETVAL:
-	case SETVAL:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-	   target_su->val = tswapl(host_su->val);
-           unlock_user_struct(target_su, target_addr, 1);
-	   break;
-	case GETALL:
-	case SETALL:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-	   *target_su->array = tswap16(*host_su->array);
-           unlock_user_struct(target_su, target_addr, 1);
-	   break;
-        default:
-           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    array = lock_user(VERIFY_WRITE, target_addr,
+                      nsems*sizeof(unsigned short), 0);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __put_user((*host_array)[i], &array[i]);
     }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+
     return 0;
 }
 
-static inline abi_long do_semctl(int first, int second, int third,
-                                 abi_long ptr)
+static inline abi_long do_semctl(int semid, int semnum, int cmd,
+                                 union target_semun target_su)
 {
     union semun arg;
     struct semid_ds dsarg;
-    int cmd = third&0xff;
-    abi_long ret = 0;
+    unsigned short *array;
+    struct seminfo seminfo;
+    abi_long ret = -TARGET_EINVAL;
+    abi_long err;
+    cmd &= 0xff;
 
     switch( cmd ) {
 	case GETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
 	case SETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            arg.val = tswapl(target_su.val);
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            target_su.val = tswapl(arg.val);
             break;
 	case GETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
 	case SETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            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:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
 	case IPC_SET:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+	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;
-    default:
-            ret = get_errno(semctl(first, second, cmd, arg));
     }
 
     return ret;
 }
 
+struct target_sembuf {
+    unsigned short sem_num;
+    short sem_op;
+    short sem_flg;
+};
+
+static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+                                             abi_ulong target_addr,
+                                             unsigned nsops)
+{
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, target_addr,
+                              nsops*sizeof(struct target_sembuf), 1);
+    if (!target_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);
+    }
+
+    unlock_user(target_sembuf, target_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+
+    if (target_to_host_sembuf(sops, ptr, nsops))
+        return -TARGET_EFAULT;
+
+    return semop(semid, sops, nsops);
+}
+
 struct target_msqid_ds
 {
     struct target_ipc_perm msg_perm;
@@ -2088,7 +2169,7 @@ static abi_long do_ipc(unsigned int call, int first,
 
     switch (call) {
     case IPCOP_semop:
-        ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
+        ret = do_semop(first, ptr, second);
         break;
 
     case IPCOP_semget:
@@ -2096,12 +2177,7 @@ static abi_long do_ipc(unsigned int call, int first,
         break;
 
     case IPCOP_semctl:
-        ret = do_semctl(first, second, third, ptr);
-        break;
-
-    case IPCOP_semtimedop:
-        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-        ret = -TARGET_ENOSYS;
+        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
         break;
 
     case IPCOP_msgget:
@@ -4932,7 +5008,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
 	break;
 #endif
-
+#ifdef TARGET_NR_semget
+    case TARGET_NR_semget:
+        ret = get_errno(semget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semop
+    case TARGET_NR_semop:
+        ret = get_errno(do_semop(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semctl
+    case TARGET_NR_semctl:
+        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
+        break;
+#endif
 #ifdef TARGET_NR_msgctl
     case TARGET_NR_msgctl:
         ret = do_msgctl(arg1, arg2, arg3);
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 05/10] Added posix message queue syscalls except mq_notify
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
                   ` (2 preceding siblings ...)
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem* riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-15 16:13   ` Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 06/10] Add support for passing contents of argv0 riku.voipio
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Lionel Landwerlin <lionel.landwerlin@openwide.fr>

From: Lionel Landwerlin <lionel.landwerlin@openwide.fr>

Added Added posix message queue syscalls and their strace
prints.

From: Lionel Landwerlin <lionel.landwerlin@openwide.fr>

Signed-off-by: Lionel Landwerlin <lionel.landwerlin@openwide.fr>
Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/strace.list    |   12 ++--
 linux-user/syscall.c      |  113 +++++++++++++++++++++++++++++++++++++++++++++
 linux-user/syscall_defs.h |    7 +++
 3 files changed, 126 insertions(+), 6 deletions(-)

diff --git a/linux-user/strace.list b/linux-user/strace.list
index 09a801f..3f688db 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -524,22 +524,22 @@
 { TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_getsetattr
-{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , NULL, NULL, NULL },
+{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , "%s(%d,%p,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_notify
-{ TARGET_NR_mq_notify, "mq_notify" , NULL, NULL, NULL },
+{ TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_open
-{ TARGET_NR_mq_open, "mq_open" , NULL, NULL, NULL },
+{ TARGET_NR_mq_open, "mq_open" , "%s(\"/%s\",%#x,%#o,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_timedreceive
-{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_timedsend
-{ TARGET_NR_mq_timedsend, "mq_timedsend" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mq_unlink
-{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, NULL, NULL },
+{ TARGET_NR_mq_unlink, "mq_unlink" , "%s(%s)", NULL, NULL },
 #endif
 #ifdef TARGET_NR_mremap
 { TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 88ed46c..30bb617 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <time.h>
 #include <limits.h>
+#include <mqueue.h>
 #include <sys/types.h>
 #include <sys/ipc.h>
 #include <sys/msg.h>
@@ -635,6 +636,43 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
     return 0;
 }
 
+static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
+                                              abi_ulong target_mq_attr_addr)
+{
+    struct target_mq_attr *target_mq_attr;
+
+    if (!lock_user_struct(VERIFY_READ, target_mq_attr,
+                          target_mq_attr_addr, 1))
+        return -TARGET_EFAULT;
+
+    __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
+    __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+    __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+    __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
+
+    return 0;
+}
+
+static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
+                                            const struct mq_attr *attr)
+{
+    struct target_mq_attr *target_mq_attr;
+
+    if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
+                          target_mq_attr_addr, 0))
+        return -TARGET_EFAULT;
+
+    __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
+    __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+    __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+    __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
+
+    return 0;
+}
 
 /* do_select() must return target values and target errnos. */
 static abi_long do_select(int n,
@@ -6439,6 +6477,81 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         break;
 #endif
 
+#ifdef TARGET_NR_mq_open
+    case TARGET_NR_mq_open:
+    {
+        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);
+        break;
+    }
+
+    case TARGET_NR_mq_unlink:
+        p = lock_user_string(arg1 - 1);
+        ret = get_errno(mq_unlink(p));
+        unlock_user (p, arg1, 0);
+        break;
+
+    case TARGET_NR_mq_timedsend:
+    {
+        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);
+        }
+        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;
+
+        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);
+        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);
+        }
+
+        break;
+    }
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 7db7a8c..a373690 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -1998,6 +1998,13 @@ struct linux_dirent64 {
     char            d_name[256];
 };
 
+struct target_mq_attr {
+    abi_long mq_flags;
+    abi_long mq_maxmsg;
+    abi_long mq_msgsize;
+    abi_long mq_curmsgs;
+};
+
 #include "socket.h"
 
 #include "errno_defs.h"
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 06/10] Add support for passing contents of argv0
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
                   ` (3 preceding siblings ...)
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 05/10] Added posix message queue syscalls except mq_notify riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-15 16:13   ` Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 07/10] linux-user: unix sockets - fix running dbus riku.voipio
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@iki.fi>

Added switch -0 (zero) which can be used to pass argv[0] to
target process. The main use is for a binfmt_misc wrapper when
the "P - preserve-argv[0]" setting is used.

From: Mika Westerberg

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/main.c |   38 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index feb3036..40308aa 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2213,6 +2213,7 @@ static void usage(void)
            "-drop-ld-preload  drop LD_PRELOAD for target process\n"
            "-E var=value      sets/modifies targets environment variable(s)\n"
            "-U var            unsets targets environment variable(s)\n"
+           "-0 argv0          forces target process argv[0] to be argv0\n"
            "\n"
            "Debug options:\n"
            "-d options   activate log (logfile=%s)\n"
@@ -2263,7 +2264,11 @@ int main(int argc, char **argv, char **envp)
     const char *r;
     int gdbstub_port = 0;
     char **target_environ, **wrk;
+    char **target_argv;
+    int target_argc;
     envlist_t *envlist = NULL;
+    const char *argv0 = NULL;
+    int i;
 
     if (argc <= 1)
         usage();
@@ -2320,6 +2325,9 @@ int main(int argc, char **argv, char **envp)
             r = argv[optind++];
             if (envlist_unsetenv(envlist, r) != 0)
                 usage();
+        } else if (!strcmp(r, "0")) {
+            r = argv[optind++];
+            argv0 = r;
         } else if (!strcmp(r, "s")) {
             if (optind >= argc)
                 break;
@@ -2430,11 +2438,39 @@ int main(int argc, char **argv, char **envp)
     target_environ = envlist_to_environ(envlist, NULL);
     envlist_free(envlist);
 
-    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+    /*
+     * Prepare copy of argv vector for target.
+     */
+    target_argc = argc - optind;
+    target_argv = calloc(target_argc + 1, sizeof (char *));
+    if (target_argv == NULL) {
+	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+	exit(1);
+    }
+
+    /*
+     * If argv0 is specified (using '-0' switch) we replace
+     * argv[0] pointer with the given one.
+     */
+    i = 0;
+    if (argv0 != NULL) {
+        target_argv[i++] = strdup(argv0);
+    }
+    for (; i < target_argc; i++) {
+        target_argv[i] = strdup(argv[optind + i]);
+    }
+    target_argv[target_argc] = NULL;
+
+    if (loader_exec(filename, target_argv, target_environ, regs, info) != 0) {
         printf("Error loading %s\n", filename);
         _exit(1);
     }
 
+    for (i = 0; i < target_argc; i++) {
+        free(target_argv[i]);
+    }
+    free(target_argv);
+
     for (wrk = target_environ; *wrk; wrk++) {
         free(*wrk);
     }
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 07/10] linux-user: unix sockets - fix running dbus
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
                   ` (4 preceding siblings ...)
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 06/10] Add support for passing contents of argv0 riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-15 16:14   ` Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 08/10] linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls riku.voipio
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@nokia.com>

dbus sends too short (according to man 7 unix) addrlen for it's
unix socket. I've been told that happens with other applications
as well. Linux kernel doesn't appear to mind, so I guess
we whould be tolerant as well. Expand sockaddr with +1 to fit
the \0 of the pathname passed.

(scratchbox1 qemu had a very different workaround for the same issue).

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/syscall.c |   29 +++++++++++++++++++++++++++--
 1 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 30bb617..8d1d12b 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -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>
@@ -735,13 +736,37 @@ 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;
@@ -1195,7 +1220,7 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr,
     if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
         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));
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 08/10] linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
                   ` (5 preceding siblings ...)
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 07/10] linux-user: unix sockets - fix running dbus riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-15 16:14   ` Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 09/10] Prefer glibc over direct syscalls riku.voipio
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 10/10] linux-user: Proper exit code for uncaught signals riku.voipio
  8 siblings, 1 reply; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Mika Westerberg <mika.westerberg@iki.fi>

- This check is not needed because kernel will check whether given
  buffer is too small and there is no upper limit for size of the buffer.

From: Mika Westerberg <mika.westerberg@iki.fi>

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/syscall.c |   17 +++++++----------
 1 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8d1d12b..110cba0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1208,16 +1208,13 @@ 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+1);
@@ -1232,7 +1229,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);
@@ -1307,7 +1304,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);
@@ -1332,7 +1329,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);
@@ -1360,7 +1357,7 @@ static abi_long do_getsockname(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);
@@ -1398,7 +1395,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);
@@ -1433,7 +1430,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;
         }
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 09/10] Prefer glibc over direct syscalls
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
                   ` (6 preceding siblings ...)
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 08/10] linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-15 16:14   ` Aurelien Jarno
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 10/10] linux-user: Proper exit code for uncaught signals riku.voipio
  8 siblings, 1 reply; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@iki.fi>

The openat/*at syscalls are incredibly common with modern coreutils,
calling them directly via syscalls breaks for example fakeroot. Use
glibc stubs whenever directly available and provide old syscall
calling for people still using older libc.

Patch originally from Mika Westerberg, Adapted to
apply to current trunk and cleaned up by Riku Voipio.

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 configure            |   53 +++++++++
 linux-user/syscall.c |  314 ++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 306 insertions(+), 61 deletions(-)

diff --git a/configure b/configure
index fa77937..8955c83 100755
--- a/configure
+++ b/configure
@@ -1115,6 +1115,53 @@ EOF
   fi
 fi
 
+#
+# Check for xxxat() functions when we are building linux-user
+# emulator.  This is done because older glibc versions don't
+# have syscall stubs for these implemented.
+#
+atfile=no
+if [ "$linux_user" = "yes" ] ; then
+  cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+	/* try to unlink nonexisting file */
+	return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
+}
+EOF
+  if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+    atfile=yes
+  fi
+fi
+
+# Check for initofy functions when we are building linux-user
+# emulator.  This is done because older glibc versions don't
+# have syscall stubs for these implemented.  In that case we
+# don't provide them even if kernel supports them.
+#
+inotify=no
+if [ "$linux_user" = "yes" ] ; then
+  cat > $TMPC << EOF
+#include <sys/inotify.h>
+
+int
+main(void)
+{
+	/* try to start inotify */
+	return inotify_init(void);
+}
+EOF
+  if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+    inotify=yes
+  fi
+fi
+
 # Check if tools are available to build documentation.
 if [ -x "`which texi2html 2>/dev/null`" ] && \
    [ -x "`which pod2man 2>/dev/null`" ]; then
@@ -1494,6 +1541,12 @@ if test "$curses" = "yes" ; then
   echo "CONFIG_CURSES=yes" >> $config_mak
   echo "CURSES_LIBS=-lcurses" >> $config_mak
 fi
+if test "$atfile" = "yes" ; then
+  echo "#define CONFIG_ATFILE 1" >> $config_h
+fi
+if test "$inotify" = "yes" ; then
+  echo "#define CONFIG_INOTIFY 1" >> $config_h
+fi
 if test "$brlapi" = "yes" ; then
   echo "CONFIG_BRLAPI=yes" >> $config_mak
   echo "#define CONFIG_BRLAPI 1" >> $config_h
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 110cba0..52e9ff5 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -53,6 +53,7 @@
 #include <sys/statfs.h>
 #include <utime.h>
 #include <sys/sysinfo.h>
+#include <sys/utsname.h>
 //#include <sys/user.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
@@ -200,7 +201,229 @@ static int gettid(void) {
     return -ENOSYS;
 }
 #endif
-_syscall1(int,sys_uname,struct new_utsname *,buf)
+#if TARGET_ABI_BITS == 32
+_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
+#endif
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
+_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
+#endif
+_syscall2(int, sys_getpriority, int, which, int, who);
+#if !defined (__x86_64__)
+_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
+          loff_t *, res, uint, wh);
+#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)
+_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+#endif
+#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
+_syscall2(int,sys_tkill,int,tid,int,sig)
+#endif
+#ifdef __NR_exit_group
+_syscall1(int,exit_group,int,error_code)
+#endif
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+_syscall1(int,set_tid_address,int *,tidptr)
+#endif
+#if defined(USE_NPTL)
+#if defined(TARGET_NR_futex) && defined(__NR_futex)
+_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
+          const struct timespec *,timeout,int *,uaddr2,int,val3)
+#endif
+#endif
+
+static bitmask_transtbl fcntl_flags_tbl[] = {
+  { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
+  { TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
+  { TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
+  { TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
+  { TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
+  { TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
+  { TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
+  { TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
+  { TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
+  { TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
+  { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
+  { TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
+  { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
+#if defined(O_DIRECT)
+  { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
+#endif
+  { 0, 0, 0, 0 }
+};
+
+#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;
+
+  if (uname(&uts_buf) < 0)
+      return (-1);
+
+  /*
+   * Just in case these have some differences, we
+   * translate utsname to new_utsname (which is the
+   * struct linux kernel uses).
+   */
+
+  bzero(buf, sizeof (*buf));
+  COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+  COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+  COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
+  COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
+  COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
+#ifdef _GNU_SOURCE
+  COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
+#endif
+  return (0);
+
+#undef COPY_UTSNAME_FIELD
+}
+
+static int sys_getcwd1(char *buf, size_t size)
+{
+  if (getcwd(buf, size) == NULL) {
+      /* getcwd() sets errno */
+      return (-1);
+  }
+  return (0);
+}
+
+#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, int flags)
+{
+  return (faccessat(dirfd, pathname, mode, flags));
+}
+#endif
+#ifdef TARGET_NR_fchmodat
+static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
+{
+  return (fchmodat(dirfd, pathname, mode, flags));
+}
+#endif
+#ifdef TARGET_NR_fchownat
+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, ...)
+{
+  /*
+   * open(2) has extra parameter 'mode' when called with
+   * flag O_CREAT.
+   */
+  if ((flags & O_CREAT) != 0) {
+      va_list ap;
+      mode_t mode;
+
+      /*
+       * Get the 'mode' parameter and translate it to
+       * host bits.
+       */
+      va_start(ap, flags);
+      mode = va_arg(ap, mode_t);
+      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
+      va_end(ap);
+
+      return (openat(dirfd, pathname, flags, mode));
+  }
+  return (openat(dirfd, pathname, flags));
+}
+#endif
+#ifdef TARGET_NR_readlinkat
+static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+  return (readlinkat(dirfd, pathname, buf, bufsiz));
+}
+#endif
+#ifdef TARGET_NR_renameat
+static int sys_renameat(int olddirfd, const char *oldpath,
+    int newdirfd, const char *newpath)
+{
+  return (renameat(olddirfd, oldpath, newdirfd, newpath));
+}
+#endif
+#ifdef TARGET_NR_symlinkat
+static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+  return (symlinkat(oldpath, newdirfd, newpath));
+}
+#endif
+#ifdef TARGET_NR_unlinkat
+static int sys_unlinkat(int dirfd, const char *pathname, int flags)
+{
+  return (unlinkat(dirfd, pathname, flags));
+}
+#endif
+#ifdef TARGET_NR_utimensat
+static int sys_utimensat(int dirfd, const char *pathname,
+    const struct timespec times[2], int flags)
+{
+  return (utimensat(dirfd, pathname, times, flags));
+}
+#endif
+#else /* !CONFIG_ATFILE */
+
+/*
+ * Try direct syscalls instead
+ */
 #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
 _syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
 #endif
@@ -221,21 +444,14 @@ _syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
 _syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
          const struct timeval *,times)
 #endif
-_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
-#if TARGET_ABI_BITS == 32
-_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
-#endif
-#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
-_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
-#endif
-_syscall2(int, sys_getpriority, int, which, int, who);
-#if !defined (__x86_64__)
-_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
-          loff_t *, res, uint, wh);
+#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)
+      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)
@@ -244,11 +460,6 @@ _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
 _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
@@ -260,24 +471,10 @@ _syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
 _syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
           int,newdirfd,const char *,newpath)
 #endif
-_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
 _syscall3(int,sys_symlinkat,const char *,oldpath,
           int,newdirfd,const char *,newpath)
 #endif
-_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
-#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
-_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
-#endif
-#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
-_syscall2(int,sys_tkill,int,tid,int,sig)
-#endif
-#ifdef __NR_exit_group
-_syscall1(int,exit_group,int,error_code)
-#endif
-#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
-_syscall1(int,set_tid_address,int *,tidptr)
-#endif
 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 #endif
@@ -285,21 +482,36 @@ _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
           const struct timespec *,tsp,int,flags)
 #endif
+
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_INOTIFY
+
 #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
-_syscall0(int,sys_inotify_init)
+static int sys_inotify_init(void)
+{
+  return (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)
+static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
+{
+  return (inotify_add_watch(fd, pathname, 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,
-          const struct timespec *,timeout,int *,uaddr2,int,val3)
-#endif
+static int sys_inotify_rm_watch(int fd, int32_t wd)
+{
+  return (inotify_rm_watch(fd,pathname, wd));
+}
 #endif
+#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);
 extern int flock(int, int);
@@ -2837,26 +3049,6 @@ static bitmask_transtbl mmap_flags_tbl[] = {
 	{ 0, 0, 0, 0 }
 };
 
-static bitmask_transtbl fcntl_flags_tbl[] = {
-	{ TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
-	{ TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
-	{ TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
-	{ TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
-	{ TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
-	{ TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
-	{ TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
-	{ TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
-	{ TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
-	{ TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
-	{ TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
-	{ TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
-	{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
-#if defined(O_DIRECT)
-	{ TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
-#endif
-	{ 0, 0, 0, 0 }
-};
-
 #if defined(TARGET_I386)
 
 /* NOTE: there is really one LDT for all the threads */
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [Qemu-devel] [PATCH 10/10] linux-user: Proper exit code for uncaught signals
  2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
                   ` (7 preceding siblings ...)
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 09/10] Prefer glibc over direct syscalls riku.voipio
@ 2009-04-05 20:59 ` riku.voipio
  2009-04-15 16:19   ` Aurelien Jarno
  8 siblings, 1 reply; 24+ messages in thread
From: riku.voipio @ 2009-04-05 20:59 UTC (permalink / raw)
  To: qemu-devel

From: Riku Voipio <riku.voipio@nokia.com>

The proper exit code for dieing from an uncaught signal is -<signal>.
The kernel doesn't allow exit() or _exit() to pass a negative value.
To get the proper exit code we need to actually die from an uncaught signal.

A default signal handler is installed, we send ourself a signal
and we wait for it to arrive.

Patch originates from Scratchbox

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/signal.c |   37 +++++++++++++++++++++++++------------
 1 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index fc37dc1..7504725 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <errno.h>
+#include <assert.h>
 #include <sys/ucontext.h>
 
 #include "qemu.h"
@@ -352,22 +353,34 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
 static void QEMU_NORETURN force_sig(int sig)
 {
     int host_sig;
+    struct sigaction act;
     host_sig = target_to_host_signal(sig);
     fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
             sig, strsignal(host_sig));
-#if 1
     gdb_signalled(thread_env, sig);
-    _exit(-host_sig);
-#else
-    {
-        struct sigaction act;
-        sigemptyset(&act.sa_mask);
-        act.sa_flags = SA_SIGINFO;
-        act.sa_sigaction = SIG_DFL;
-        sigaction(SIGABRT, &act, NULL);
-        abort();
-    }
-#endif
+
+    /* The proper exit code for dieing from an uncaught signal is
+     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
+     * a negative value.  To get the proper exit code we need to
+     * actually die from an uncaught signal.  Here the default signal
+     * handler is installed, we send ourself a signal and we wait for
+     * it to arrive. */
+    sigfillset(&act.sa_mask);
+    act.sa_handler = SIG_DFL;
+    sigaction(host_sig, &act, NULL);
+
+    /* For some reason raise(host_sig) doesn't send the signal when
+     * statically linked on x86-64. */
+    kill(getpid(), host_sig);
+
+    /* Make sure the signal isn't masked (just reuse the mask inside
+    of act) */
+    sigdelset(&act.sa_mask, host_sig);
+    sigsuspend(&act.sa_mask);
+
+    /* unreachable */
+    assert(0);
+
 }
 
 /* queue a signal so that it will be send to the virtual CPU as soon
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem* riku.voipio
@ 2009-04-06  9:06   ` Arnaud Patard
  2009-04-06 15:17     ` Riku Voipio
  2009-04-15 15:28   ` Aurelien Jarno
  1 sibling, 1 reply; 24+ messages in thread
From: Arnaud Patard @ 2009-04-06  9:06 UTC (permalink / raw)
  To: qemu-devel

riku.voipio@iki.fi writes:

Hi,

> -static inline abi_long do_semctl(int first, int second, int third,
> -                                 abi_long ptr)
> +static inline abi_long do_semctl(int semid, int semnum, int cmd,
> +                                 union target_semun target_su)
>  {
>      union semun arg;
>      struct semid_ds dsarg;
> -    int cmd = third&0xff;
> -    abi_long ret = 0;
> +    unsigned short *array;
> +    struct seminfo seminfo;
> +    abi_long ret = -TARGET_EINVAL;
> +    abi_long err;
> +    cmd &= 0xff;
>  
>      switch( cmd ) {

I'm wondering if it's a good way of handling the IPC_64 flag. afaik this
flag is set to indicate that we're using newer ipc version, so if it's
set, the code may use things like 32bit uids.
Taking this into account, is it possible that falling back to the old
*ctl versions is breaking some applications ?

Thanks,
Arnaud

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-06  9:06   ` Arnaud Patard
@ 2009-04-06 15:17     ` Riku Voipio
  2009-04-06 16:22       ` Arnaud Patard
  0 siblings, 1 reply; 24+ messages in thread
From: Riku Voipio @ 2009-04-06 15:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: kirill

On Mon, Apr 06, 2009 at 11:06:22AM +0200, Arnaud Patard wrote:
> riku.voipio@iki.fi writes:
> 
> Hi,
> 
> > -static inline abi_long do_semctl(int first, int second, int third,
> > -                                 abi_long ptr)
> > +static inline abi_long do_semctl(int semid, int semnum, int cmd,
> > +                                 union target_semun target_su)
> >  {
> >      union semun arg;
> >      struct semid_ds dsarg;
> > -    int cmd = third&0xff;
> > -    abi_long ret = 0;
> > +    unsigned short *array;
> > +    struct seminfo seminfo;
> > +    abi_long ret = -TARGET_EINVAL;
> > +    abi_long err;
> > +    cmd &= 0xff;
> >  
> >      switch( cmd ) {

> I'm wondering if it's a good way of handling the IPC_64 flag. afaik this
> flag is set to indicate that we're using newer ipc version, so if it's
> set, the code may use things like 32bit uids.
> Taking this into account, is it possible that falling back to the old
> *ctl versions is breaking some applications ?

As far as I see the patch doesn't change qemu's behaviour in this respect?
I didn't see any failures in ltp testing with amd64/i386 hosts and arm
arm target. Would some other target/host combination be more suspectible
from errors of this behaviour? when running qemu-arm under i386, glibc
appears to add the IPC_64 flag when qemu is calling sem* functions.

-- 
"rm -rf" only sounds scary if you don't have backups

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-06 15:17     ` Riku Voipio
@ 2009-04-06 16:22       ` Arnaud Patard
  0 siblings, 0 replies; 24+ messages in thread
From: Arnaud Patard @ 2009-04-06 16:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: kirill

Riku Voipio <riku.voipio@iki.fi> writes:

> On Mon, Apr 06, 2009 at 11:06:22AM +0200, Arnaud Patard wrote:
>> riku.voipio@iki.fi writes:
>> 
>> Hi,
>> 
>> > -static inline abi_long do_semctl(int first, int second, int third,
>> > -                                 abi_long ptr)
>> > +static inline abi_long do_semctl(int semid, int semnum, int cmd,
>> > +                                 union target_semun target_su)
>> >  {
>> >      union semun arg;
>> >      struct semid_ds dsarg;
>> > -    int cmd = third&0xff;
>> > -    abi_long ret = 0;
>> > +    unsigned short *array;
>> > +    struct seminfo seminfo;
>> > +    abi_long ret = -TARGET_EINVAL;
>> > +    abi_long err;
>> > +    cmd &= 0xff;
>> >  
>> >      switch( cmd ) {
>
>> I'm wondering if it's a good way of handling the IPC_64 flag. afaik this
>> flag is set to indicate that we're using newer ipc version, so if it's
>> set, the code may use things like 32bit uids.
>> Taking this into account, is it possible that falling back to the old
>> *ctl versions is breaking some applications ?
>
> As far as I see the patch doesn't change qemu's behaviour in this respect?

well, in case of semctl, it was broken so it does change the
behaviour. In case of shmctl, you're right it's changing nothing

> I didn't see any failures in ltp testing with amd64/i386 hosts and arm
> arm target. Would some other target/host combination be more suspectible
> from errors of this behaviour? when running qemu-arm under i386, glibc
> appears to add the IPC_64 flag when qemu is calling sem* functions.

Well, it was an open question. I've seen the semctl breakage and then
your patch. When looking at it, I've noticed that it might break
something but I've no idea if it's breaking something in
practice. That's why I've asked.


Arnaud

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem* riku.voipio
  2009-04-06  9:06   ` Arnaud Patard
@ 2009-04-15 15:28   ` Aurelien Jarno
  2009-04-16 14:23     ` Riku Voipio
  1 sibling, 1 reply; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 15:28 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:20PM +0300, riku.voipio@iki.fi wrote:
> From: Riku Voipio <riku.voipio@iki.fi>
> 
> From: Kirill A. Shutemov <kirill@shutemov.name>
> 
> Fix and cleanup IPCOP_sem* ipc calls handling and
> implement sem* syscalls.
> 
> Uglify whitespace so that diff gets smaller and easier
> to review - Riku
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/syscall.c |  286 +++++++++++++++++++++++++++++++++-----------------
>  1 files changed, 188 insertions(+), 98 deletions(-)
> 
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 16cf89c..ddcc656 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -1733,7 +1733,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
>  
>      if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
>          return -TARGET_EFAULT;
> -    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
> +    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
> +        return -TARGET_EFAULT;
>      host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
>      host_sd->sem_otime = tswapl(target_sd->sem_otime);
>      host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
> @@ -1748,7 +1749,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
>  
>      if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
>          return -TARGET_EFAULT;
> -    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
> +    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
> +        return -TARGET_EFAULT;;
>      target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
>      target_sd->sem_otime = tswapl(host_sd->sem_otime);
>      target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
> @@ -1756,135 +1758,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
>      return 0;
>  }
>  
> +struct target_seminfo {
> +    int semmap;
> +    int semmni;
> +    int semmns;
> +    int semmnu;
> +    int semmsl;
> +    int semopm;
> +    int semume;
> +    int semusz;
> +    int semvmx;
> +    int semaem;
> +};
> +
> +static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
> +                                              struct seminfo *host_seminfo)
> +{
> +    struct target_seminfo *target_seminfo;
> +    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
> +        return -TARGET_EFAULT;
> +    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
> +    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
> +    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
> +    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
> +    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
> +    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
> +    __put_user(host_seminfo->semume, &target_seminfo->semume);
> +    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
> +    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
> +    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
> +    unlock_user_struct(target_seminfo, target_addr, 1);
> +    return 0;
> +}
> +
>  union semun {
>  	int val;
>  	struct semid_ds *buf;
>  	unsigned short *array;
> +	struct seminfo *__buf;
>  };
>  
>  union target_semun {
>  	int val;
> -	abi_long buf;
> -	unsigned short int *array;
> +	abi_ulong buf;
> +	abi_ulong array;
> +	abi_ulong __buf;
>  };
>  
> -static inline abi_long target_to_host_semun(int cmd,
> -                                            union semun *host_su,
> -                                            abi_ulong target_addr,
> -                                            struct semid_ds *ds)
> +static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
> +                                               abi_ulong target_addr)
>  {
> -    union target_semun *target_su;
> +    int nsems;
> +    unsigned short *array;
> +    union semun semun;
> +    struct semid_ds semid_ds;
> +    int i, ret;
>  
> -    switch( cmd ) {
> -	case IPC_STAT:
> -	case IPC_SET:
> -           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
> -               return -TARGET_EFAULT;
> -	   target_to_host_semid_ds(ds,target_su->buf);
> -	   host_su->buf = ds;
> -           unlock_user_struct(target_su, target_addr, 0);
> -	   break;
> -	case GETVAL:
> -	case SETVAL:
> -           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
> -               return -TARGET_EFAULT;
> -	   host_su->val = tswapl(target_su->val);
> -           unlock_user_struct(target_su, target_addr, 0);
> -	   break;
> -	case GETALL:
> -	case SETALL:
> -           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
> -               return -TARGET_EFAULT;
> -	   *host_su->array = tswap16(*target_su->array);
> -           unlock_user_struct(target_su, target_addr, 0);
> -	   break;
> -	default:
> -           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
> +    semun.buf = &semid_ds;
> +
> +    ret = semctl(semid, 0, IPC_STAT, semun);
> +    if (ret == -1)
> +        return get_errno(ret);
> +
> +    nsems = semid_ds.sem_nsems;
> +
> +    *host_array = malloc(nsems*sizeof(unsigned short));
> +    array = lock_user(VERIFY_READ, target_addr,
> +                      nsems*sizeof(unsigned short), 1);
> +    if (!array)
> +        return -TARGET_EFAULT;
> +
> +    for(i=0; i<nsems; i++) {
> +        __get_user((*host_array)[i], &array[i]);
>      }
> +    unlock_user(array, target_addr, 0);
> +
>      return 0;
>  }
>  
> -static inline abi_long host_to_target_semun(int cmd,
> -                                            abi_ulong target_addr,
> -                                            union semun *host_su,
> -                                            struct semid_ds *ds)
> +static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
> +                                               unsigned short **host_array)
>  {
> -    union target_semun *target_su;
> +    int nsems;
> +    unsigned short *array;
> +    union semun semun;
> +    struct semid_ds semid_ds;
> +    int i, ret;
>  
> -    switch( cmd ) {
> -	case IPC_STAT:
> -	case IPC_SET:
> -           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
> -               return -TARGET_EFAULT;
> -	   host_to_target_semid_ds(target_su->buf,ds);
> -           unlock_user_struct(target_su, target_addr, 1);
> -	   break;
> -	case GETVAL:
> -	case SETVAL:
> -           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
> -               return -TARGET_EFAULT;
> -	   target_su->val = tswapl(host_su->val);
> -           unlock_user_struct(target_su, target_addr, 1);
> -	   break;
> -	case GETALL:
> -	case SETALL:
> -           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
> -               return -TARGET_EFAULT;
> -	   *target_su->array = tswap16(*host_su->array);
> -           unlock_user_struct(target_su, target_addr, 1);
> -	   break;
> -        default:
> -           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
> +    semun.buf = &semid_ds;
> +
> +    ret = semctl(semid, 0, IPC_STAT, semun);
> +    if (ret == -1)
> +        return get_errno(ret);
> +
> +    nsems = semid_ds.sem_nsems;
> +
> +    array = lock_user(VERIFY_WRITE, target_addr,
> +                      nsems*sizeof(unsigned short), 0);
> +    if (!array)
> +        return -TARGET_EFAULT;
> +
> +    for(i=0; i<nsems; i++) {
> +        __put_user((*host_array)[i], &array[i]);
>      }
> +    free(*host_array);
> +    unlock_user(array, target_addr, 1);
> +
>      return 0;
>  }
>  
> -static inline abi_long do_semctl(int first, int second, int third,
> -                                 abi_long ptr)
> +static inline abi_long do_semctl(int semid, int semnum, int cmd,
> +                                 union target_semun target_su)
>  {
>      union semun arg;
>      struct semid_ds dsarg;
> -    int cmd = third&0xff;
> -    abi_long ret = 0;
> +    unsigned short *array;
> +    struct seminfo seminfo;
> +    abi_long ret = -TARGET_EINVAL;
> +    abi_long err;
> +    cmd &= 0xff;
>  
>      switch( cmd ) {
>  	case GETVAL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> -            break;
>  	case SETVAL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> +            arg.val = tswapl(target_su.val);
> +            ret = get_errno(semctl(semid, semnum, cmd, arg));
> +            target_su.val = tswapl(arg.val);
>              break;
>  	case GETALL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> -            break;
>  	case SETALL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> +            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:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> -            break;
>  	case IPC_SET:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> +	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;
> -    default:
> -            ret = get_errno(semctl(first, second, cmd, arg));
>      }
>  
>      return ret;
>  }
>  
> +struct target_sembuf {
> +    unsigned short sem_num;
> +    short sem_op;
> +    short sem_flg;
> +};
> +
> +static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
> +                                             abi_ulong target_addr,
> +                                             unsigned nsops)
> +{
> +    struct target_sembuf *target_sembuf;
> +    int i;
> +
> +    target_sembuf = lock_user(VERIFY_READ, target_addr,
> +                              nsops*sizeof(struct target_sembuf), 1);
> +    if (!target_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);
> +    }

I don't follow fully the subtle difference between __put_user() and
__get_user,() but given lock_user is called with VERIFY_READ, I think
__get_user() should be used instead.

> +    unlock_user(target_sembuf, target_addr, 0);
> +
> +    return 0;
> +}
> +
> +static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
> +{
> +    struct sembuf sops[nsops];
> +
> +    if (target_to_host_sembuf(sops, ptr, nsops))
> +        return -TARGET_EFAULT;
> +
> +    return semop(semid, sops, nsops);
> +}
> +
>  struct target_msqid_ds
>  {
>      struct target_ipc_perm msg_perm;
> @@ -2088,7 +2169,7 @@ static abi_long do_ipc(unsigned int call, int first,
>  
>      switch (call) {
>      case IPCOP_semop:
> -        ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
> +        ret = do_semop(first, ptr, second);
>          break;
>  
>      case IPCOP_semget:
> @@ -2096,12 +2177,7 @@ static abi_long do_ipc(unsigned int call, int first,
>          break;
>  
>      case IPCOP_semctl:
> -        ret = do_semctl(first, second, third, ptr);
> -        break;
> -
> -    case IPCOP_semtimedop:
> -        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
> -        ret = -TARGET_ENOSYS;
> +        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
>          break;
>  
>      case IPCOP_msgget:
> @@ -4932,7 +5008,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
>  	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
>  	break;
>  #endif
> -
> +#ifdef TARGET_NR_semget
> +    case TARGET_NR_semget:
> +        ret = get_errno(semget(arg1, arg2, arg3));
> +        break;
> +#endif
> +#ifdef TARGET_NR_semop
> +    case TARGET_NR_semop:
> +        ret = get_errno(do_semop(arg1, arg2, arg3));
> +        break;
> +#endif
> +#ifdef TARGET_NR_semctl
> +    case TARGET_NR_semctl:
> +        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
> +        break;
> +#endif
>  #ifdef TARGET_NR_msgctl
>      case TARGET_NR_msgctl:
>          ret = do_msgctl(arg1, arg2, arg3);
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 05/10] Added posix message queue syscalls except mq_notify
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 05/10] Added posix message queue syscalls except mq_notify riku.voipio
@ 2009-04-15 16:13   ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:13 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:21PM +0300, riku.voipio@iki.fi wrote:
> From: Lionel Landwerlin <lionel.landwerlin@openwide.fr>
> 
> From: Lionel Landwerlin <lionel.landwerlin@openwide.fr>
> 
> Added Added posix message queue syscalls and their strace
> prints.
> 
> From: Lionel Landwerlin <lionel.landwerlin@openwide.fr>
> 
> Signed-off-by: Lionel Landwerlin <lionel.landwerlin@openwide.fr>
> Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/strace.list    |   12 ++--
>  linux-user/syscall.c      |  113 +++++++++++++++++++++++++++++++++++++++++++++
>  linux-user/syscall_defs.h |    7 +++
>  3 files changed, 126 insertions(+), 6 deletions(-)

Thanks, applied.

> diff --git a/linux-user/strace.list b/linux-user/strace.list
> index 09a801f..3f688db 100644
> --- a/linux-user/strace.list
> +++ b/linux-user/strace.list
> @@ -524,22 +524,22 @@
>  { TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mq_getsetattr
> -{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , NULL, NULL, NULL },
> +{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , "%s(%d,%p,%p)", NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mq_notify
> -{ TARGET_NR_mq_notify, "mq_notify" , NULL, NULL, NULL },
> +{ TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mq_open
> -{ TARGET_NR_mq_open, "mq_open" , NULL, NULL, NULL },
> +{ TARGET_NR_mq_open, "mq_open" , "%s(\"/%s\",%#x,%#o,%p)", NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mq_timedreceive
> -{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , NULL, NULL, NULL },
> +{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mq_timedsend
> -{ TARGET_NR_mq_timedsend, "mq_timedsend" , NULL, NULL, NULL },
> +{ TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mq_unlink
> -{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, NULL, NULL },
> +{ TARGET_NR_mq_unlink, "mq_unlink" , "%s(%s)", NULL, NULL },
>  #endif
>  #ifdef TARGET_NR_mremap
>  { TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 88ed46c..30bb617 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -29,6 +29,7 @@
>  #include <fcntl.h>
>  #include <time.h>
>  #include <limits.h>
> +#include <mqueue.h>
>  #include <sys/types.h>
>  #include <sys/ipc.h>
>  #include <sys/msg.h>
> @@ -635,6 +636,43 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
>      return 0;
>  }
>  
> +static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
> +                                              abi_ulong target_mq_attr_addr)
> +{
> +    struct target_mq_attr *target_mq_attr;
> +
> +    if (!lock_user_struct(VERIFY_READ, target_mq_attr,
> +                          target_mq_attr_addr, 1))
> +        return -TARGET_EFAULT;
> +
> +    __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
> +    __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
> +    __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
> +    __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
> +
> +    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
> +
> +    return 0;
> +}
> +
> +static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
> +                                            const struct mq_attr *attr)
> +{
> +    struct target_mq_attr *target_mq_attr;
> +
> +    if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
> +                          target_mq_attr_addr, 0))
> +        return -TARGET_EFAULT;
> +
> +    __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
> +    __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
> +    __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
> +    __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
> +
> +    unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
> +
> +    return 0;
> +}
>  
>  /* do_select() must return target values and target errnos. */
>  static abi_long do_select(int n,
> @@ -6439,6 +6477,81 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
>          break;
>  #endif
>  
> +#ifdef TARGET_NR_mq_open
> +    case TARGET_NR_mq_open:
> +    {
> +        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);
> +        break;
> +    }
> +
> +    case TARGET_NR_mq_unlink:
> +        p = lock_user_string(arg1 - 1);
> +        ret = get_errno(mq_unlink(p));
> +        unlock_user (p, arg1, 0);
> +        break;
> +
> +    case TARGET_NR_mq_timedsend:
> +    {
> +        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);
> +        }
> +        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;
> +
> +        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);
> +        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);
> +        }
> +
> +        break;
> +    }
> +#endif
> +
>      default:
>      unimplemented:
>          gemu_log("qemu: Unsupported syscall: %d\n", num);
> diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
> index 7db7a8c..a373690 100644
> --- a/linux-user/syscall_defs.h
> +++ b/linux-user/syscall_defs.h
> @@ -1998,6 +1998,13 @@ struct linux_dirent64 {
>      char            d_name[256];
>  };
>  
> +struct target_mq_attr {
> +    abi_long mq_flags;
> +    abi_long mq_maxmsg;
> +    abi_long mq_msgsize;
> +    abi_long mq_curmsgs;
> +};
> +
>  #include "socket.h"
>  
>  #include "errno_defs.h"
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 06/10] Add support for passing contents of argv0
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 06/10] Add support for passing contents of argv0 riku.voipio
@ 2009-04-15 16:13   ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:13 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:22PM +0300, riku.voipio@iki.fi wrote:
> From: Riku Voipio <riku.voipio@iki.fi>
> 
> Added switch -0 (zero) which can be used to pass argv[0] to
> target process. The main use is for a binfmt_misc wrapper when
> the "P - preserve-argv[0]" setting is used.
> 
> From: Mika Westerberg
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/main.c |   38 +++++++++++++++++++++++++++++++++++++-
>  1 files changed, 37 insertions(+), 1 deletions(-)

Thanks, applied.

> diff --git a/linux-user/main.c b/linux-user/main.c
> index feb3036..40308aa 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -2213,6 +2213,7 @@ static void usage(void)
>             "-drop-ld-preload  drop LD_PRELOAD for target process\n"
>             "-E var=value      sets/modifies targets environment variable(s)\n"
>             "-U var            unsets targets environment variable(s)\n"
> +           "-0 argv0          forces target process argv[0] to be argv0\n"
>             "\n"
>             "Debug options:\n"
>             "-d options   activate log (logfile=%s)\n"
> @@ -2263,7 +2264,11 @@ int main(int argc, char **argv, char **envp)
>      const char *r;
>      int gdbstub_port = 0;
>      char **target_environ, **wrk;
> +    char **target_argv;
> +    int target_argc;
>      envlist_t *envlist = NULL;
> +    const char *argv0 = NULL;
> +    int i;
>  
>      if (argc <= 1)
>          usage();
> @@ -2320,6 +2325,9 @@ int main(int argc, char **argv, char **envp)
>              r = argv[optind++];
>              if (envlist_unsetenv(envlist, r) != 0)
>                  usage();
> +        } else if (!strcmp(r, "0")) {
> +            r = argv[optind++];
> +            argv0 = r;
>          } else if (!strcmp(r, "s")) {
>              if (optind >= argc)
>                  break;
> @@ -2430,11 +2438,39 @@ int main(int argc, char **argv, char **envp)
>      target_environ = envlist_to_environ(envlist, NULL);
>      envlist_free(envlist);
>  
> -    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
> +    /*
> +     * Prepare copy of argv vector for target.
> +     */
> +    target_argc = argc - optind;
> +    target_argv = calloc(target_argc + 1, sizeof (char *));
> +    if (target_argv == NULL) {
> +	(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
> +	exit(1);
> +    }
> +
> +    /*
> +     * If argv0 is specified (using '-0' switch) we replace
> +     * argv[0] pointer with the given one.
> +     */
> +    i = 0;
> +    if (argv0 != NULL) {
> +        target_argv[i++] = strdup(argv0);
> +    }
> +    for (; i < target_argc; i++) {
> +        target_argv[i] = strdup(argv[optind + i]);
> +    }
> +    target_argv[target_argc] = NULL;
> +
> +    if (loader_exec(filename, target_argv, target_environ, regs, info) != 0) {
>          printf("Error loading %s\n", filename);
>          _exit(1);
>      }
>  
> +    for (i = 0; i < target_argc; i++) {
> +        free(target_argv[i]);
> +    }
> +    free(target_argv);
> +
>      for (wrk = target_environ; *wrk; wrk++) {
>          free(*wrk);
>      }
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 07/10] linux-user: unix sockets - fix running dbus
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 07/10] linux-user: unix sockets - fix running dbus riku.voipio
@ 2009-04-15 16:14   ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:14 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:23PM +0300, riku.voipio@iki.fi wrote:
> From: Riku Voipio <riku.voipio@nokia.com>
> 
> dbus sends too short (according to man 7 unix) addrlen for it's
> unix socket. I've been told that happens with other applications
> as well. Linux kernel doesn't appear to mind, so I guess
> we whould be tolerant as well. Expand sockaddr with +1 to fit
> the \0 of the pathname passed.
> 
> (scratchbox1 qemu had a very different workaround for the same issue).
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/syscall.c |   29 +++++++++++++++++++++++++++--
>  1 files changed, 27 insertions(+), 2 deletions(-)

Thanks, applied.

> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 30bb617..8d1d12b 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -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>
> @@ -735,13 +736,37 @@ 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;
> @@ -1195,7 +1220,7 @@ static abi_long do_bind(int sockfd, abi_ulong target_addr,
>      if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
>          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));
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 08/10] linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 08/10] linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls riku.voipio
@ 2009-04-15 16:14   ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:14 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:24PM +0300, riku.voipio@iki.fi wrote:
> From: Mika Westerberg <mika.westerberg@iki.fi>
> 
> - This check is not needed because kernel will check whether given
>   buffer is too small and there is no upper limit for size of the buffer.
> 
> From: Mika Westerberg <mika.westerberg@iki.fi>
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/syscall.c |   17 +++++++----------
>  1 files changed, 7 insertions(+), 10 deletions(-)

Thanks, applied.

> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 8d1d12b..110cba0 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -1208,16 +1208,13 @@ 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+1);
> @@ -1232,7 +1229,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);
> @@ -1307,7 +1304,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);
> @@ -1332,7 +1329,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);
> @@ -1360,7 +1357,7 @@ static abi_long do_getsockname(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);
> @@ -1398,7 +1395,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);
> @@ -1433,7 +1430,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;
>          }
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 09/10] Prefer glibc over direct syscalls
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 09/10] Prefer glibc over direct syscalls riku.voipio
@ 2009-04-15 16:14   ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:14 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:25PM +0300, riku.voipio@iki.fi wrote:
> From: Riku Voipio <riku.voipio@iki.fi>
> 
> The openat/*at syscalls are incredibly common with modern coreutils,
> calling them directly via syscalls breaks for example fakeroot. Use
> glibc stubs whenever directly available and provide old syscall
> calling for people still using older libc.
> 
> Patch originally from Mika Westerberg, Adapted to
> apply to current trunk and cleaned up by Riku Voipio.
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  configure            |   53 +++++++++
>  linux-user/syscall.c |  314 ++++++++++++++++++++++++++++++++++++++++----------
>  2 files changed, 306 insertions(+), 61 deletions(-)

Thanks, applied.

> diff --git a/configure b/configure
> index fa77937..8955c83 100755
> --- a/configure
> +++ b/configure
> @@ -1115,6 +1115,53 @@ EOF
>    fi
>  fi
>  
> +#
> +# Check for xxxat() functions when we are building linux-user
> +# emulator.  This is done because older glibc versions don't
> +# have syscall stubs for these implemented.
> +#
> +atfile=no
> +if [ "$linux_user" = "yes" ] ; then
> +  cat > $TMPC << EOF
> +#define _ATFILE_SOURCE
> +#include <sys/types.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +
> +int
> +main(void)
> +{
> +	/* try to unlink nonexisting file */
> +	return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
> +}
> +EOF
> +  if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
> +    atfile=yes
> +  fi
> +fi
> +
> +# Check for initofy functions when we are building linux-user
> +# emulator.  This is done because older glibc versions don't
> +# have syscall stubs for these implemented.  In that case we
> +# don't provide them even if kernel supports them.
> +#
> +inotify=no
> +if [ "$linux_user" = "yes" ] ; then
> +  cat > $TMPC << EOF
> +#include <sys/inotify.h>
> +
> +int
> +main(void)
> +{
> +	/* try to start inotify */
> +	return inotify_init(void);
> +}
> +EOF
> +  if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
> +    inotify=yes
> +  fi
> +fi
> +
>  # Check if tools are available to build documentation.
>  if [ -x "`which texi2html 2>/dev/null`" ] && \
>     [ -x "`which pod2man 2>/dev/null`" ]; then
> @@ -1494,6 +1541,12 @@ if test "$curses" = "yes" ; then
>    echo "CONFIG_CURSES=yes" >> $config_mak
>    echo "CURSES_LIBS=-lcurses" >> $config_mak
>  fi
> +if test "$atfile" = "yes" ; then
> +  echo "#define CONFIG_ATFILE 1" >> $config_h
> +fi
> +if test "$inotify" = "yes" ; then
> +  echo "#define CONFIG_INOTIFY 1" >> $config_h
> +fi
>  if test "$brlapi" = "yes" ; then
>    echo "CONFIG_BRLAPI=yes" >> $config_mak
>    echo "#define CONFIG_BRLAPI 1" >> $config_h
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 110cba0..52e9ff5 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -53,6 +53,7 @@
>  #include <sys/statfs.h>
>  #include <utime.h>
>  #include <sys/sysinfo.h>
> +#include <sys/utsname.h>
>  //#include <sys/user.h>
>  #include <netinet/ip.h>
>  #include <netinet/tcp.h>
> @@ -200,7 +201,229 @@ static int gettid(void) {
>      return -ENOSYS;
>  }
>  #endif
> -_syscall1(int,sys_uname,struct new_utsname *,buf)
> +#if TARGET_ABI_BITS == 32
> +_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
> +#endif
> +#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
> +_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
> +#endif
> +_syscall2(int, sys_getpriority, int, which, int, who);
> +#if !defined (__x86_64__)
> +_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
> +          loff_t *, res, uint, wh);
> +#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)
> +_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
> +#endif
> +#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
> +_syscall2(int,sys_tkill,int,tid,int,sig)
> +#endif
> +#ifdef __NR_exit_group
> +_syscall1(int,exit_group,int,error_code)
> +#endif
> +#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
> +_syscall1(int,set_tid_address,int *,tidptr)
> +#endif
> +#if defined(USE_NPTL)
> +#if defined(TARGET_NR_futex) && defined(__NR_futex)
> +_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
> +          const struct timespec *,timeout,int *,uaddr2,int,val3)
> +#endif
> +#endif
> +
> +static bitmask_transtbl fcntl_flags_tbl[] = {
> +  { TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
> +  { TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
> +  { TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
> +  { TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
> +  { TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
> +  { TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
> +  { TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
> +  { TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
> +  { TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
> +  { TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
> +  { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
> +  { TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
> +  { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
> +#if defined(O_DIRECT)
> +  { TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
> +#endif
> +  { 0, 0, 0, 0 }
> +};
> +
> +#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;
> +
> +  if (uname(&uts_buf) < 0)
> +      return (-1);
> +
> +  /*
> +   * Just in case these have some differences, we
> +   * translate utsname to new_utsname (which is the
> +   * struct linux kernel uses).
> +   */
> +
> +  bzero(buf, sizeof (*buf));
> +  COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
> +  COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
> +  COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
> +  COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
> +  COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
> +#ifdef _GNU_SOURCE
> +  COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
> +#endif
> +  return (0);
> +
> +#undef COPY_UTSNAME_FIELD
> +}
> +
> +static int sys_getcwd1(char *buf, size_t size)
> +{
> +  if (getcwd(buf, size) == NULL) {
> +      /* getcwd() sets errno */
> +      return (-1);
> +  }
> +  return (0);
> +}
> +
> +#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, int flags)
> +{
> +  return (faccessat(dirfd, pathname, mode, flags));
> +}
> +#endif
> +#ifdef TARGET_NR_fchmodat
> +static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
> +{
> +  return (fchmodat(dirfd, pathname, mode, flags));
> +}
> +#endif
> +#ifdef TARGET_NR_fchownat
> +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, ...)
> +{
> +  /*
> +   * open(2) has extra parameter 'mode' when called with
> +   * flag O_CREAT.
> +   */
> +  if ((flags & O_CREAT) != 0) {
> +      va_list ap;
> +      mode_t mode;
> +
> +      /*
> +       * Get the 'mode' parameter and translate it to
> +       * host bits.
> +       */
> +      va_start(ap, flags);
> +      mode = va_arg(ap, mode_t);
> +      mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
> +      va_end(ap);
> +
> +      return (openat(dirfd, pathname, flags, mode));
> +  }
> +  return (openat(dirfd, pathname, flags));
> +}
> +#endif
> +#ifdef TARGET_NR_readlinkat
> +static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
> +{
> +  return (readlinkat(dirfd, pathname, buf, bufsiz));
> +}
> +#endif
> +#ifdef TARGET_NR_renameat
> +static int sys_renameat(int olddirfd, const char *oldpath,
> +    int newdirfd, const char *newpath)
> +{
> +  return (renameat(olddirfd, oldpath, newdirfd, newpath));
> +}
> +#endif
> +#ifdef TARGET_NR_symlinkat
> +static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
> +{
> +  return (symlinkat(oldpath, newdirfd, newpath));
> +}
> +#endif
> +#ifdef TARGET_NR_unlinkat
> +static int sys_unlinkat(int dirfd, const char *pathname, int flags)
> +{
> +  return (unlinkat(dirfd, pathname, flags));
> +}
> +#endif
> +#ifdef TARGET_NR_utimensat
> +static int sys_utimensat(int dirfd, const char *pathname,
> +    const struct timespec times[2], int flags)
> +{
> +  return (utimensat(dirfd, pathname, times, flags));
> +}
> +#endif
> +#else /* !CONFIG_ATFILE */
> +
> +/*
> + * Try direct syscalls instead
> + */
>  #if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
>  _syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
>  #endif
> @@ -221,21 +444,14 @@ _syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
>  _syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
>           const struct timeval *,times)
>  #endif
> -_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
> -#if TARGET_ABI_BITS == 32
> -_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
> -#endif
> -#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
> -_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
> -#endif
> -_syscall2(int, sys_getpriority, int, which, int, who);
> -#if !defined (__x86_64__)
> -_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
> -          loff_t *, res, uint, wh);
> +#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)
> +      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)
> @@ -244,11 +460,6 @@ _syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
>  _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
> @@ -260,24 +471,10 @@ _syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
>  _syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
>            int,newdirfd,const char *,newpath)
>  #endif
> -_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
>  #if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
>  _syscall3(int,sys_symlinkat,const char *,oldpath,
>            int,newdirfd,const char *,newpath)
>  #endif
> -_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
> -#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
> -_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
> -#endif
> -#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
> -_syscall2(int,sys_tkill,int,tid,int,sig)
> -#endif
> -#ifdef __NR_exit_group
> -_syscall1(int,exit_group,int,error_code)
> -#endif
> -#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
> -_syscall1(int,set_tid_address,int *,tidptr)
> -#endif
>  #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
>  _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
>  #endif
> @@ -285,21 +482,36 @@ _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
>  _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
>            const struct timespec *,tsp,int,flags)
>  #endif
> +
> +#endif /* CONFIG_ATFILE */
> +
> +#ifdef CONFIG_INOTIFY
> +
>  #if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
> -_syscall0(int,sys_inotify_init)
> +static int sys_inotify_init(void)
> +{
> +  return (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)
> +static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
> +{
> +  return (inotify_add_watch(fd, pathname, 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,
> -          const struct timespec *,timeout,int *,uaddr2,int,val3)
> -#endif
> +static int sys_inotify_rm_watch(int fd, int32_t wd)
> +{
> +  return (inotify_rm_watch(fd,pathname, wd));
> +}
>  #endif
> +#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);
>  extern int flock(int, int);
> @@ -2837,26 +3049,6 @@ static bitmask_transtbl mmap_flags_tbl[] = {
>  	{ 0, 0, 0, 0 }
>  };
>  
> -static bitmask_transtbl fcntl_flags_tbl[] = {
> -	{ TARGET_O_ACCMODE,   TARGET_O_WRONLY,    O_ACCMODE,   O_WRONLY,    },
> -	{ TARGET_O_ACCMODE,   TARGET_O_RDWR,      O_ACCMODE,   O_RDWR,      },
> -	{ TARGET_O_CREAT,     TARGET_O_CREAT,     O_CREAT,     O_CREAT,     },
> -	{ TARGET_O_EXCL,      TARGET_O_EXCL,      O_EXCL,      O_EXCL,      },
> -	{ TARGET_O_NOCTTY,    TARGET_O_NOCTTY,    O_NOCTTY,    O_NOCTTY,    },
> -	{ TARGET_O_TRUNC,     TARGET_O_TRUNC,     O_TRUNC,     O_TRUNC,     },
> -	{ TARGET_O_APPEND,    TARGET_O_APPEND,    O_APPEND,    O_APPEND,    },
> -	{ TARGET_O_NONBLOCK,  TARGET_O_NONBLOCK,  O_NONBLOCK,  O_NONBLOCK,  },
> -	{ TARGET_O_SYNC,      TARGET_O_SYNC,      O_SYNC,      O_SYNC,      },
> -	{ TARGET_FASYNC,      TARGET_FASYNC,      FASYNC,      FASYNC,      },
> -	{ TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
> -	{ TARGET_O_NOFOLLOW,  TARGET_O_NOFOLLOW,  O_NOFOLLOW,  O_NOFOLLOW,  },
> -	{ TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
> -#if defined(O_DIRECT)
> -	{ TARGET_O_DIRECT,    TARGET_O_DIRECT,    O_DIRECT,    O_DIRECT,    },
> -#endif
> -	{ 0, 0, 0, 0 }
> -};
> -
>  #if defined(TARGET_I386)
>  
>  /* NOTE: there is really one LDT for all the threads */
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 10/10] linux-user: Proper exit code for uncaught signals
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 10/10] linux-user: Proper exit code for uncaught signals riku.voipio
@ 2009-04-15 16:19   ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:19 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Sun, Apr 05, 2009 at 11:59:26PM +0300, riku.voipio@iki.fi wrote:
> From: Riku Voipio <riku.voipio@nokia.com>
> 
> The proper exit code for dieing from an uncaught signal is -<signal>.
> The kernel doesn't allow exit() or _exit() to pass a negative value.
> To get the proper exit code we need to actually die from an uncaught signal.
> 
> A default signal handler is installed, we send ourself a signal
> and we wait for it to arrive.
> 
> Patch originates from Scratchbox
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/signal.c |   37 +++++++++++++++++++++++++------------
>  1 files changed, 25 insertions(+), 12 deletions(-)

Thanks, applied.

> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index fc37dc1..7504725 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -25,6 +25,7 @@
>  #include <unistd.h>
>  #include <signal.h>
>  #include <errno.h>
> +#include <assert.h>
>  #include <sys/ucontext.h>
>  
>  #include "qemu.h"
> @@ -352,22 +353,34 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
>  static void QEMU_NORETURN force_sig(int sig)
>  {
>      int host_sig;
> +    struct sigaction act;
>      host_sig = target_to_host_signal(sig);
>      fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
>              sig, strsignal(host_sig));
> -#if 1
>      gdb_signalled(thread_env, sig);
> -    _exit(-host_sig);
> -#else
> -    {
> -        struct sigaction act;
> -        sigemptyset(&act.sa_mask);
> -        act.sa_flags = SA_SIGINFO;
> -        act.sa_sigaction = SIG_DFL;
> -        sigaction(SIGABRT, &act, NULL);
> -        abort();
> -    }
> -#endif
> +
> +    /* The proper exit code for dieing from an uncaught signal is
> +     * -<signal>.  The kernel doesn't allow exit() or _exit() to pass
> +     * a negative value.  To get the proper exit code we need to
> +     * actually die from an uncaught signal.  Here the default signal
> +     * handler is installed, we send ourself a signal and we wait for
> +     * it to arrive. */
> +    sigfillset(&act.sa_mask);
> +    act.sa_handler = SIG_DFL;
> +    sigaction(host_sig, &act, NULL);
> +
> +    /* For some reason raise(host_sig) doesn't send the signal when
> +     * statically linked on x86-64. */
> +    kill(getpid(), host_sig);
> +
> +    /* Make sure the signal isn't masked (just reuse the mask inside
> +    of act) */
> +    sigdelset(&act.sa_mask, host_sig);
> +    sigsuspend(&act.sa_mask);
> +
> +    /* unreachable */
> +    assert(0);
> +
>  }
>  
>  /* queue a signal so that it will be send to the virtual CPU as soon
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets
  2009-04-05 20:59 ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets riku.voipio
  2009-04-05 20:59   ` [Qemu-devel] [PATCH 03/10] Implement shm* syscalls and fix 64/32bit errors riku.voipio
@ 2009-04-15 16:21   ` Aurelien Jarno
  1 sibling, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-15 16:21 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paul Brook

On Sun, Apr 05, 2009 at 11:59:18PM +0300, riku.voipio@iki.fi wrote:
> From: Kirill A. Shutemov <kirill@shutemov.name>
> 
> qemu's page table can be incomple if /proc/self/maps is unavailable or
> host allocating a memory with mmap(), so we can't use it to find free
> memory area.
> 
> New version mmap_find_vma() uses mmap() without MAP_FIXED to find free
> memory.
> 
> From: Kirill A. Shutemov <kirill@shutemov.name>
> 
> Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name>
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/mmap.c |   81 ++++++++++++++++++++++++++++------------------------
>  linux-user/qemu.h |    1 +
>  2 files changed, 45 insertions(+), 37 deletions(-)

Last time this patch has been posted, Paul Brook has emitted some
concerns about this patch. Paul do you have any more comments about it?

> diff --git a/linux-user/mmap.c b/linux-user/mmap.c
> index 6f300a0..8cec230 100644
> --- a/linux-user/mmap.c
> +++ b/linux-user/mmap.c
> @@ -275,52 +275,59 @@ static abi_ulong mmap_next_start = 0x40000000;
>  
>  unsigned long last_brk;
>  
> -/* find a free memory area of size 'size'. The search starts at
> -   'start'. If 'start' == 0, then a default start address is used.
> -   Return -1 if error.
> -*/
> -/* page_init() marks pages used by the host as reserved to be sure not
> -   to use them. */
> -static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
> +/*
> + * Find and reserve a free memory area of size 'size'. The search
> + * starts at 'start'.
> + * It must be called with mmap_lock() held.
> + * Return -1 if error.
> + */
> +abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size)
>  {
> -    abi_ulong addr, addr1, addr_start;
> -    int prot;
> -    unsigned long new_brk;
> -
> -    new_brk = (unsigned long)sbrk(0);
> -    if (last_brk && last_brk < new_brk && last_brk == (target_ulong)last_brk) {
> -        /* This is a hack to catch the host allocating memory with brk().
> -           If it uses mmap then we loose.
> -           FIXME: We really want to avoid the host allocating memory in
> -           the first place, and maybe leave some slack to avoid switching
> -           to mmap.  */
> -        page_set_flags(last_brk & TARGET_PAGE_MASK,
> -                       TARGET_PAGE_ALIGN(new_brk),
> -                       PAGE_RESERVED); 
> -    }
> -    last_brk = new_brk;
> +    void *ptr;
> +    abi_ulong addr;
>  
>      size = HOST_PAGE_ALIGN(size);
> -    start = start & qemu_host_page_mask;
> +    start &= qemu_host_page_mask;
> +
> +    /* If 'start' == 0, then a default start address is used. */
> +    if (start == 0)
> +        start = mmap_next_start;
> +
>      addr = start;
> -    if (addr == 0)
> -        addr = mmap_next_start;
> -    addr_start = addr;
> +
>      for(;;) {
> -        prot = 0;
> -        for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) {
> -            prot |= page_get_flags(addr1);
> -        }
> -        if (prot == 0)
> +        /*
> +         * Reserve needed memory area to avoid a race.
> +         * It should be discarded using:
> +         *  - mmap() with MAP_FIXED flag
> +         *  - mremap() with MREMAP_FIXED flag
> +         *  - shmat() with SHM_REMAP flag
> +         */
> +        ptr = mmap((void *)(unsigned long)addr, size, PROT_NONE,
> +                   MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
> +
> +        /* ENOMEM, if host address space has no memory */
> +        if (ptr == MAP_FAILED)
> +            return (abi_ulong)-1;
> +
> +        /* If address fits target address space we've found what we need */
> +        if ((unsigned long)ptr + size - 1 <= (abi_ulong)-1)
>              break;
> +
> +        /* Unmap and try again with new page */
> +        munmap(ptr, size);
>          addr += qemu_host_page_size;
> -        /* we found nothing */
> -        if (addr == addr_start)
> +
> +        /* ENOMEM if we check whole of target address space */
> +        if (addr == start)
>              return (abi_ulong)-1;
>      }
> -    if (start == 0)
> -        mmap_next_start = addr + size;
> -    return addr;
> +
> +    /* Update default start address */
> +    if (start == mmap_next_start)
> +        mmap_next_start = (unsigned long)ptr + size;
> +
> +    return h2g(ptr);
>  }
>  
>  /* NOTE: all the constants are the HOST ones */
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index 94ae333..2bef14a 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -228,6 +228,7 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
>  extern unsigned long last_brk;
>  void mmap_lock(void);
>  void mmap_unlock(void);
> +abi_ulong mmap_find_vma(abi_ulong, abi_ulong);
>  void cpu_list_lock(void);
>  void cpu_list_unlock(void);
>  #if defined(USE_NPTL)
> -- 
> 1.6.2.1
> 
> 
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-15 15:28   ` Aurelien Jarno
@ 2009-04-16 14:23     ` Riku Voipio
  2009-04-18 16:16       ` Aurelien Jarno
  0 siblings, 1 reply; 24+ messages in thread
From: Riku Voipio @ 2009-04-16 14:23 UTC (permalink / raw)
  To: Aurelien Jarno; +Cc: qemu-devel

On Wed, Apr 15, 2009 at 05:28:23PM +0200, Aurelien Jarno wrote:
> > +struct target_sembuf {
> > +    unsigned short sem_num;
> > +    short sem_op;
> > +    short sem_flg;
> > +};
> > +
> > +static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
> > +                                             abi_ulong target_addr,
> > +                                             unsigned nsops)
> > +{
> > +    struct target_sembuf *target_sembuf;
> > +    int i;
> > +
> > +    target_sembuf = lock_user(VERIFY_READ, target_addr,
> > +                              nsops*sizeof(struct target_sembuf), 1);
> > +    if (!target_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);
> > +    }

> I don't follow fully the subtle difference between __put_user() and
> __get_user,() but given lock_user is called with VERIFY_READ, I think
> __get_user() should be used instead.

Yes.. since the target and host args are swapped, it still works like __get_user.
Corrected version attached.

(This error appears also once in the shm* patch too)

>From 32b512d9b521d2b146658f932b9c3553cd3ec1cd Mon Sep 17 00:00:00 2001
From: Riku Voipio <riku.voipio@iki.fi>
Date: Fri, 3 Apr 2009 00:28:14 +0300
Subject: [PATCH] [v2] fix IPCOP_sem* and implement sem*

From: Kirill A. Shutemov <kirill@shutemov.name>

Fix and cleanup IPCOP_sem* ipc calls handling and
implement sem* syscalls.

Riku:

1) Uglify whitespace so that diff gets smaller and easier
to review

2) use __get_user in target_to_host_sembuf

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
---
 linux-user/syscall.c |  286 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 188 insertions(+), 98 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 74b41a8..92e5159 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2005,7 +2005,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
 
     if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
         return -TARGET_EFAULT;
-    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
+        return -TARGET_EFAULT;
     host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
     host_sd->sem_otime = tswapl(target_sd->sem_otime);
     host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
@@ -2020,7 +2021,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
 
     if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
         return -TARGET_EFAULT;
-    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
+        return -TARGET_EFAULT;;
     target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
     target_sd->sem_otime = tswapl(host_sd->sem_otime);
     target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
@@ -2028,135 +2030,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
     return 0;
 }
 
+struct target_seminfo {
+    int semmap;
+    int semmni;
+    int semmns;
+    int semmnu;
+    int semmsl;
+    int semopm;
+    int semume;
+    int semusz;
+    int semvmx;
+    int semaem;
+};
+
+static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
+                                              struct seminfo *host_seminfo)
+{
+    struct target_seminfo *target_seminfo;
+    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
+        return -TARGET_EFAULT;
+    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+    __put_user(host_seminfo->semume, &target_seminfo->semume);
+    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+    unlock_user_struct(target_seminfo, target_addr, 1);
+    return 0;
+}
+
 union semun {
 	int val;
 	struct semid_ds *buf;
 	unsigned short *array;
+	struct seminfo *__buf;
 };
 
 union target_semun {
 	int val;
-	abi_long buf;
-	unsigned short int *array;
+	abi_ulong buf;
+	abi_ulong array;
+	abi_ulong __buf;
 };
 
-static inline abi_long target_to_host_semun(int cmd,
-                                            union semun *host_su,
-                                            abi_ulong target_addr,
-                                            struct semid_ds *ds)
+static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+                                               abi_ulong target_addr)
 {
-    union target_semun *target_su;
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
 
-    switch( cmd ) {
-	case IPC_STAT:
-	case IPC_SET:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-	   target_to_host_semid_ds(ds,target_su->buf);
-	   host_su->buf = ds;
-           unlock_user_struct(target_su, target_addr, 0);
-	   break;
-	case GETVAL:
-	case SETVAL:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-	   host_su->val = tswapl(target_su->val);
-           unlock_user_struct(target_su, target_addr, 0);
-	   break;
-	case GETALL:
-	case SETALL:
-           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
-               return -TARGET_EFAULT;
-	   *host_su->array = tswap16(*target_su->array);
-           unlock_user_struct(target_su, target_addr, 0);
-	   break;
-	default:
-           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    *host_array = malloc(nsems*sizeof(unsigned short));
+    array = lock_user(VERIFY_READ, target_addr,
+                      nsems*sizeof(unsigned short), 1);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __get_user((*host_array)[i], &array[i]);
     }
+    unlock_user(array, target_addr, 0);
+
     return 0;
 }
 
-static inline abi_long host_to_target_semun(int cmd,
-                                            abi_ulong target_addr,
-                                            union semun *host_su,
-                                            struct semid_ds *ds)
+static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+                                               unsigned short **host_array)
 {
-    union target_semun *target_su;
+    int nsems;
+    unsigned short *array;
+    union semun semun;
+    struct semid_ds semid_ds;
+    int i, ret;
 
-    switch( cmd ) {
-	case IPC_STAT:
-	case IPC_SET:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-	   host_to_target_semid_ds(target_su->buf,ds);
-           unlock_user_struct(target_su, target_addr, 1);
-	   break;
-	case GETVAL:
-	case SETVAL:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-	   target_su->val = tswapl(host_su->val);
-           unlock_user_struct(target_su, target_addr, 1);
-	   break;
-	case GETALL:
-	case SETALL:
-           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
-               return -TARGET_EFAULT;
-	   *target_su->array = tswap16(*host_su->array);
-           unlock_user_struct(target_su, target_addr, 1);
-	   break;
-        default:
-           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    semun.buf = &semid_ds;
+
+    ret = semctl(semid, 0, IPC_STAT, semun);
+    if (ret == -1)
+        return get_errno(ret);
+
+    nsems = semid_ds.sem_nsems;
+
+    array = lock_user(VERIFY_WRITE, target_addr,
+                      nsems*sizeof(unsigned short), 0);
+    if (!array)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsems; i++) {
+        __put_user((*host_array)[i], &array[i]);
     }
+    free(*host_array);
+    unlock_user(array, target_addr, 1);
+
     return 0;
 }
 
-static inline abi_long do_semctl(int first, int second, int third,
-                                 abi_long ptr)
+static inline abi_long do_semctl(int semid, int semnum, int cmd,
+                                 union target_semun target_su)
 {
     union semun arg;
     struct semid_ds dsarg;
-    int cmd = third&0xff;
-    abi_long ret = 0;
+    unsigned short *array;
+    struct seminfo seminfo;
+    abi_long ret = -TARGET_EINVAL;
+    abi_long err;
+    cmd &= 0xff;
 
     switch( cmd ) {
 	case GETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
 	case SETVAL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            arg.val = tswapl(target_su.val);
+            ret = get_errno(semctl(semid, semnum, cmd, arg));
+            target_su.val = tswapl(arg.val);
             break;
 	case GETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
 	case SETALL:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            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:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
-            break;
 	case IPC_SET:
-            target_to_host_semun(cmd,&arg,ptr,&dsarg);
-            ret = get_errno(semctl(first, second, cmd, arg));
-            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+	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;
-    default:
-            ret = get_errno(semctl(first, second, cmd, arg));
     }
 
     return ret;
 }
 
+struct target_sembuf {
+    unsigned short sem_num;
+    short sem_op;
+    short sem_flg;
+};
+
+static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+                                             abi_ulong target_addr,
+                                             unsigned nsops)
+{
+    struct target_sembuf *target_sembuf;
+    int i;
+
+    target_sembuf = lock_user(VERIFY_READ, target_addr,
+                              nsops*sizeof(struct target_sembuf), 1);
+    if (!target_sembuf)
+        return -TARGET_EFAULT;
+
+    for(i=0; i<nsops; i++) {
+        __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);
+
+    return 0;
+}
+
+static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
+{
+    struct sembuf sops[nsops];
+
+    if (target_to_host_sembuf(sops, ptr, nsops))
+        return -TARGET_EFAULT;
+
+    return semop(semid, sops, nsops);
+}
+
 struct target_msqid_ds
 {
     struct target_ipc_perm msg_perm;
@@ -2360,7 +2441,7 @@ static abi_long do_ipc(unsigned int call, int first,
 
     switch (call) {
     case IPCOP_semop:
-        ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
+        ret = do_semop(first, ptr, second);
         break;
 
     case IPCOP_semget:
@@ -2368,12 +2449,7 @@ static abi_long do_ipc(unsigned int call, int first,
         break;
 
     case IPCOP_semctl:
-        ret = do_semctl(first, second, third, ptr);
-        break;
-
-    case IPCOP_semtimedop:
-        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
-        ret = -TARGET_ENOSYS;
+        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
         break;
 
     case IPCOP_msgget:
@@ -5184,7 +5260,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
 	break;
 #endif
-
+#ifdef TARGET_NR_semget
+    case TARGET_NR_semget:
+        ret = get_errno(semget(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semop
+    case TARGET_NR_semop:
+        ret = get_errno(do_semop(arg1, arg2, arg3));
+        break;
+#endif
+#ifdef TARGET_NR_semctl
+    case TARGET_NR_semctl:
+        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
+        break;
+#endif
 #ifdef TARGET_NR_msgctl
     case TARGET_NR_msgctl:
         ret = do_msgctl(arg1, arg2, arg3);
-- 
1.6.2.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem*
  2009-04-16 14:23     ` Riku Voipio
@ 2009-04-18 16:16       ` Aurelien Jarno
  0 siblings, 0 replies; 24+ messages in thread
From: Aurelien Jarno @ 2009-04-18 16:16 UTC (permalink / raw)
  To: Riku Voipio; +Cc: qemu-devel

On Thu, Apr 16, 2009 at 05:23:09PM +0300, Riku Voipio wrote:
> On Wed, Apr 15, 2009 at 05:28:23PM +0200, Aurelien Jarno wrote:
> > > +struct target_sembuf {
> > > +    unsigned short sem_num;
> > > +    short sem_op;
> > > +    short sem_flg;
> > > +};
> > > +
> > > +static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
> > > +                                             abi_ulong target_addr,
> > > +                                             unsigned nsops)
> > > +{
> > > +    struct target_sembuf *target_sembuf;
> > > +    int i;
> > > +
> > > +    target_sembuf = lock_user(VERIFY_READ, target_addr,
> > > +                              nsops*sizeof(struct target_sembuf), 1);
> > > +    if (!target_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);
> > > +    }
> 
> > I don't follow fully the subtle difference between __put_user() and
> > __get_user,() but given lock_user is called with VERIFY_READ, I think
> > __get_user() should be used instead.
> 
> Yes.. since the target and host args are swapped, it still works like __get_user.
> Corrected version attached.

Thanks, applied.

> (This error appears also once in the shm* patch too)
> 
> From 32b512d9b521d2b146658f932b9c3553cd3ec1cd Mon Sep 17 00:00:00 2001
> From: Riku Voipio <riku.voipio@iki.fi>
> Date: Fri, 3 Apr 2009 00:28:14 +0300
> Subject: [PATCH] [v2] fix IPCOP_sem* and implement sem*
> 
> From: Kirill A. Shutemov <kirill@shutemov.name>
> 
> Fix and cleanup IPCOP_sem* ipc calls handling and
> implement sem* syscalls.
> 
> Riku:
> 
> 1) Uglify whitespace so that diff gets smaller and easier
> to review
> 
> 2) use __get_user in target_to_host_sembuf
> 
> Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
> ---
>  linux-user/syscall.c |  286 +++++++++++++++++++++++++++++++++-----------------
>  1 files changed, 188 insertions(+), 98 deletions(-)
> 
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 74b41a8..92e5159 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -2005,7 +2005,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
>  
>      if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
>          return -TARGET_EFAULT;
> -    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
> +    if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
> +        return -TARGET_EFAULT;
>      host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
>      host_sd->sem_otime = tswapl(target_sd->sem_otime);
>      host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
> @@ -2020,7 +2021,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
>  
>      if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
>          return -TARGET_EFAULT;
> -    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
> +    if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
> +        return -TARGET_EFAULT;;
>      target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
>      target_sd->sem_otime = tswapl(host_sd->sem_otime);
>      target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
> @@ -2028,135 +2030,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
>      return 0;
>  }
>  
> +struct target_seminfo {
> +    int semmap;
> +    int semmni;
> +    int semmns;
> +    int semmnu;
> +    int semmsl;
> +    int semopm;
> +    int semume;
> +    int semusz;
> +    int semvmx;
> +    int semaem;
> +};
> +
> +static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
> +                                              struct seminfo *host_seminfo)
> +{
> +    struct target_seminfo *target_seminfo;
> +    if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
> +        return -TARGET_EFAULT;
> +    __put_user(host_seminfo->semmap, &target_seminfo->semmap);
> +    __put_user(host_seminfo->semmni, &target_seminfo->semmni);
> +    __put_user(host_seminfo->semmns, &target_seminfo->semmns);
> +    __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
> +    __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
> +    __put_user(host_seminfo->semopm, &target_seminfo->semopm);
> +    __put_user(host_seminfo->semume, &target_seminfo->semume);
> +    __put_user(host_seminfo->semusz, &target_seminfo->semusz);
> +    __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
> +    __put_user(host_seminfo->semaem, &target_seminfo->semaem);
> +    unlock_user_struct(target_seminfo, target_addr, 1);
> +    return 0;
> +}
> +
>  union semun {
>  	int val;
>  	struct semid_ds *buf;
>  	unsigned short *array;
> +	struct seminfo *__buf;
>  };
>  
>  union target_semun {
>  	int val;
> -	abi_long buf;
> -	unsigned short int *array;
> +	abi_ulong buf;
> +	abi_ulong array;
> +	abi_ulong __buf;
>  };
>  
> -static inline abi_long target_to_host_semun(int cmd,
> -                                            union semun *host_su,
> -                                            abi_ulong target_addr,
> -                                            struct semid_ds *ds)
> +static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
> +                                               abi_ulong target_addr)
>  {
> -    union target_semun *target_su;
> +    int nsems;
> +    unsigned short *array;
> +    union semun semun;
> +    struct semid_ds semid_ds;
> +    int i, ret;
>  
> -    switch( cmd ) {
> -	case IPC_STAT:
> -	case IPC_SET:
> -           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
> -               return -TARGET_EFAULT;
> -	   target_to_host_semid_ds(ds,target_su->buf);
> -	   host_su->buf = ds;
> -           unlock_user_struct(target_su, target_addr, 0);
> -	   break;
> -	case GETVAL:
> -	case SETVAL:
> -           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
> -               return -TARGET_EFAULT;
> -	   host_su->val = tswapl(target_su->val);
> -           unlock_user_struct(target_su, target_addr, 0);
> -	   break;
> -	case GETALL:
> -	case SETALL:
> -           if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
> -               return -TARGET_EFAULT;
> -	   *host_su->array = tswap16(*target_su->array);
> -           unlock_user_struct(target_su, target_addr, 0);
> -	   break;
> -	default:
> -           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
> +    semun.buf = &semid_ds;
> +
> +    ret = semctl(semid, 0, IPC_STAT, semun);
> +    if (ret == -1)
> +        return get_errno(ret);
> +
> +    nsems = semid_ds.sem_nsems;
> +
> +    *host_array = malloc(nsems*sizeof(unsigned short));
> +    array = lock_user(VERIFY_READ, target_addr,
> +                      nsems*sizeof(unsigned short), 1);
> +    if (!array)
> +        return -TARGET_EFAULT;
> +
> +    for(i=0; i<nsems; i++) {
> +        __get_user((*host_array)[i], &array[i]);
>      }
> +    unlock_user(array, target_addr, 0);
> +
>      return 0;
>  }
>  
> -static inline abi_long host_to_target_semun(int cmd,
> -                                            abi_ulong target_addr,
> -                                            union semun *host_su,
> -                                            struct semid_ds *ds)
> +static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
> +                                               unsigned short **host_array)
>  {
> -    union target_semun *target_su;
> +    int nsems;
> +    unsigned short *array;
> +    union semun semun;
> +    struct semid_ds semid_ds;
> +    int i, ret;
>  
> -    switch( cmd ) {
> -	case IPC_STAT:
> -	case IPC_SET:
> -           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
> -               return -TARGET_EFAULT;
> -	   host_to_target_semid_ds(target_su->buf,ds);
> -           unlock_user_struct(target_su, target_addr, 1);
> -	   break;
> -	case GETVAL:
> -	case SETVAL:
> -           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
> -               return -TARGET_EFAULT;
> -	   target_su->val = tswapl(host_su->val);
> -           unlock_user_struct(target_su, target_addr, 1);
> -	   break;
> -	case GETALL:
> -	case SETALL:
> -           if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
> -               return -TARGET_EFAULT;
> -	   *target_su->array = tswap16(*host_su->array);
> -           unlock_user_struct(target_su, target_addr, 1);
> -	   break;
> -        default:
> -           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
> +    semun.buf = &semid_ds;
> +
> +    ret = semctl(semid, 0, IPC_STAT, semun);
> +    if (ret == -1)
> +        return get_errno(ret);
> +
> +    nsems = semid_ds.sem_nsems;
> +
> +    array = lock_user(VERIFY_WRITE, target_addr,
> +                      nsems*sizeof(unsigned short), 0);
> +    if (!array)
> +        return -TARGET_EFAULT;
> +
> +    for(i=0; i<nsems; i++) {
> +        __put_user((*host_array)[i], &array[i]);
>      }
> +    free(*host_array);
> +    unlock_user(array, target_addr, 1);
> +
>      return 0;
>  }
>  
> -static inline abi_long do_semctl(int first, int second, int third,
> -                                 abi_long ptr)
> +static inline abi_long do_semctl(int semid, int semnum, int cmd,
> +                                 union target_semun target_su)
>  {
>      union semun arg;
>      struct semid_ds dsarg;
> -    int cmd = third&0xff;
> -    abi_long ret = 0;
> +    unsigned short *array;
> +    struct seminfo seminfo;
> +    abi_long ret = -TARGET_EINVAL;
> +    abi_long err;
> +    cmd &= 0xff;
>  
>      switch( cmd ) {
>  	case GETVAL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> -            break;
>  	case SETVAL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> +            arg.val = tswapl(target_su.val);
> +            ret = get_errno(semctl(semid, semnum, cmd, arg));
> +            target_su.val = tswapl(arg.val);
>              break;
>  	case GETALL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> -            break;
>  	case SETALL:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> +            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:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> -            break;
>  	case IPC_SET:
> -            target_to_host_semun(cmd,&arg,ptr,&dsarg);
> -            ret = get_errno(semctl(first, second, cmd, arg));
> -            host_to_target_semun(cmd,ptr,&arg,&dsarg);
> +	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;
> -    default:
> -            ret = get_errno(semctl(first, second, cmd, arg));
>      }
>  
>      return ret;
>  }
>  
> +struct target_sembuf {
> +    unsigned short sem_num;
> +    short sem_op;
> +    short sem_flg;
> +};
> +
> +static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
> +                                             abi_ulong target_addr,
> +                                             unsigned nsops)
> +{
> +    struct target_sembuf *target_sembuf;
> +    int i;
> +
> +    target_sembuf = lock_user(VERIFY_READ, target_addr,
> +                              nsops*sizeof(struct target_sembuf), 1);
> +    if (!target_sembuf)
> +        return -TARGET_EFAULT;
> +
> +    for(i=0; i<nsops; i++) {
> +        __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);
> +
> +    return 0;
> +}
> +
> +static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
> +{
> +    struct sembuf sops[nsops];
> +
> +    if (target_to_host_sembuf(sops, ptr, nsops))
> +        return -TARGET_EFAULT;
> +
> +    return semop(semid, sops, nsops);
> +}
> +
>  struct target_msqid_ds
>  {
>      struct target_ipc_perm msg_perm;
> @@ -2360,7 +2441,7 @@ static abi_long do_ipc(unsigned int call, int first,
>  
>      switch (call) {
>      case IPCOP_semop:
> -        ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
> +        ret = do_semop(first, ptr, second);
>          break;
>  
>      case IPCOP_semget:
> @@ -2368,12 +2449,7 @@ static abi_long do_ipc(unsigned int call, int first,
>          break;
>  
>      case IPCOP_semctl:
> -        ret = do_semctl(first, second, third, ptr);
> -        break;
> -
> -    case IPCOP_semtimedop:
> -        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
> -        ret = -TARGET_ENOSYS;
> +        ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
>          break;
>  
>      case IPCOP_msgget:
> @@ -5184,7 +5260,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
>  	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
>  	break;
>  #endif
> -
> +#ifdef TARGET_NR_semget
> +    case TARGET_NR_semget:
> +        ret = get_errno(semget(arg1, arg2, arg3));
> +        break;
> +#endif
> +#ifdef TARGET_NR_semop
> +    case TARGET_NR_semop:
> +        ret = get_errno(do_semop(arg1, arg2, arg3));
> +        break;
> +#endif
> +#ifdef TARGET_NR_semctl
> +    case TARGET_NR_semctl:
> +        ret = do_semctl(arg1, arg2, arg3, (union target_semun)(abi_ulong)arg4);
> +        break;
> +#endif
>  #ifdef TARGET_NR_msgctl
>      case TARGET_NR_msgctl:
>          ret = do_msgctl(arg1, arg2, arg3);
> -- 
> 1.6.2.1
> 
> 

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2009-04-18 16:16 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-05 20:59 [Qemu-devel] [PATCH 00/10] misc userland patches [v2] riku.voipio
2009-04-05 20:59 ` [Qemu-devel] [PATCH 01/10] Fix fstatat64()/newfstatat() syscall implementation riku.voipio
2009-04-05 20:59 ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets riku.voipio
2009-04-05 20:59   ` [Qemu-devel] [PATCH 03/10] Implement shm* syscalls and fix 64/32bit errors riku.voipio
2009-04-15 16:21   ` [Qemu-devel] [PATCH 02/10] Rewrite mmap_find_vma() to work fine on 64-bit hosts with 32-bit targets Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 04/10] fix IPCOP_sem* and implement sem* riku.voipio
2009-04-06  9:06   ` Arnaud Patard
2009-04-06 15:17     ` Riku Voipio
2009-04-06 16:22       ` Arnaud Patard
2009-04-15 15:28   ` Aurelien Jarno
2009-04-16 14:23     ` Riku Voipio
2009-04-18 16:16       ` Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 05/10] Added posix message queue syscalls except mq_notify riku.voipio
2009-04-15 16:13   ` Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 06/10] Add support for passing contents of argv0 riku.voipio
2009-04-15 16:13   ` Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 07/10] linux-user: unix sockets - fix running dbus riku.voipio
2009-04-15 16:14   ` Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 08/10] linux-user: removed unnecessary MAX_SOCK_ADDR checks for socket syscalls riku.voipio
2009-04-15 16:14   ` Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 09/10] Prefer glibc over direct syscalls riku.voipio
2009-04-15 16:14   ` Aurelien Jarno
2009-04-05 20:59 ` [Qemu-devel] [PATCH 10/10] linux-user: Proper exit code for uncaught signals riku.voipio
2009-04-15 16:19   ` Aurelien Jarno

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.