Add -name option, by Anthony Liguori.
[qemu] / linux-user / syscall.c
index e952128..5eb5b39 100644 (file)
 #include <fcntl.h>
 #include <time.h>
 #include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
 #include <sys/wait.h>
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
+#include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/mman.h>
 #include <sys/swap.h>
@@ -42,6 +45,7 @@
 #include <sys/poll.h>
 #include <sys/times.h>
 #include <sys/shm.h>
+#include <sys/sem.h>
 #include <sys/statfs.h>
 #include <utime.h>
 #include <sys/sysinfo.h>
@@ -139,6 +143,7 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6)       \
 #define __NR_sys_getdents __NR_getdents
 #define __NR_sys_getdents64 __NR_getdents64
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
+#define __NR_sys_syslog __NR_syslog
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -158,9 +163,13 @@ _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
+_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 #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
 
 extern int personality(int);
 extern int flock(int, int);
@@ -841,7 +850,7 @@ static long do_accept(int fd, target_ulong target_addr,
                       target_ulong target_addrlen)
 {
     socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(target_addrlen);
+    void *addr = alloca(addrlen);
     long ret;
 
     ret = get_errno(accept(fd, addr, &addrlen));
@@ -856,7 +865,7 @@ static long do_getpeername(int fd, target_ulong target_addr,
                            target_ulong target_addrlen)
 {
     socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(target_addrlen);
+    void *addr = alloca(addrlen);
     long ret;
 
     ret = get_errno(getpeername(fd, addr, &addrlen));
@@ -871,7 +880,7 @@ static long do_getsockname(int fd, target_ulong target_addr,
                            target_ulong target_addrlen)
 {
     socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(target_addrlen);
+    void *addr = alloca(addrlen);
     long ret;
 
     ret = get_errno(getsockname(fd, addr, &addrlen));
@@ -1114,6 +1123,12 @@ static struct shm_region {
     uint32_t   size;
 } shm_regions[N_SHM_REGIONS];
 
+union semun {
+       int val;
+       struct senid_ds *buf;
+       unsigned short *array;
+};
+
 /* ??? This only works with linear mappings.  */
 static long do_ipc(long call, long first, long second, long third,
                   long ptr, long fifth)
@@ -1128,6 +1143,52 @@ static long do_ipc(long call, long first, long second, long third,
     call &= 0xffff;
 
     switch (call) {
+    case IPCOP_semop:
+        ret = get_errno(semop(first,(struct sembuf *) ptr, second));
+        break;
+
+    case IPCOP_semget:
+        ret = get_errno(semget(first, second, third));
+        break;
+
+    case IPCOP_semctl:
+        ret = get_errno(semctl(first, second, third, ((union semun*)ptr)->val));
+
+        break;
+
+    case IPCOP_semtimedop:
+        gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
+        ret = -ENOSYS;
+        break;
+
+       case IPCOP_msgget:
+               ret = get_errno(msgget(first, second));
+               break;
+
+       case IPCOP_msgsnd:
+               ret = get_errno(msgsnd(first, (struct msgbuf *) ptr, second, third));
+               break;
+
+       case IPCOP_msgctl:
+               ret = get_errno(msgctl(first, second, (struct msqid_ds *) ptr));
+               break;
+
+       case IPCOP_msgrcv:
+               {
+                       struct ipc_kludge
+                       {
+                               void *__unbounded msgp;
+                               long int msgtyp;
+                       };
+
+                       struct ipc_kludge *foo = (struct ipc_kludge *) ptr;
+                       struct msgbuf *msgp = (struct msgbuf *) foo->msgp;
+
+                       ret = get_errno(msgrcv(first, msgp, second, 0, third));
+
+               }
+               break;
+
     case IPCOP_shmat:
        /* SHM_* flags are the same on all linux platforms */
        ret = get_errno((long) shmat(first, (void *) ptr, second));
@@ -1664,8 +1725,7 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
         ts->next = first_task_state;
         first_task_state = ts;
         /* we create a new CPU instance. */
-        new_env = cpu_init();
-        memcpy(new_env, env, sizeof(CPUState));
+        new_env = cpu_copy(env);
 #if defined(TARGET_I386)
         if (!newsp)
             newsp = env->regs[R_ESP];
@@ -1727,6 +1787,8 @@ static long do_fcntl(int fd, int cmd, target_ulong arg)
 {
     struct flock fl;
     struct target_flock *target_fl;
+    struct flock64 fl64;
+    struct target_flock64 *target_fl64;
     long ret;
 
     switch(cmd) {
@@ -1756,10 +1818,27 @@ static long do_fcntl(int fd, int cmd, target_ulong arg)
         break;
         
     case TARGET_F_GETLK64:
+        ret = fcntl(fd, cmd >> 1, &fl64);
+        if (ret == 0) {
+            lock_user_struct(target_fl64, arg, 0);
+            target_fl64->l_type = tswap16(fl64.l_type) >> 1;
+            target_fl64->l_whence = tswap16(fl64.l_whence);
+            target_fl64->l_start = tswapl(fl64.l_start);
+            target_fl64->l_len = tswapl(fl64.l_len);
+            target_fl64->l_pid = tswapl(fl64.l_pid);
+            unlock_user_struct(target_fl64, arg, 1);
+        }
+               break;
     case TARGET_F_SETLK64:
     case TARGET_F_SETLKW64:
-        ret = -1;
-        errno = EINVAL;
+        lock_user_struct(target_fl64, arg, 1);
+        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
+        fl64.l_whence = tswap16(target_fl64->l_whence);
+        fl64.l_start = tswapl(target_fl64->l_start);
+        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_pid = tswap16(target_fl64->l_pid);
+        unlock_user_struct(target_fl64, arg, 0);
+               ret = fcntl(fd, cmd >> 1, &fl64);
         break;
 
     case F_GETFL:
@@ -2088,8 +2167,18 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = get_errno(getpid());
         break;
     case TARGET_NR_mount:
-        /* need to look at the data field */
-        goto unimplemented;
+               {
+                       /* need to look at the data field */
+                       void *p2, *p3;
+                       p = lock_user_string(arg1);
+                       p2 = lock_user_string(arg2);
+                       p3 = lock_user_string(arg3);
+                       ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5));
+                       unlock_user(p, arg1, 0);
+                       unlock_user(p2, arg2, 0);
+                       unlock_user(p3, arg3, 0);
+                       break;
+               }
     case TARGET_NR_umount:
         p = lock_user_string(arg1);
         ret = get_errno(umount(p));
@@ -2673,7 +2762,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         break;
 #ifdef TARGET_NR_mmap2
     case TARGET_NR_mmap2:
-#if defined(TARGET_SPARC)
+#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
 #define MMAP_SHIFT 12
 #else
 #define MMAP_SHIFT TARGET_PAGE_BITS
@@ -2827,12 +2916,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 #endif
 #ifdef TARGET_NR_recv
     case TARGET_NR_recv:
-        ret = do_recvfrom(arg1, arg1, arg3, arg4, 0, 0);
+        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
         break;
 #endif
 #ifdef TARGET_NR_recvfrom
     case TARGET_NR_recvfrom:
-        ret = do_recvfrom(arg1, arg1, arg3, arg4, arg5, arg6);
+        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 #endif
 #ifdef TARGET_NR_recvmsg
@@ -2875,9 +2964,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
         break;
 #endif
-        
+
     case TARGET_NR_syslog:
-        goto unimplemented;
+        p = lock_user_string(arg2);
+        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
+        unlock_user(p, arg2, 0);
+        break;
+
     case TARGET_NR_setitimer:
         {
             struct itimerval value, ovalue, *pvalue;
@@ -2933,7 +3026,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
                 lock_user_struct(target_st, arg2, 0);
                 target_st->st_dev = tswap16(st.st_dev);
                 target_st->st_ino = tswapl(st.st_ino);
-#if defined(TARGET_PPC)
+#if defined(TARGET_PPC) || defined(TARGET_MIPS)
                 target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
                 target_st->st_uid = tswap32(st.st_uid);
                 target_st->st_gid = tswap32(st.st_gid);
@@ -3346,7 +3439,21 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_nfsservctl:
         goto unimplemented;
     case TARGET_NR_prctl:
-        goto unimplemented;
+        switch (arg1)
+            {
+            case PR_GET_PDEATHSIG:
+                {
+                    int deathsig;
+                    ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
+                    if (!is_error(ret) && arg2)
+                        tput32(arg2, deathsig);
+                }
+                break;
+            default:
+                ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
+                break;
+            }
+        break;
 #ifdef TARGET_NR_pread
     case TARGET_NR_pread:
         page_unprotect_range(arg2, arg3);
@@ -3829,6 +3936,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
        break;
     }
 #endif
+#ifdef TARGET_NR_cacheflush
+    case TARGET_NR_cacheflush:
+        /* self-modifying code is handled automatically, so nothing needed */
+        ret = 0;
+        break;
+#endif
 #ifdef TARGET_NR_security
     case TARGET_NR_security:
         goto unimplemented;
@@ -3860,6 +3973,15 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 #endif
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
+#ifdef TARGET_MIPS
+      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+      ret = 0;
+      break;
+#else
+      goto unimplemented_nowarn;
+#endif
+#endif
+#ifdef TARGET_NR_get_thread_area
     case TARGET_NR_get_thread_area:
         goto unimplemented_nowarn;
 #endif
@@ -3867,10 +3989,40 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_getdomainname:
         goto unimplemented_nowarn;
 #endif
+
+#ifdef TARGET_NR_clock_gettime
+    case TARGET_NR_clock_gettime:
+    {
+        struct timespec ts;
+        ret = get_errno(clock_gettime(arg1, &ts));
+        if (!is_error(ret)) {
+            host_to_target_timespec(arg2, &ts);
+        }
+        break;
+    }
+#endif
+#ifdef TARGET_NR_clock_getres
+    case TARGET_NR_clock_getres:
+    {
+        struct timespec ts;
+        ret = get_errno(clock_getres(arg1, &ts));
+        if (!is_error(ret)) {
+            host_to_target_timespec(arg2, &ts);
+        }
+        break;
+    }
+#endif
+
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+    case TARGET_NR_set_tid_address:
+      ret = get_errno(set_tid_address((int *) arg1));
+      break;
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);
-#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname)
+#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname)
     unimplemented_nowarn:
 #endif
         ret = -ENOSYS;