#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>
}
-#define __NR_sys_exit __NR_exit
#define __NR_sys_uname __NR_uname
#define __NR_sys_faccessat __NR_faccessat
#define __NR_sys_fchmodat __NR_fchmodat
return -ENOSYS;
}
#endif
-_syscall1(int,sys_exit,int,status)
-_syscall1(int,sys_uname,struct new_utsname *,buf)
-#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
-_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
-#endif
-#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
-_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
- mode_t,mode,int,flags)
-#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(TARGET_NR_newfstatat)) && \
defined(__NR_fstatat64)
_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
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
#endif
-#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
-_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
- int,newdirfd,const char *,newpath,int,flags)
-#endif
-#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
-_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
-#endif
-#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
-_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
- mode_t,mode,dev_t,dev)
-#endif
#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
defined(__NR_newfstatat)
_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
struct stat *,buf,int,flags)
#endif
-#if defined(TARGET_NR_openat) && defined(__NR_openat)
-_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
-#endif
-#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
-_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
- char *,buf,size_t,bufsize)
-#endif
-#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
-_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
- int,newdirfd,const char *,newpath)
-#endif
_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)
#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
-#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(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
_syscall0(int,sys_inotify_init)
#endif
#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 }
+};
+
+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).
+ */
+
+#define COPY_UTSNAME_FIELD(dest, src) \
+ do { \
+ /* __NEW_UTS_LEN doesn't include terminating null */ \
+ (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+ (dest)[__NEW_UTS_LEN] = '\0'; \
+ } while (0)
+
+ bzero(buf, sizeof (*buf));
+ COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+ COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+ 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_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_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_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 TARGET_NR_fstatat
+static int
+sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+ int flags)
+{
+ return (fstatat64(dirfd, pathname, buf, flags));
+}
+#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_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_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_symlinkat
+static int
+sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+ return (symlinkat(oldpath, newdirfd, newpath));
+}
+#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_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_faccessat
+static int
+sys_faccessat(int dirfd, const char *pathname, int mode, int flags)
+{
+ return (faccessat(dirfd, pathname, mode, 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 */
+
+/*
+ * Host system doesn't have these available so we don't try
+ * to implement them.
+ */
+
+#undef TARGET_NR_openat
+#undef TARGET_NR_mkdirat
+#undef TARGET_NR_mknodat
+#undef TARGET_NR_fchownat
+#undef TARGET_NR_fstatat
+#undef TARGET_NR_unlinkat
+#undef TARGET_NR_renameat
+#undef TARGET_NR_linkat
+#undef TARGET_NR_symlinkat
+#undef TARGET_NR_readlinkat
+#undef TARGET_NR_fchmodat
+#undef TARGET_NR_faccessat
+#undef TARGET_NR_utimensat
+
+#endif /* CONFIG_ATFILE */
+
+
extern int personality(int);
extern int flock(int, int);
extern int setfsuid(int);
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) {
+ 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;
return get_errno(socket(domain, type, protocol));
}
-/* MAX_SOCK_ADDR from linux/net/socket.c */
-#define MAX_SOCK_ADDR 128
-
/* do_bind() Must return target values and target errnos. */
static abi_long do_bind(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
void *addr;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
- addr = alloca(addrlen);
+ addr = alloca(addrlen+1);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(bind(sockfd, addr, addrlen));
{
void *addr;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(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 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
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);
void *addr;
abi_long ret;
+ if (target_addr == 0)
+ return get_errno(accept(fd, NULL, NULL));
+
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
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);
ret = -TARGET_EFAULT;
goto fail;
}
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) {
+ if (addrlen < 0) {
ret = -TARGET_EINVAL;
goto fail;
}
}
}
+ *raddr = h2g(*raddr);
+
mmap_unlock();
return 0;
}
{ 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 */
pthread_cond_t cond;
pthread_t thread;
uint32_t tid;
+ unsigned int flags;
abi_ulong child_tidptr;
abi_ulong parent_tidptr;
sigset_t sigmask;
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);
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);
switch(num) {
case TARGET_NR_exit:
+#ifdef USE_NPTL
+ /* In old applications this may be used to implement _exit(2).
+ However in threaded applictions it is used for thread termination,
+ and _exit_group is used for application termination.
+ Do thread termination if we have more then one thread. */
+ /* FIXME: This probably breaks if a signal arrives. We should probably
+ be disabling signals. */
+ if (first_cpu->next_cpu) {
+ CPUState **lastp;
+ CPUState *p;
+
+ cpu_list_lock();
+ lastp = &first_cpu;
+ p = first_cpu;
+ while (p && p != (CPUState *)cpu_env) {
+ lastp = &p->next_cpu;
+ p = p->next_cpu;
+ }
+ /* If we didn't find the CPU for this thread then something is
+ horribly wrong. */
+ if (!p)
+ abort();
+ /* Remove the CPU from the list. */
+ *lastp = p->next_cpu;
+ cpu_list_unlock();
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+ if (ts->child_tidptr) {
+ put_user_u32(0, ts->child_tidptr);
+ sys_futex(g2h(ts->child_tidptr), FUTEX_WAKE, INT_MAX,
+ NULL, NULL, 0);
+ }
+ /* TODO: Free CPU state. */
+ pthread_exit(NULL);
+ }
+#endif
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
- /* XXX: should free thread stack and CPU env */
- sys_exit(arg1);
+ _exit(arg1);
ret = 0; /* avoid warning */
break;
case TARGET_NR_read:
#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);
}