*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <limits.h>
-#include <dirent.h>
+#include <mqueue.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#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>
#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>
#include <qemu-common.h>
+#ifdef HAVE_GPROF
+#include <sys/gmon.h>
+#endif
#define termios host_termios
#define winsize host_winsize
#include <linux/soundcard.h>
#include <linux/kd.h>
#include <linux/mtio.h>
+#include <linux/fs.h>
#include "linux_loop.h"
#include "qemu.h"
//#define DEBUG
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
- || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
-/* 16 bit uid wrappers emulation */
-#define USE_UID16
-#endif
-
//#include <linux/msdos_fs.h>
-#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
-#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
+#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
+#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
#undef _syscall0
#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
#define __NR_sys_unlinkat __NR_unlinkat
#define __NR_sys_utimensat __NR_utimensat
#define __NR_sys_futex __NR_futex
+#define __NR_sys_inotify_init __NR_inotify_init
+#define __NR_sys_inotify_add_watch __NR_inotify_add_watch
+#define __NR_sys_inotify_rm_watch __NR_inotify_rm_watch
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define __NR__llseek __NR_lseek
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(TARGET_NR__llseek) && !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 strlen(buf)+1;
+}
+
+#ifdef CONFIG_ATFILE
+/*
+ * Host system seems to have atfile syscall stubs available. We
+ * now enable them one by one as specified by target syscall_nr.h.
+ */
+
+#ifdef TARGET_NR_faccessat
+static int sys_faccessat(int dirfd, const char *pathname, int mode)
+{
+ return (faccessat(dirfd, pathname, mode, 0));
+}
+#endif
+#ifdef TARGET_NR_fchmodat
+static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
+{
+ return (fchmodat(dirfd, pathname, mode, 0));
+}
+#endif
+#if defined(TARGET_NR_fchownat) && defined(USE_UID16)
+static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
+ gid_t group, int flags)
+{
+ return (fchownat(dirfd, pathname, owner, group, flags));
+}
+#endif
+#ifdef __NR_fstatat64
+static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+ int flags)
+{
+ return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef __NR_newfstatat
+static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
+ int flags)
+{
+ return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef TARGET_NR_futimesat
+static int sys_futimesat(int dirfd, const char *pathname,
+ const struct timeval times[2])
+{
+ return (futimesat(dirfd, pathname, times));
+}
+#endif
+#ifdef TARGET_NR_linkat
+static int sys_linkat(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, int flags)
+{
+ return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+}
+#endif
+#ifdef TARGET_NR_mkdirat
+static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+ return (mkdirat(dirfd, pathname, mode));
+}
+#endif
+#ifdef TARGET_NR_mknodat
+static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
+ dev_t dev)
+{
+ return (mknodat(dirfd, pathname, mode, dev));
+}
+#endif
+#ifdef TARGET_NR_openat
+static int sys_openat(int dirfd, const char *pathname, int flags, ...)
+{
+ /*
+ * 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
+#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)
+_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
#endif
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
-_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
- mode_t,mode,int,flags)
+_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
#endif
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
uid_t,owner,gid_t,group,int,flags)
#endif
-#if defined(TARGET_NR_fstatat64) && defined(__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
_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 dirent *, dirp, uint, count);
-#endif
-#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
-_syscall3(int, sys_getdents64, uint, fd, struct 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)
_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
+
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_UTIMENSAT
+static int sys_utimensat(int dirfd, const char *pathname,
+ const struct timespec times[2], int flags)
+{
+ if (pathname == NULL)
+ return futimens(dirfd, times);
+ else
+ return utimensat(dirfd, pathname, times, flags);
+}
+#else
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
const struct timespec *,tsp,int,flags)
#endif
-#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 /* CONFIG_UTIMENSAT */
+
+#ifdef CONFIG_INOTIFY
+#include <sys/inotify.h>
+
+#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
+static int sys_inotify_init(void)
+{
+ return (inotify_init());
+}
+#endif
+#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
+static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
+{
+ return (inotify_add_watch(fd, pathname, mask));
+}
#endif
+#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
+static int sys_inotify_rm_watch(int fd, int32_t wd)
+{
+ return (inotify_rm_watch(fd, 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);
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,
return ret;
}
+static abi_long do_pipe2(int host_pipe[], int flags)
+{
+#ifdef CONFIG_PIPE2
+ return pipe2(host_pipe, flags);
+#else
+ return -ENOSYS;
+#endif
+}
+
+static abi_long do_pipe(void *cpu_env, int pipedes, int flags)
+{
+ int host_pipe[2];
+ abi_long ret;
+ ret = flags ? do_pipe2(host_pipe, flags) : pipe(host_pipe);
+
+ if (is_error(ret))
+ return get_errno(ret);
+#if defined(TARGET_MIPS)
+ ((CPUMIPSState*)cpu_env)->active_tc.gpr[3] = host_pipe[1];
+ ret = host_pipe[0];
+#elif defined(TARGET_SH4)
+ ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
+ ret = host_pipe[0];
+#else
+ if (put_user_s32(host_pipe[0], pipedes)
+ || put_user_s32(host_pipe[1], pipedes + sizeof(host_pipe[0])))
+ return -TARGET_EFAULT;
+#endif
+ return get_errno(ret);
+}
+
+static inline abi_long target_to_host_ip_mreq(struct ip_mreqn *mreqn,
+ abi_ulong target_addr,
+ socklen_t len)
+{
+ struct target_ip_mreqn *target_smreqn;
+
+ target_smreqn = lock_user(VERIFY_READ, target_addr, len, 1);
+ if (!target_smreqn)
+ return -TARGET_EFAULT;
+ mreqn->imr_multiaddr.s_addr = target_smreqn->imr_multiaddr.s_addr;
+ mreqn->imr_address.s_addr = target_smreqn->imr_address.s_addr;
+ if (len == sizeof(struct target_ip_mreqn))
+ mreqn->imr_ifindex = tswapl(target_smreqn->imr_ifindex);
+ unlock_user(target_smreqn, target_addr, 0);
+
+ return 0;
+}
+
static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
abi_ulong target_addr,
socklen_t len)
{
+ const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
+ sa_family_t sa_family;
struct target_sockaddr *target_saddr;
target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
if (!target_saddr)
return -TARGET_EFAULT;
+
+ sa_family = tswap16(target_saddr->sa_family);
+
+ /* Oops. The caller might send a incomplete sun_path; sun_path
+ * must be terminated by \0 (see the manual page), but
+ * unfortunately it is quite common to specify sockaddr_un
+ * length as "strlen(x->sun_path)" while it should be
+ * "strlen(...) + 1". We'll fix that here if needed.
+ * Linux kernel has a similar feature.
+ */
+
+ if (sa_family == AF_UNIX) {
+ if (len < unix_maxlen && len > 0) {
+ char *cp = (char*)target_saddr;
+
+ if ( cp[len-1] && !cp[len] )
+ len++;
+ }
+ if (len > unix_maxlen)
+ len = unix_maxlen;
+ }
+
memcpy(addr, target_saddr, len);
- addr->sa_family = tswap16(target_saddr->sa_family);
+ addr->sa_family = sa_family;
unlock_user(target_saddr, target_addr, 0);
return 0;
{
abi_long ret;
int val;
+ struct ip_mreqn *ip_mreq;
+ struct ip_mreq_source *ip_mreq_source;
switch(level) {
case SOL_TCP:
}
ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
break;
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ if (optlen < sizeof (struct target_ip_mreq) ||
+ optlen > sizeof (struct target_ip_mreqn))
+ return -TARGET_EINVAL;
+
+ ip_mreq = (struct ip_mreqn *) alloca(optlen);
+ target_to_host_ip_mreq(ip_mreq, optval_addr, optlen);
+ ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq, optlen));
+ break;
+
+ case IP_BLOCK_SOURCE:
+ case IP_UNBLOCK_SOURCE:
+ case IP_ADD_SOURCE_MEMBERSHIP:
+ case IP_DROP_SOURCE_MEMBERSHIP:
+ if (optlen != sizeof (struct target_ip_mreq_source))
+ return -TARGET_EINVAL;
+
+ ip_mreq_source = lock_user(VERIFY_READ, optval_addr, optlen, 1);
+ ret = get_errno(setsockopt(sockfd, level, optname, ip_mreq_source, optlen));
+ unlock_user (ip_mreq_source, optval_addr, 0);
+ break;
+
default:
goto unimplemented;
}
{
struct target_iovec *target_vec;
abi_ulong base;
- int i, j;
+ int i;
target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
if (!target_vec)
vec[i].iov_len = tswapl(target_vec[i].iov_len);
if (vec[i].iov_len != 0) {
vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
- if (!vec[i].iov_base && vec[i].iov_len)
- goto fail;
+ /* Don't check lock_user return value. We must call writev even
+ if a element has invalid base address. */
} else {
/* zero length pointer is ignored */
vec[i].iov_base = NULL;
}
unlock_user (target_vec, target_addr, 0);
return 0;
- fail:
- /* failure - unwind locks */
- for (j = 0; j < i; j++) {
- base = tswapl(target_vec[j].iov_base);
- unlock_user(vec[j].iov_base, base, 0);
- }
- unlock_user (target_vec, target_addr, 0);
- return -TARGET_EFAULT;
}
static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
if (!target_vec)
return -TARGET_EFAULT;
for(i = 0;i < count; i++) {
- base = tswapl(target_vec[i].iov_base);
- unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
+ if (target_vec[i].iov_base) {
+ base = tswapl(target_vec[i].iov_base);
+ unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
+ }
}
unlock_user (target_vec, target_addr, 0);
static abi_long do_bind(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
- void *addr = alloca(addrlen);
+ void *addr;
+
+ if (addrlen < 0)
+ return -TARGET_EINVAL;
+
+ addr = alloca(addrlen+1);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(bind(sockfd, addr, addrlen));
static abi_long do_connect(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
- void *addr = alloca(addrlen);
+ void *addr;
+
+ if (addrlen < 0)
+ return -TARGET_EINVAL;
+
+ addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(connect(sockfd, addr, addrlen));
static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg,
int flags, int send)
{
- abi_long ret;
+ abi_long ret, len;
struct target_msghdr *msgp;
struct msghdr msg;
int count;
ret = get_errno(sendmsg(fd, &msg, flags));
} else {
ret = get_errno(recvmsg(fd, &msg, flags));
- if (!is_error(ret))
+ if (!is_error(ret)) {
+ len = ret;
ret = host_to_target_cmsg(msgp, &msg);
+ if (!is_error(ret))
+ ret = len;
+ }
}
unlock_iovec(vec, target_vec, count, !send);
unlock_user_struct(msgp, target_msg, send ? 0 : 1);
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
+ if (addrlen < 0)
+ return -TARGET_EINVAL;
+
addr = alloca(addrlen);
ret = get_errno(accept(fd, addr, &addrlen));
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
+ if (addrlen < 0)
+ return -TARGET_EINVAL;
+
addr = alloca(addrlen);
ret = get_errno(getpeername(fd, addr, &addrlen));
void *addr;
abi_long ret;
+ if (target_addr == 0)
+ return get_errno(accept(fd, NULL, NULL));
+
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
+ if (addrlen < 0)
+ return -TARGET_EINVAL;
+
addr = alloca(addrlen);
ret = get_errno(getsockname(fd, addr, &addrlen));
void *host_msg;
abi_long ret;
+ if (addrlen < 0)
+ return -TARGET_EINVAL;
+
host_msg = lock_user(VERIFY_READ, msg, len, 1);
if (!host_msg)
return -TARGET_EFAULT;
ret = -TARGET_EFAULT;
goto fail;
}
+ if (addrlen < 0) {
+ ret = -TARGET_EINVAL;
+ goto fail;
+ }
addr = alloca(addrlen);
ret = get_errno(recvfrom(fd, host_msg, len, flags, addr, &addrlen));
} else {
}
#endif
-#ifdef TARGET_NR_ipc
#define N_SHM_REGIONS 32
static struct shm_region {
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);
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);
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;
- abi_ulong msg_stime;
- abi_ulong __unused1;
- abi_ulong msg_rtime;
- abi_ulong __unused2;
- abi_ulong msg_ctime;
- abi_ulong __unused3;
- abi_ulong __msg_cbytes;
- abi_ulong msg_qnum;
- abi_ulong msg_qbytes;
- abi_ulong msg_lspid;
- abi_ulong msg_lrpid;
- abi_ulong __unused4;
- abi_ulong __unused5;
+ struct target_ipc_perm msg_perm;
+ abi_ulong msg_stime;
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused1;
+#endif
+ abi_ulong msg_rtime;
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused2;
+#endif
+ abi_ulong msg_ctime;
+#if TARGET_ABI_BITS == 32
+ abi_ulong __unused3;
+#endif
+ abi_ulong __msg_cbytes;
+ abi_ulong msg_qnum;
+ abi_ulong msg_qbytes;
+ abi_ulong msg_lspid;
+ abi_ulong msg_lrpid;
+ abi_ulong __unused4;
+ abi_ulong __unused5;
};
static inline abi_long target_to_host_msqid_ds(struct msqid_ds *host_md,
if (!lock_user_struct(VERIFY_READ, target_md, target_addr, 1))
return -TARGET_EFAULT;
- target_to_host_ipc_perm(&(host_md->msg_perm),target_addr);
+ if (target_to_host_ipc_perm(&(host_md->msg_perm),target_addr))
+ return -TARGET_EFAULT;
host_md->msg_stime = tswapl(target_md->msg_stime);
host_md->msg_rtime = tswapl(target_md->msg_rtime);
host_md->msg_ctime = tswapl(target_md->msg_ctime);
if (!lock_user_struct(VERIFY_WRITE, target_md, target_addr, 0))
return -TARGET_EFAULT;
- host_to_target_ipc_perm(target_addr,&(host_md->msg_perm));
+ if (host_to_target_ipc_perm(target_addr,&(host_md->msg_perm)))
+ return -TARGET_EFAULT;
target_md->msg_stime = tswapl(host_md->msg_stime);
target_md->msg_rtime = tswapl(host_md->msg_rtime);
target_md->msg_ctime = tswapl(host_md->msg_ctime);
return 0;
}
-static inline abi_long do_msgctl(int first, int second, abi_long ptr)
+struct target_msginfo {
+ int msgpool;
+ int msgmap;
+ int msgmax;
+ int msgmnb;
+ int msgmni;
+ int msgssz;
+ int msgtql;
+ unsigned short int msgseg;
+};
+
+static inline abi_long host_to_target_msginfo(abi_ulong target_addr,
+ struct msginfo *host_msginfo)
+{
+ struct target_msginfo *target_msginfo;
+ if (!lock_user_struct(VERIFY_WRITE, target_msginfo, target_addr, 0))
+ return -TARGET_EFAULT;
+ __put_user(host_msginfo->msgpool, &target_msginfo->msgpool);
+ __put_user(host_msginfo->msgmap, &target_msginfo->msgmap);
+ __put_user(host_msginfo->msgmax, &target_msginfo->msgmax);
+ __put_user(host_msginfo->msgmnb, &target_msginfo->msgmnb);
+ __put_user(host_msginfo->msgmni, &target_msginfo->msgmni);
+ __put_user(host_msginfo->msgssz, &target_msginfo->msgssz);
+ __put_user(host_msginfo->msgtql, &target_msginfo->msgtql);
+ __put_user(host_msginfo->msgseg, &target_msginfo->msgseg);
+ unlock_user_struct(target_msginfo, target_addr, 1);
+ return 0;
+}
+
+static inline abi_long do_msgctl(int msgid, int cmd, abi_long ptr)
{
struct msqid_ds dsarg;
- int cmd = second&0xff;
+ struct msginfo msginfo;
+ abi_long ret = -TARGET_EINVAL;
+
+ cmd &= 0xff;
+
+ switch (cmd) {
+ case IPC_STAT:
+ case IPC_SET:
+ case MSG_STAT:
+ if (target_to_host_msqid_ds(&dsarg,ptr))
+ return -TARGET_EFAULT;
+ ret = get_errno(msgctl(msgid, cmd, &dsarg));
+ if (host_to_target_msqid_ds(ptr,&dsarg))
+ return -TARGET_EFAULT;
+ break;
+ case IPC_RMID:
+ ret = get_errno(msgctl(msgid, cmd, NULL));
+ break;
+ case IPC_INFO:
+ case MSG_INFO:
+ ret = get_errno(msgctl(msgid, cmd, (struct msqid_ds *)&msginfo));
+ if (host_to_target_msginfo(ptr, &msginfo))
+ return -TARGET_EFAULT;
+ break;
+ }
+
+ return ret;
+}
+
+struct target_msgbuf {
+ abi_long mtype;
+ char mtext[1];
+};
+
+static inline abi_long do_msgsnd(int msqid, abi_long msgp,
+ unsigned int msgsz, int msgflg)
+{
+ struct target_msgbuf *target_mb;
+ struct msgbuf *host_mb;
abi_long ret = 0;
- switch( cmd ) {
+
+ if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
+ return -TARGET_EFAULT;
+ host_mb = malloc(msgsz+sizeof(long));
+ host_mb->mtype = (abi_long) tswapl(target_mb->mtype);
+ memcpy(host_mb->mtext, target_mb->mtext, msgsz);
+ ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
+ free(host_mb);
+ unlock_user_struct(target_mb, msgp, 0);
+
+ return ret;
+}
+
+static inline abi_long do_msgrcv(int msqid, abi_long msgp,
+ unsigned int msgsz, abi_long msgtyp,
+ int msgflg)
+{
+ struct target_msgbuf *target_mb;
+ char *target_mtext;
+ struct msgbuf *host_mb;
+ abi_long ret = 0;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
+ return -TARGET_EFAULT;
+
+ host_mb = malloc(msgsz+sizeof(long));
+ ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapl(msgtyp), msgflg));
+
+ if (ret > 0) {
+ abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
+ target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
+ if (!target_mtext) {
+ ret = -TARGET_EFAULT;
+ goto end;
+ }
+ memcpy(target_mb->mtext, host_mb->mtext, ret);
+ unlock_user(target_mtext, target_mtext_addr, ret);
+ }
+
+ target_mb->mtype = tswapl(host_mb->mtype);
+ free(host_mb);
+
+end:
+ if (target_mb)
+ unlock_user_struct(target_mb, msgp, 1);
+ 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;
+ __get_user(host_sd->shm_segsz, &target_sd->shm_segsz);
+ __get_user(host_sd->shm_atime, &target_sd->shm_atime);
+ __get_user(host_sd->shm_dtime, &target_sd->shm_dtime);
+ __get_user(host_sd->shm_ctime, &target_sd->shm_ctime);
+ __get_user(host_sd->shm_cpid, &target_sd->shm_cpid);
+ __get_user(host_sd->shm_lpid, &target_sd->shm_lpid);
+ __get_user(host_sd->shm_nattch, &target_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:
- target_to_host_msqid_ds(&dsarg,ptr);
- ret = get_errno(msgctl(first, cmd, &dsarg));
- host_to_target_msqid_ds(ptr,&dsarg);
- default:
- ret = get_errno(msgctl(first, cmd, &dsarg));
+ 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);
}
- return ret;
-}
-struct target_msgbuf {
- abi_ulong mtype;
- char mtext[1];
-};
+ if (host_raddr == (void *)-1) {
+ mmap_unlock();
+ return get_errno((long)host_raddr);
+ }
+ raddr=h2g((unsigned long)host_raddr);
-static inline abi_long do_msgsnd(int msqid, abi_long msgp,
- unsigned int msgsz, int msgflg)
-{
- struct target_msgbuf *target_mb;
- struct msgbuf *host_mb;
- abi_long ret = 0;
+ page_set_flags(raddr, raddr + shm_info.shm_segsz,
+ PAGE_VALID | PAGE_READ |
+ ((shmflg & SHM_RDONLY)? 0 : PAGE_WRITE));
- if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0))
- return -TARGET_EFAULT;
- host_mb = malloc(msgsz+sizeof(long));
- host_mb->mtype = tswapl(target_mb->mtype);
- memcpy(host_mb->mtext,target_mb->mtext,msgsz);
- ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
- free(host_mb);
- unlock_user_struct(target_mb, msgp, 0);
+ 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;
- return ret;
}
-static inline abi_long do_msgrcv(int msqid, abi_long msgp,
- unsigned int msgsz, int msgtype,
- int msgflg)
+static inline abi_long do_shmdt(abi_ulong shmaddr)
{
- struct target_msgbuf *target_mb;
- char *target_mtext;
- struct msgbuf *host_mb;
- abi_long ret = 0;
+ int i;
- if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
- return -TARGET_EFAULT;
- host_mb = malloc(msgsz+sizeof(long));
- ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg));
- if (ret > 0) {
- abi_ulong target_mtext_addr = msgp + sizeof(abi_ulong);
- target_mtext = lock_user(VERIFY_WRITE, target_mtext_addr, ret, 0);
- if (!target_mtext) {
- ret = -TARGET_EFAULT;
- goto end;
+ 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;
}
- memcpy(target_mb->mtext, host_mb->mtext, ret);
- unlock_user(target_mtext, target_mtext_addr, ret);
}
- target_mb->mtype = tswapl(host_mb->mtype);
- free(host_mb);
-end:
- if (target_mb)
- unlock_user_struct(target_mb, msgp, 1);
- return ret;
+ 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. */
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;
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:
break;
case IPCOP_semctl:
- ret = do_semctl(first, second, third, ptr);
+ ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
break;
- case IPCOP_semtimedop:
- gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
- ret = -TARGET_ENOSYS;
+ case IPCOP_msgget:
+ ret = get_errno(msgget(first, second));
break;
- case IPCOP_msgget:
- ret = get_errno(msgget(first, second));
- break;
-
- case IPCOP_msgsnd:
- ret = do_msgsnd(first, ptr, second, third);
- break;
+ case IPCOP_msgsnd:
+ ret = do_msgsnd(first, ptr, second, third);
+ break;
- case IPCOP_msgctl:
- ret = do_msgctl(first, second, ptr);
- break;
+ case IPCOP_msgctl:
+ ret = do_msgctl(first, second, ptr);
+ break;
- case IPCOP_msgrcv:
- {
- /* XXX: this code is not correct */
- struct ipc_kludge
- {
- void *__unbounded msgp;
- long int msgtyp;
- };
+ case IPCOP_msgrcv:
+ switch (version) {
+ case 0:
+ {
+ struct target_ipc_kludge {
+ abi_long msgp;
+ abi_long msgtyp;
+ } *tmp;
- struct ipc_kludge *foo = (struct ipc_kludge *)g2h(ptr);
- struct msgbuf *msgp = (struct msgbuf *) foo->msgp;
+ if (!lock_user_struct(VERIFY_READ, tmp, ptr, 1)) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
- ret = do_msgrcv(first, (long)msgp, second, 0, third);
+ ret = do_msgrcv(first, tmp->msgp, second, tmp->msgtyp, third);
- }
- break;
+ unlock_user_struct(tmp, ptr, 0);
+ break;
+ }
+ default:
+ ret = do_msgrcv(first, ptr, second, fifth, third);
+ }
+ 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:
/* 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;
/* kernel structure types definitions */
#define IFNAMSIZ 16
-#define STRUCT(name, list...) STRUCT_ ## name,
+#define STRUCT(name, ...) STRUCT_ ## name,
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
enum {
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL
-#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL };
+#define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = { __VA_ARGS__, TYPE_NULL };
#define STRUCT_SPECIAL(name)
#include "syscall_types.h"
#undef STRUCT
#define MAX_STRUCT_SIZE 4096
-IOCTLEntry ioctl_entries[] = {
-#define IOCTL(cmd, access, types...) \
- { TARGET_ ## cmd, cmd, #cmd, access, { types } },
+static IOCTLEntry ioctl_entries[] = {
+#define IOCTL(cmd, access, ...) \
+ { TARGET_ ## cmd, cmd, #cmd, access, { __VA_ARGS__ } },
#include "ioctls.h"
{ 0, 0, },
};
return ret;
}
-bitmask_transtbl iflag_tbl[] = {
+static const bitmask_transtbl iflag_tbl[] = {
{ TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
{ TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
{ TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
{ 0, 0, 0, 0 }
};
-bitmask_transtbl oflag_tbl[] = {
+static const bitmask_transtbl oflag_tbl[] = {
{ TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
{ TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
{ TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
{ 0, 0, 0, 0 }
};
-bitmask_transtbl cflag_tbl[] = {
+static const bitmask_transtbl cflag_tbl[] = {
{ TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
{ TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
{ TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
{ 0, 0, 0, 0 }
};
-bitmask_transtbl lflag_tbl[] = {
+static const bitmask_transtbl lflag_tbl[] = {
{ TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
{ TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
{ TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
host->c_line = target->c_line;
+ memset(host->c_cc, 0, sizeof(host->c_cc));
host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
target->c_line = host->c_line;
+ memset(target->c_cc, 0, sizeof(target->c_cc));
target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
}
-StructEntry struct_termios_def = {
+static const StructEntry struct_termios_def = {
.convert = { host_to_target_termios, target_to_host_termios },
.size = { sizeof(struct target_termios), sizeof(struct host_termios) },
.align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
{ 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 */
-uint8_t *ldt_table;
+static uint8_t *ldt_table;
static abi_long read_ldt(abi_ulong ptr, unsigned long bytecount)
{
}
/* allocate the LDT */
if (!ldt_table) {
- ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
- if (!ldt_table)
+ env->ldt.base = target_mmap(0,
+ TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ if (env->ldt.base == -1)
return -TARGET_ENOMEM;
- memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
- env->ldt.base = h2g((unsigned long)ldt_table);
+ memset(g2h(env->ldt.base), 0,
+ TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
env->ldt.limit = 0xffff;
+ ldt_table = g2h(env->ldt.base);
}
/* NOTE: same code as Linux kernel */
{
new_thread_info *info = arg;
CPUState *env;
+ TaskState *ts;
env = info->env;
thread_env = env;
+ ts = (TaskState *)thread_env->opaque;
info->tid = gettid();
+ env->host_tid = info->tid;
+ task_settid(ts);
if (info->child_tidptr)
put_user_u32(info->tid, info->child_tidptr);
if (info->parent_tidptr)
sigset_t sigmask;
#endif
+ /* Emulate vfork() with fork() */
+ if (flags & CLONE_VFORK)
+ flags &= ~(CLONE_VFORK | CLONE_VM);
+
if (flags & CLONE_VM) {
+ TaskState *parent_ts = (TaskState *)env->opaque;
#if defined(USE_NPTL)
new_thread_info info;
pthread_attr_t attr;
/* Init regs that differ from the parent. */
cpu_clone_regs(new_env, newsp);
new_env->opaque = ts;
+ ts->bprm = parent_ts->bprm;
+ ts->info = parent_ts->info;
#if defined(USE_NPTL)
nptl_flags = flags;
flags &= ~CLONE_NPTL_FLAGS2;
- /* TODO: Implement CLONE_CHILD_CLEARTID. */
+ if (nptl_flags & CLONE_CHILD_CLEARTID) {
+ ts->child_tidptr = child_tidptr;
+ }
+
if (nptl_flags & CLONE_SETTLS)
cpu_set_tls (new_env, newtls);
sigprocmask(SIG_BLOCK, &sigmask, &info.sigmask);
ret = pthread_create(&info.thread, &attr, clone_func, &info);
+ /* TODO: Free new CPU state if thread creation failed. */
sigprocmask(SIG_SETMASK, &info.sigmask, NULL);
pthread_attr_destroy(&attr);
return -EINVAL;
fork_start();
ret = fork();
-#if defined(USE_NPTL)
- /* There is a race condition here. The parent process could
- theoretically read the TID in the child process before the child
- tid is set. This would require using either ptrace
- (not implemented) or having *_tidptr to point at a shared memory
- mapping. We can't repeat the spinlock hack used above because
- the child process gets its own copy of the lock. */
if (ret == 0) {
+ /* Child Process. */
cpu_clone_regs(env, newsp);
fork_end(1);
- /* Child Process. */
+#if defined(USE_NPTL)
+ /* There is a race condition here. The parent process could
+ theoretically read the TID in the child process before the child
+ tid is set. This would require using either ptrace
+ (not implemented) or having *_tidptr to point at a shared memory
+ mapping. We can't repeat the spinlock hack used above because
+ the child process gets its own copy of the lock. */
if (flags & CLONE_CHILD_SETTID)
put_user_u32(gettid(), child_tidptr);
if (flags & CLONE_PARENT_SETTID)
ts = (TaskState *)env->opaque;
if (flags & CLONE_SETTLS)
cpu_set_tls (env, newtls);
- /* TODO: Implement CLONE_CHILD_CLEARTID. */
+ if (flags & CLONE_CHILD_CLEARTID)
+ ts->child_tidptr = child_tidptr;
+#endif
} else {
fork_end(0);
}
-#else
- if (ret == 0) {
- cpu_clone_regs(env, newsp);
- }
-#endif
}
return ret;
}
int size;
int i;
-#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
#include "syscall_types.h"
#undef STRUCT
target_to_host_errno_table[host_to_target_errno_table[i]] = i;
/* automatic consistency check if same arch */
-#if defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)
- if (ie->target_cmd != ie->host_cmd) {
- fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
- ie->target_cmd, ie->host_cmd);
+#if (defined(__i386__) && defined(TARGET_I386) && defined(TARGET_ABI32)) || \
+ (defined(__x86_64__) && defined(TARGET_X86_64))
+ if (unlikely(ie->target_cmd != ie->host_cmd)) {
+ fprintf(stderr, "ERROR: ioctl(%s): target=0x%x host=0x%x\n",
+ ie->name, ie->target_cmd, ie->host_cmd);
}
#endif
ie++;
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)
} 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
/* ??? We assume FUTEX_* constants are the same on both host
and target. */
+#ifdef FUTEX_CMD_MASK
+ switch ((op&FUTEX_CMD_MASK)) {
+#else
switch (op) {
+#endif
case FUTEX_WAIT:
if (timeout) {
pts = &ts;
} else {
pts = NULL;
}
- return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val),
+ return get_errno(sys_futex(g2h(uaddr), op, tswap32(val),
pts, NULL, 0));
case FUTEX_WAKE:
- return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0));
+ return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
+ case FUTEX_WAKE_OP:
+ return get_errno(sys_futex(g2h(uaddr), op, val, NULL, g2h(uaddr2), val3 ));
case FUTEX_FD:
- return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0));
+ return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0));
case FUTEX_REQUEUE:
- return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val,
+ return get_errno(sys_futex(g2h(uaddr), op, val,
NULL, g2h(uaddr2), 0));
case FUTEX_CMP_REQUEUE:
- return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val,
+ return get_errno(sys_futex(g2h(uaddr), op, val,
NULL, g2h(uaddr2), tswap32(val3)));
default:
return -TARGET_ENOSYS;
}
#endif
+/* Map host to target signal numbers for the wait family of syscalls.
+ Assume all other status bits are the same. */
+static int host_to_target_waitstatus(int status)
+{
+ if (WIFSIGNALED(status)) {
+ return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
+ }
+ if (WIFSTOPPED(status)) {
+ return (host_to_target_signal(WSTOPSIG(status)) << 8)
+ | (status & 0xff);
+ }
+ return status;
+}
+
int get_osversion(void)
{
static int osversion;
switch(num) {
case TARGET_NR_exit:
+#ifdef USE_NPTL
+ /* In old applications this may be used to implement _exit(2).
+ However in threaded applictions it is used for thread termination,
+ and _exit_group is used for application termination.
+ Do thread termination if we have more then one thread. */
+ /* FIXME: This probably breaks if a signal arrives. We should probably
+ be disabling signals. */
+ if (first_cpu->next_cpu) {
+ TaskState *ts;
+ CPUState **lastp;
+ CPUState *p;
+
+ cpu_list_lock();
+ lastp = &first_cpu;
+ p = first_cpu;
+ while (p && p != (CPUState *)cpu_env) {
+ lastp = &p->next_cpu;
+ p = p->next_cpu;
+ }
+ /* If we didn't find the CPU for this thread then something is
+ horribly wrong. */
+ if (!p)
+ abort();
+ /* Remove the CPU from the list. */
+ *lastp = p->next_cpu;
+ cpu_list_unlock();
+ ts = ((CPUState *)cpu_env)->opaque;
+ if (ts->child_tidptr) {
+ put_user_u32(0, ts->child_tidptr);
+ sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+ NULL, NULL, 0);
+ }
+ /* TODO: Free CPU state. */
+ pthread_exit(NULL);
+ }
+#endif
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
- /* XXX: should free thread stack and CPU env */
_exit(arg1);
ret = 0; /* avoid warning */
break;
case TARGET_NR_read:
- if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
- goto efault;
- ret = get_errno(read(arg1, p, arg3));
- unlock_user(p, arg2, ret);
+ if (arg3 == 0)
+ ret = 0;
+ else {
+ if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+ goto efault;
+ ret = get_errno(read(arg1, p, arg3));
+ unlock_user(p, arg2, ret);
+ }
break;
case TARGET_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
int status;
ret = get_errno(waitpid(arg1, &status, arg3));
if (!is_error(ret) && arg2
- && put_user_s32(status, arg2))
+ && put_user_s32(host_to_target_waitstatus(status), arg2))
goto efault;
}
break;
case TARGET_NR_faccessat:
if (!(p = lock_user_string(arg2)))
goto efault;
- ret = get_errno(sys_faccessat(arg1, p, arg3, arg4));
+ ret = get_errno(sys_faccessat(arg1, p, arg3));
unlock_user(p, arg2, 0);
break;
#endif
ret = get_errno(dup(arg1));
break;
case TARGET_NR_pipe:
- {
- int host_pipe[2];
- ret = get_errno(pipe(host_pipe));
- if (!is_error(ret)) {
-#if defined(TARGET_MIPS)
- CPUMIPSState *env = (CPUMIPSState*)cpu_env;
- env->active_tc.gpr[3] = host_pipe[1];
- ret = host_pipe[0];
-#elif defined(TARGET_SH4)
- ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
- ret = host_pipe[0];
-#else
- if (put_user_s32(host_pipe[0], arg1)
- || put_user_s32(host_pipe[1], arg1 + sizeof(host_pipe[0])))
- goto efault;
-#endif
- }
- }
+ ret = do_pipe(cpu_env, arg1, 0);
+ break;
+#ifdef TARGET_NR_pipe2
+ case TARGET_NR_pipe2:
+ ret = do_pipe(cpu_env, arg1, arg2);
break;
+#endif
case TARGET_NR_times:
{
struct target_tms *tmsp;
goto unimplemented;
#endif
case TARGET_NR_acct:
- if (!(p = lock_user_string(arg1)))
- goto efault;
- ret = get_errno(acct(path(p)));
- unlock_user(p, arg1, 0);
+ if (arg1 == 0) {
+ ret = get_errno(acct(NULL));
+ } else {
+ if (!(p = lock_user_string(arg1)))
+ goto efault;
+ ret = get_errno(acct(path(p)));
+ unlock_user(p, arg1, 0);
+ }
break;
#ifdef TARGET_NR_umount2 /* not on alpha */
case TARGET_NR_umount2:
#endif
case TARGET_NR_readlink:
{
- void *p2;
+ void *p2, *temp;
p = lock_user_string(arg1);
p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
if (!p || !p2)
ret = -TARGET_EFAULT;
- else
- ret = get_errno(readlink(path(p), p2, arg3));
+ else {
+ if (strncmp((const char *)p, "/proc/self/exe", 14) == 0) {
+ char real[PATH_MAX];
+ temp = realpath(exec_path,real);
+ ret = (temp==NULL) ? get_errno(-1) : strlen(real) ;
+ snprintf((char *)p2, arg3, "%s", real);
+ }
+ else
+ ret = get_errno(readlink(path(p), p2, arg3));
+ }
unlock_user(p2, arg2, ret);
unlock_user(p, arg1, 0);
}
#endif
#ifdef TARGET_NR_mmap
case TARGET_NR_mmap:
-#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS)
+#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE)
{
abi_ulong *v;
abi_ulong v1, v2, v3, v4, v5, v6;
case TARGET_NR_fchmodat:
if (!(p = lock_user_string(arg2)))
goto efault;
- ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4));
+ ret = get_errno(sys_fchmodat(arg1, p, arg3));
unlock_user(p, arg2, 0);
break;
#endif
ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
if (!is_error(ret)) {
if (status_ptr) {
+ status = host_to_target_waitstatus(status);
if (put_user_s32(status, status_ptr))
goto efault;
}
case TARGET_NR_ipc:
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);
+ break;
+#endif
+#ifdef TARGET_NR_msgget
+ case TARGET_NR_msgget:
+ ret = get_errno(msgget(arg1, arg2));
+ break;
+#endif
+#ifdef TARGET_NR_msgrcv
+ case TARGET_NR_msgrcv:
+ ret = do_msgrcv(arg1, arg2, arg3, arg4, arg5);
+ break;
+#endif
+#ifdef TARGET_NR_msgsnd
+ case TARGET_NR_msgsnd:
+ 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));
case TARGET_NR_clone:
#if defined(TARGET_SH4)
ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg5, arg4));
+#elif defined(TARGET_CRIS)
+ ret = get_errno(do_fork(cpu_env, arg2, arg1, arg3, arg4, arg5));
#else
ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
#endif
#ifdef __NR_exit_group
/* new thread calls */
case TARGET_NR_exit_group:
+#ifdef HAVE_GPROF
+ _mcleanup();
+#endif
gdb_exit(cpu_env, arg1);
ret = get_errno(exit_group(arg1));
break;
#elif TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
{
struct target_dirent *target_dirp;
- struct dirent *dirp;
+ struct linux_dirent *dirp;
abi_long count = arg3;
dirp = malloc(count);
ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) {
- struct dirent *de;
+ struct linux_dirent *de;
struct target_dirent *tde;
int len = ret;
int reclen, treclen;
if (tnamelen > 256)
tnamelen = 256;
/* XXX: may not be correct */
- strncpy(tde->d_name, de->d_name, tnamelen);
- de = (struct dirent *)((char *)de + reclen);
+ pstrcpy(tde->d_name, tnamelen, de->d_name);
+ de = (struct linux_dirent *)((char *)de + reclen);
len -= reclen;
tde = (struct target_dirent *)((char *)tde + treclen);
count1 += treclen;
}
#else
{
- struct dirent *dirp;
+ struct linux_dirent *dirp;
abi_long count = arg3;
if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
goto efault;
ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) {
- struct dirent *de;
+ struct linux_dirent *de;
int len = ret;
int reclen;
de = dirp;
de->d_reclen = tswap16(reclen);
tswapls(&de->d_ino);
tswapls(&de->d_off);
- de = (struct dirent *)((char *)de + reclen);
+ de = (struct linux_dirent *)((char *)de + reclen);
len -= reclen;
}
}
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
case TARGET_NR_getdents64:
{
- struct dirent64 *dirp;
+ struct linux_dirent64 *dirp;
abi_long count = arg3;
if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
goto efault;
ret = get_errno(sys_getdents64(arg1, dirp, count));
if (!is_error(ret)) {
- struct dirent64 *de;
+ struct linux_dirent64 *de;
int len = ret;
int reclen;
de = dirp;
de->d_reclen = tswap16(reclen);
tswap64s((uint64_t *)&de->d_ino);
tswap64s((uint64_t *)&de->d_off);
- de = (struct dirent64 *)((char *)de + reclen);
+ de = (struct linux_dirent64 *)((char *)de + reclen);
len -= reclen;
}
}
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;
ret = get_errno(getuid());
break;
#endif
+
+#if defined(TARGET_NR_getxuid) && defined(TARGET_ALPHA)
+ /* Alpha specific */
+ case TARGET_NR_getxuid:
+ {
+ uid_t euid;
+ euid=geteuid();
+ ((CPUAlphaState *)cpu_env)->ir[IR_A4]=euid;
+ }
+ ret = get_errno(getuid());
+ break;
+#endif
+#if defined(TARGET_NR_getxgid) && defined(TARGET_ALPHA)
+ /* Alpha specific */
+ case TARGET_NR_getxgid:
+ {
+ uid_t egid;
+ egid=getegid();
+ ((CPUAlphaState *)cpu_env)->ir[IR_A4]=egid;
+ }
+ ret = get_errno(getgid());
+ break;
+#endif
+
#ifdef TARGET_NR_getgid32
case TARGET_NR_getgid32:
ret = get_errno(getgid());
goto unimplemented;
#ifdef TARGET_NR_mincore
case TARGET_NR_mincore:
- goto unimplemented;
+ {
+ void *a;
+ ret = -TARGET_EFAULT;
+ if (!(a = lock_user(VERIFY_READ, arg1,arg2, 0)))
+ goto efault;
+ if (!(p = lock_user_string(arg3)))
+ goto mincore_fail;
+ ret = get_errno(mincore(a, arg2, p));
+ unlock_user(p, arg3, ret);
+ mincore_fail:
+ unlock_user(a, arg1, 0);
+ }
+ break;
+#endif
+#ifdef TARGET_NR_arm_fadvise64_64
+ case TARGET_NR_arm_fadvise64_64:
+ {
+ /*
+ * arm_fadvise64_64 looks like fadvise64_64 but
+ * with different argument order
+ */
+ abi_long temp;
+ temp = arg3;
+ arg3 = arg4;
+ arg4 = temp;
+ }
+#endif
+#if defined(TARGET_NR_fadvise64_64) || defined(TARGET_NR_arm_fadvise64_64)
+#ifdef TARGET_NR_fadvise64_64
+ case TARGET_NR_fadvise64_64:
+#endif
+ /* This is a hint, so ignoring and returning success is ok. */
+ ret = get_errno(0);
+ break;
#endif
#ifdef TARGET_NR_madvise
case TARGET_NR_madvise:
break;
#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
- goto unimplemented;
+#if TARGET_ABI_BITS == 32
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi)
+ {
+ arg2 = arg3;
+ arg3 = arg4;
+ arg4 = arg5;
+ }
+#endif
+ ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
+#else
+ ret = get_errno(readahead(arg1, arg2, arg3));
+#endif
+ break;
#endif
#ifdef TARGET_NR_setxattr
case TARGET_NR_setxattr:
case TARGET_NR_removexattr:
case TARGET_NR_lremovexattr:
case TARGET_NR_fremovexattr:
- goto unimplemented_nowarn;
+ ret = -TARGET_EOPNOTSUPP;
+ break;
#endif
#ifdef TARGET_NR_set_thread_area
case TARGET_NR_set_thread_area:
((CPUMIPSState *) cpu_env)->tls_value = arg1;
ret = 0;
break;
+#elif defined(TARGET_CRIS)
+ if (arg1 & 0xff)
+ ret = -TARGET_EINVAL;
+ else {
+ ((CPUCRISState *) cpu_env)->pregs[PR_PID] = arg1;
+ ret = 0;
+ }
+ break;
#elif defined(TARGET_I386) && defined(TARGET_ABI32)
ret = do_set_thread_area(cpu_env, arg1);
break;
#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
case TARGET_NR_utimensat:
{
- struct timespec ts[2];
- target_to_host_timespec(ts, arg3);
- target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+ struct timespec *tsp, ts[2];
+ if (!arg3) {
+ tsp = NULL;
+ } else {
+ target_to_host_timespec(ts, arg3);
+ target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+ tsp = ts;
+ }
if (!arg2)
- ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
+ ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
else {
if (!(p = lock_user_string(arg2))) {
ret = -TARGET_EFAULT;
goto fail;
}
- ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
+ ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
unlock_user(p, arg2, 0);
}
}
ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
+#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
+ case TARGET_NR_inotify_init:
+ ret = get_errno(sys_inotify_init());
+ break;
+#endif
+#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
+ case TARGET_NR_inotify_add_watch:
+ p = lock_user_string(arg2);
+ ret = get_errno(sys_inotify_add_watch(arg1, path(p), arg3));
+ unlock_user(p, arg2, 0);
+ break;
+#endif
+#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
+ case TARGET_NR_inotify_rm_watch:
+ ret = get_errno(sys_inotify_rm_watch(arg1, arg2));
+ break;
+#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: