From e2937d83a945dc1f2a2f127466134847d5e5097d Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Tue, 4 Jun 2013 14:15:50 -0500 Subject: [PATCH 16/23] bsd-user: add shims for stat and file handle related syscalls To: Cc: This change adds support for status, file handle, and fcntl related system calls including stat(), statfs(), fhstatfs(), fcntl() and the many variants. Signed-off-by: Stacey Son --- bsd-user/Makefile.objs | 3 +- bsd-user/freebsd/os-stat.c | 234 +++++++++++++++++++++++ bsd-user/freebsd/os-stat.h | 437 ++++++++++++++++++++++++++++++++++++++++++++ bsd-user/freebsd/qemu-os.h | 10 + bsd-user/netbsd/os-stat.c | 1 + bsd-user/netbsd/os-stat.h | 176 ++++++++++++++++++ bsd-user/openbsd/os-stat.c | 1 + bsd-user/openbsd/os-stat.h | 176 ++++++++++++++++++ bsd-user/syscall.c | 76 ++++++++ bsd-user/syscall_defs.h | 155 ++++++++++++++++ 10 files changed, 1268 insertions(+), 1 deletions(-) create mode 100644 bsd-user/freebsd/os-stat.c create mode 100644 bsd-user/freebsd/os-stat.h create mode 100644 bsd-user/netbsd/os-stat.c create mode 100644 bsd-user/netbsd/os-stat.h create mode 100644 bsd-user/openbsd/os-stat.c create mode 100644 bsd-user/openbsd/os-stat.h diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs index 01f315e..cc7a82b 100644 --- a/bsd-user/Makefile.objs +++ b/bsd-user/Makefile.objs @@ -1,3 +1,4 @@ obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ uaccess.o bsd-mem.o bsd-proc.o $(TARGET_OS)/os-time.o \ - $(TARGET_OS)/os-proc.o bsd-socket.o $(TARGET_OS)/os-socket.o + $(TARGET_OS)/os-proc.o bsd-socket.o $(TARGET_OS)/os-socket.o \ + $(TARGET_OS)/os-stat.o diff --git a/bsd-user/freebsd/os-stat.c b/bsd-user/freebsd/os-stat.c new file mode 100644 index 0000000..50885d1 --- /dev/null +++ b/bsd-user/freebsd/os-stat.c @@ -0,0 +1,234 @@ +/* + * FreeBSD stat related conversion routines + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "qemu.h" +#include "qemu-os.h" + +/* + * stat conversion + */ +abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st) +{ + struct target_freebsd_stat *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) { + return -TARGET_EFAULT; + } + 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); + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec); + __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec); + __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec); + __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec); + __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec); + __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec); + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_flags, &target_st->st_flags); + __put_user(host_st->st_gen, &target_st->st_gen); + /* st_lspare not used */ + __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec); + __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec); + unlock_user_struct(target_st, target_addr, 1); + + return 0; +} + +abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st) +{ + struct target_freebsd_nstat *target_st; + + if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0)) { + return -TARGET_EFAULT; + } + 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); + __put_user(host_st->st_mode, &target_st->st_mode); + __put_user(host_st->st_nlink, &target_st->st_nlink); + __put_user(host_st->st_uid, &target_st->st_uid); + __put_user(host_st->st_gid, &target_st->st_gid); + __put_user(host_st->st_rdev, &target_st->st_rdev); + __put_user(host_st->st_atim.tv_sec, &target_st->st_atim.tv_sec); + __put_user(host_st->st_atim.tv_nsec, &target_st->st_atim.tv_nsec); + __put_user(host_st->st_mtim.tv_sec, &target_st->st_mtim.tv_sec); + __put_user(host_st->st_mtim.tv_nsec, &target_st->st_mtim.tv_nsec); + __put_user(host_st->st_ctim.tv_sec, &target_st->st_ctim.tv_sec); + __put_user(host_st->st_ctim.tv_nsec, &target_st->st_ctim.tv_nsec); + __put_user(host_st->st_size, &target_st->st_size); + __put_user(host_st->st_blocks, &target_st->st_blocks); + __put_user(host_st->st_blksize, &target_st->st_blksize); + __put_user(host_st->st_flags, &target_st->st_flags); + __put_user(host_st->st_gen, &target_st->st_gen); + __put_user(host_st->st_birthtim.tv_sec, &target_st->st_birthtim.tv_sec); + __put_user(host_st->st_birthtim.tv_nsec, &target_st->st_birthtim.tv_nsec); + unlock_user_struct(target_st, target_addr, 1); + + return 0; +} + +/* + * file handle conversion + */ +abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr) +{ + target_freebsd_fhandle_t *target_fh; + + if (!lock_user_struct(VERIFY_READ, target_fh, target_addr, 1)) { + return -TARGET_EFAULT; + } + __get_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]); + __get_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]); + __get_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len); + /* u_short fid_data0; */ + memcpy(host_fh->fh_fid.fid_data, target_fh->fh_fid.fid_data, + TARGET_MAXFIDSZ); + unlock_user_struct(target_fh, target_addr, 0); + return 0; +} + +abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh) +{ + target_freebsd_fhandle_t *target_fh; + + if (!lock_user_struct(VERIFY_WRITE, target_fh, target_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_fh->fh_fsid.val[0], &target_fh->fh_fsid.val[0]); + __put_user(host_fh->fh_fsid.val[1], &target_fh->fh_fsid.val[0]); + __put_user(host_fh->fh_fid.fid_len, &target_fh->fh_fid.fid_len); + /* u_short fid_data0; */ + memcpy(target_fh->fh_fid.fid_data, host_fh->fh_fid.fid_data, + TARGET_MAXFIDSZ); + unlock_user_struct(target_fh, target_addr, 1); + return 0; +} + +/* + * file system stat + */ +abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs) +{ + struct target_freebsd_statfs *target_statfs; + + if (!lock_user_struct(VERIFY_WRITE, target_statfs, target_addr, 0)) { + return -TARGET_EFAULT; + } + __put_user(host_statfs->f_version, &target_statfs->f_version); + __put_user(host_statfs->f_type, &target_statfs->f_type); + __put_user(host_statfs->f_flags, &target_statfs->f_flags); + __put_user(host_statfs->f_bsize, &target_statfs->f_bsize); + __put_user(host_statfs->f_iosize, &target_statfs->f_iosize); + __put_user(host_statfs->f_blocks, &target_statfs->f_blocks); + __put_user(host_statfs->f_bfree, &target_statfs->f_bfree); + __put_user(host_statfs->f_bavail, &target_statfs->f_bavail); + __put_user(host_statfs->f_files, &target_statfs->f_files); + __put_user(host_statfs->f_ffree, &target_statfs->f_ffree); + __put_user(host_statfs->f_syncwrites, &target_statfs->f_syncwrites); + __put_user(host_statfs->f_asyncwrites, &target_statfs->f_asyncwrites); + __put_user(host_statfs->f_syncreads, &target_statfs->f_syncreads); + __put_user(host_statfs->f_asyncreads, &target_statfs->f_asyncreads); + /* uint64_t f_spare[10]; */ + __put_user(host_statfs->f_namemax, &target_statfs->f_namemax); + __put_user(host_statfs->f_owner, &target_statfs->f_owner); + __put_user(host_statfs->f_fsid.val[0], &target_statfs->f_fsid.val[0]); + __put_user(host_statfs->f_fsid.val[1], &target_statfs->f_fsid.val[1]); + /* char f_charspace[80]; */ + strncpy(&target_statfs->f_fstypename[0], host_statfs->f_fstypename, + TARGET_MFSNAMELEN); + strncpy(&target_statfs->f_mntfromname[0], host_statfs->f_mntfromname, + TARGET_MNAMELEN); + strncpy(&target_statfs->f_mntonname[0], host_statfs->f_mntonname, + TARGET_MNAMELEN); + unlock_user_struct(target_statfs, target_addr, 1); + return 0; +} + +/* + * fcntl cmd conversion + */ +abi_long target_to_host_fcntl_cmd(int cmd) +{ + + switch (cmd) { + case TARGET_F_DUPFD: + return F_DUPFD; + + case TARGET_F_DUP2FD: + return F_DUP2FD; + + case TARGET_F_GETFD: + return F_GETFD; + + case TARGET_F_SETFD: + return F_SETFD; + + case TARGET_F_GETFL: + return F_GETFL; + + case TARGET_F_SETFL: + return F_SETFL; + + case TARGET_F_GETOWN: + return F_GETOWN; + + case TARGET_F_SETOWN: + return F_SETOWN; + + case TARGET_F_GETLK: + return F_GETLK; + + case TARGET_F_SETLK: + return F_SETLK; + + case TARGET_F_SETLKW: + return F_SETLKW; + + case TARGET_F_READAHEAD: + return F_READAHEAD; + + case TARGET_F_RDAHEAD: + return F_RDAHEAD; + +#ifdef F_DUPFD_CLOEXEC + case TARGET_F_DUPFD_CLOEXEC: + return F_DUPFD_CLOEXEC; +#endif + +#ifdef F_DUP2FD_CLOEXEC + case TARGET_F_DUP2FD_CLOEXEC: + return F_DUP2FD_CLOEXEC; +#endif + + default: + return -TARGET_EINVAL; + } +} + diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h new file mode 100644 index 0000000..abf92a6 --- /dev/null +++ b/bsd-user/freebsd/os-stat.h @@ -0,0 +1,437 @@ +/* + * stat related system call shims and definitions + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __FREEBSD_STAT_H_ +#define __FREEBSD_STAT_H_ + +#include +#include +#include +#include +#include + +#include "qemu-os.h" + +/* undocumented nstat system calls */ +int nstat(const char *path, struct stat *sb); +int nlstat(const char *path, struct stat *sb); +int nfstat(int fd, struct stat *sb); + +/* stat(2) */ +static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(stat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd_stat(arg2, &st); + } + return ret; +} + +/* lstat(2) */ +static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(lstat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd_stat(arg2, &st); + } + return ret; +} + +/* fstat(2) */ +static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct stat st; + + ret = get_errno(fstat(arg1, &st)); + if (!is_error(ret)) { + ret = h2t_freebsd_stat(arg2, &st); + } + return ret; +} + +/* fstatat(2) */ +static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + abi_long ret; + void *p; + struct stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(fstatat(arg1, p, &st, arg4)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd_stat(arg2, &st); + } + return ret; +} + +/* undocummented nstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(nstat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd_nstat(arg2, &st); + } + return ret; +} + +/* undocummented nfstat(int fd, struct nstat *sb) syscall */ +static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + struct stat st; + + ret = get_errno(nfstat(arg1, &st)); + if (!is_error(ret)) { + ret = h2t_freebsd_nstat(arg2, &st); + } + return ret; +} + +/* undocummented nlstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct stat st; + + LOCK_PATH(p, arg1); + ret = get_errno(nlstat(path(p), &st)); + UNLOCK_PATH(p, arg1); + if (!is_error(ret)) { + ret = h2t_freebsd_nstat(arg2, &st); + } + return ret; +} + +/* getfh(2) */ +static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + fhandle_t host_fh; + + LOCK_PATH(p, arg1); + ret = get_errno(getfh(path(p), &host_fh)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_fhandle(arg2, &host_fh); +} + +/* lgetfh(2) */ +static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + fhandle_t host_fh; + + LOCK_PATH(p, arg1); + ret = get_errno(lgetfh(path(p), &host_fh)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_fhandle(arg2, &host_fh); +} + +/* fhopen(2) */ +static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2) +{ + abi_long ret; + fhandle_t host_fh; + + ret = t2h_freebsd_fhandle(&host_fh, arg1); + if (is_error(ret)) { + return ret; + } + + return get_errno(fhopen(&host_fh, arg2)); +} + +/* fhstat(2) */ +static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) +{ + abi_long ret; + fhandle_t host_fh; + struct stat host_sb; + + ret = t2h_freebsd_fhandle(&host_fh, arg1); + if (is_error(ret)) { + return ret; + } + ret = get_errno(fhstat(&host_fh, &host_sb)); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_stat(arg2, &host_sb); +} + +/* fhstatfs(2) */ +static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, + abi_ulong target_stfs_addr) +{ + abi_long ret; + fhandle_t host_fh; + struct statfs host_stfs; + + ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr); + if (is_error(ret)) { + return ret; + } + ret = get_errno(fhstatfs(&host_fh, &host_stfs)); + if (is_error(ret)) { + return ret; + } + return h2t_freebsd_statfs(target_stfs_addr, &host_stfs); +} + +/* statfs(2) */ +static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) +{ + abi_long ret; + void *p; + struct statfs host_stfs; + + LOCK_PATH(p, arg1); + ret = get_errno(statfs(path(p), &host_stfs)); + UNLOCK_PATH(p, arg1); + if (is_error(ret)) { + return ret; + } + + return h2t_freebsd_statfs(arg2, &host_stfs); +} + +/* fstatfs(2) */ +static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) +{ + abi_long ret; + struct statfs host_stfs; + + ret = get_errno(fstatfs(fd, &host_stfs)); + if (is_error(ret)) { + return ret; + } + + return h2t_freebsd_statfs(target_addr, &host_stfs); +} + +/* getfsstat(2) */ +static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, + abi_long bufsize, abi_long flags) +{ + abi_long ret; + struct statfs *host_stfs; + int count; + long host_bufsize; + + count = bufsize / sizeof(struct target_freebsd_statfs); + + /* if user buffer is NULL then return number of mounted FS's */ + if (target_addr == 0 || count == 0) { + return get_errno(getfsstat(NULL, 0, flags)); + } + + /* XXX check count to be reasonable */ + host_bufsize = sizeof(struct statfs) * count; + host_stfs = alloca(host_bufsize); + if (!host_stfs) { + return -TARGET_EINVAL; + } + + ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags)); + if (is_error(ret)) { + return ret; + } + + while (count--) { + if (h2t_freebsd_statfs((target_addr + + (count * sizeof(struct target_freebsd_statfs))), + &host_stfs[count])) { + return -TARGET_EFAULT; + } + } + return ret; +} + +/* getdents(2) */ +static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2, + abi_long nbytes) +{ + abi_long ret; + struct dirent *dirp; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(getdents(arg1, (char *)dirp, nbytes)); + if (!is_error(ret)) { + struct dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_reclen = tswap16(reclen); + de->d_fileno = tswap32(de->d_fileno); + len -= reclen; + } + } + return ret; +} + +/* getdirecentries(2) */ +static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2, + abi_long nbytes, abi_ulong arg4) +{ + abi_long ret; + struct dirent *dirp; + long basep; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep)); + if (!is_error(ret)) { + struct dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_reclen = tswap16(reclen); + de->d_fileno = tswap32(de->d_fileno); + len -= reclen; + de = (struct dirent *)((void *)de + reclen); + } + } + unlock_user(dirp, arg2, ret); + if (arg4) { + if (put_user(basep, arg4, abi_ulong)) { + return -TARGET_EFAULT; + } + } + return ret; +} + +/* fcntl(2) */ +static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2, + abi_ulong arg3) +{ + abi_long ret; + int host_cmd; + struct flock fl; + struct target_freebsd_flock *target_fl; + + host_cmd = target_to_host_fcntl_cmd(arg2); + if (host_cmd < 0) { + return host_cmd; + } + switch (arg2) { + case TARGET_F_GETLK: + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + return -TARGET_EFAULT; + } + __get_user(fl.l_type, &target_fl->l_type); + __get_user(fl.l_whence, &target_fl->l_whence); + __get_user(fl.l_start, &target_fl->l_start); + __get_user(fl.l_len, &target_fl->l_len); + __get_user(fl.l_pid, &target_fl->l_pid); + __get_user(fl.l_sysid, &target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 0); + ret = get_errno(fcntl(arg1, host_cmd, &fl)); + if (!is_error(ret)) { + if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) { + return -TARGET_EFAULT; + } + __put_user(fl.l_type, &target_fl->l_type); + __put_user(fl.l_whence, &target_fl->l_whence); + __put_user(fl.l_start, &target_fl->l_start); + __put_user(fl.l_len, &target_fl->l_len); + __put_user(fl.l_pid, &target_fl->l_pid); + __put_user(fl.l_sysid, &target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 1); + } + break; + + case TARGET_F_SETLK: + case TARGET_F_SETLKW: + if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) { + return -TARGET_EFAULT; + } + __get_user(fl.l_type, &target_fl->l_type); + __get_user(fl.l_whence, &target_fl->l_whence); + __get_user(fl.l_start, &target_fl->l_start); + __get_user(fl.l_len, &target_fl->l_len); + __get_user(fl.l_pid, &target_fl->l_pid); + __get_user(fl.l_sysid, &target_fl->l_sysid); + unlock_user_struct(target_fl, arg3, 0); + ret = get_errno(fcntl(arg1, host_cmd, &fl)); + break; + + case TARGET_F_DUPFD: + case TARGET_F_DUP2FD: + case TARGET_F_GETOWN: + case TARGET_F_SETOWN: + case TARGET_F_GETFD: + case TARGET_F_SETFD: + case TARGET_F_GETFL: + case TARGET_F_SETFL: + case TARGET_F_READAHEAD: + case TARGET_F_RDAHEAD: + default: + ret = get_errno(fcntl(arg1, host_cmd, arg3)); + break; + } + return ret; +} + +#endif /* ! __FREEBSD_STAT_H_ */ diff --git a/bsd-user/freebsd/qemu-os.h b/bsd-user/freebsd/qemu-os.h index ff3a2c2..0dd65f5 100644 --- a/bsd-user/freebsd/qemu-os.h +++ b/bsd-user/freebsd/qemu-os.h @@ -21,9 +21,11 @@ #define _QEMU_OS_H_ #include +#include #include #include #include +#include #include #include @@ -52,4 +54,12 @@ abi_long t2h_freebsd_cmsg(struct msghdr *msgh, abi_long h2t_freebsd_cmsg(struct target_msghdr *target_msgh, struct msghdr *msgh); +/* os-stat.c */ +abi_long h2t_freebsd_stat(abi_ulong target_addr, struct stat *host_st); +abi_long h2t_freebsd_nstat(abi_ulong target_addr, struct stat *host_st); +abi_long t2h_freebsd_fhandle(fhandle_t *host_fh, abi_ulong target_addr); +abi_long h2t_freebsd_fhandle(abi_ulong target_addr, fhandle_t *host_fh); +abi_long h2t_freebsd_statfs(abi_ulong target_addr, struct statfs *host_statfs); +abi_long target_to_host_fcntl_cmd(int cmd); + #endif /* !_QEMU_OS_H_ */ diff --git a/bsd-user/netbsd/os-stat.c b/bsd-user/netbsd/os-stat.c new file mode 100644 index 0000000..11ea122 --- /dev/null +++ b/bsd-user/netbsd/os-stat.c @@ -0,0 +1 @@ +/* XXX NetBSD stat related helpers */ diff --git a/bsd-user/netbsd/os-stat.h b/bsd-user/netbsd/os-stat.h new file mode 100644 index 0000000..d3e5bdd --- /dev/null +++ b/bsd-user/netbsd/os-stat.h @@ -0,0 +1,176 @@ +/* + * NetBSD stat related system call shims and definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __NETBSD_STAT_H_ +#define __NETBSD_STAT_H_ + +/* + * XXX To support FreeBSD binaries on NetBSD these syscalls will need + * to be emulated. + */ + +/* stat(2) */ +static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall stat()\n"); + return -TARGET_ENOSYS; +} + +/* lstat(2) */ +static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall lstat()\n"); + return -TARGET_ENOSYS; +} + +/* fstat(2) */ +static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall fstat()\n"); + return -TARGET_ENOSYS; +} + +/* fstatat(2) */ +static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + + qemu_log("qemu: Unsupported syscall fstatat()\n"); + return -TARGET_ENOSYS; +} + +/* undocummented nstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall nstat()\n"); + return -TARGET_ENOSYS; +} + +/* undocummented nfstat(int fd, struct nstat *sb) syscall */ +static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall nfstat()\n"); + return -TARGET_ENOSYS; +} + +/* undocummented nlstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall nlstat()\n"); + return -TARGET_ENOSYS; +} + +/* getfh(2) */ +static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall getfh()\n"); + return -TARGET_ENOSYS; +} + +/* lgetfh(2) */ +static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall lgetfh()\n"); + return -TARGET_ENOSYS; +} + +/* fhopen(2) */ +static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall fhopen()\n"); + return -TARGET_ENOSYS; +} + +/* fhstat(2) */ +static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall fhstat()\n"); + return -TARGET_ENOSYS; +} + +/* fhstatfs(2) */ +static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, + abi_ulong target_stfs_addr) +{ + + qemu_log("qemu: Unsupported syscall fhstatfs()\n"); + return -TARGET_ENOSYS; +} + +/* statfs(2) */ +static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall statfs()\n"); + return -TARGET_ENOSYS; +} + +/* fstatfs(2) */ +static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) +{ + + qemu_log("qemu: Unsupported syscall fstatfs()\n"); + return -TARGET_ENOSYS; +} + +/* getfsstat(2) */ +static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, + abi_long bufsize, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall getfsstat()\n"); + return -TARGET_ENOSYS; +} + +/* getdents(2) */ +static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2, + abi_long nbytes) +{ + + qemu_log("qemu: Unsupported syscall getdents()\n"); + return -TARGET_ENOSYS; +} + +/* getdirecentries(2) */ +static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2, + abi_long nbytes, abi_ulong arg4) +{ + + qemu_log("qemu: Unsupported syscall getdirecentries()\n"); + return -TARGET_ENOSYS; +} + +/* fcntl(2) */ +static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2, + abi_ulong arg3) +{ + + qemu_log("qemu: Unsupported syscall fcntl()\n"); + return -TARGET_ENOSYS; +} + +#endif /* ! __NETBSD_STAT_H_ */ diff --git a/bsd-user/openbsd/os-stat.c b/bsd-user/openbsd/os-stat.c new file mode 100644 index 0000000..de4e3f5 --- /dev/null +++ b/bsd-user/openbsd/os-stat.c @@ -0,0 +1 @@ +/* XXX OpenBSD stat related helpers */ diff --git a/bsd-user/openbsd/os-stat.h b/bsd-user/openbsd/os-stat.h new file mode 100644 index 0000000..1d3850d --- /dev/null +++ b/bsd-user/openbsd/os-stat.h @@ -0,0 +1,176 @@ +/* + * OpenBSD stat related system call shims and definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __OPENBSD_STAT_H_ +#define __OPENBSD_STAT_H_ + +/* + * XXX To support FreeBSD binaries on OpenBSD these syscalls will need + * to be emulated. + */ + +/* stat(2) */ +static inline abi_long do_freebsd_stat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall stat()\n"); + return -TARGET_ENOSYS; +} + +/* lstat(2) */ +static inline abi_long do_freebsd_lstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall lstat()\n"); + return -TARGET_ENOSYS; +} + +/* fstat(2) */ +static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall fstat()\n"); + return -TARGET_ENOSYS; +} + +/* fstatat(2) */ +static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4) +{ + + qemu_log("qemu: Unsupported syscall fstatat()\n"); + return -TARGET_ENOSYS; +} + +/* undocummented nstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd_nstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall nstat()\n"); + return -TARGET_ENOSYS; +} + +/* undocummented nfstat(int fd, struct nstat *sb) syscall */ +static abi_long do_freebsd_nfstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall nfstat()\n"); + return -TARGET_ENOSYS; +} + +/* undocummented nlstat(char *path, struct nstat *ub) syscall */ +static abi_long do_freebsd_nlstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall nlstat()\n"); + return -TARGET_ENOSYS; +} + +/* getfh(2) */ +static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall getfh()\n"); + return -TARGET_ENOSYS; +} + +/* lgetfh(2) */ +static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall lgetfh()\n"); + return -TARGET_ENOSYS; +} + +/* fhopen(2) */ +static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall fhopen()\n"); + return -TARGET_ENOSYS; +} + +/* fhstat(2) */ +static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall fhstat()\n"); + return -TARGET_ENOSYS; +} + +/* fhstatfs(2) */ +static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr, + abi_ulong target_stfs_addr) +{ + + qemu_log("qemu: Unsupported syscall fhstatfs()\n"); + return -TARGET_ENOSYS; +} + +/* statfs(2) */ +static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2) +{ + + qemu_log("qemu: Unsupported syscall statfs()\n"); + return -TARGET_ENOSYS; +} + +/* fstatfs(2) */ +static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr) +{ + + qemu_log("qemu: Unsupported syscall fstatfs()\n"); + return -TARGET_ENOSYS; +} + +/* getfsstat(2) */ +static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, + abi_long bufsize, abi_long flags) +{ + + qemu_log("qemu: Unsupported syscall getfsstat()\n"); + return -TARGET_ENOSYS; +} + +/* getdents(2) */ +static inline abi_long do_freebsd_getdents(abi_long arg1, abi_ulong arg2, + abi_long nbytes) +{ + + qemu_log("qemu: Unsupported syscall getdents()\n"); + return -TARGET_ENOSYS; +} + +/* getdirecentries(2) */ +static inline abi_long do_freebsd_getdirentries(abi_long arg1, abi_ulong arg2, + abi_long nbytes, abi_ulong arg4) +{ + + qemu_log("qemu: Unsupported syscall getdirecentries()\n"); + return -TARGET_ENOSYS; +} + +/* fcntl(2) */ +static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2, + abi_ulong arg3) +{ + + qemu_log("qemu: Unsupported syscall fcntl()\n"); + return -TARGET_ENOSYS; +} + +#endif /* ! __OPENBSD_STAT_H_ */ diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 98b1339..fee602b 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -44,6 +44,7 @@ static int host_to_target_errno(int err); #include "os-proc.h" #include "os-signal.h" #include "os-socket.h" +#include "os-stat.h" /* #define DEBUG */ @@ -869,6 +870,81 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3); break; + /* + * stat system calls + */ + case TARGET_FREEBSD_NR_stat: /* stat(2) */ + ret = do_freebsd_stat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lstat: /* lstat(2) */ + ret = do_freebsd_lstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fstat: /* fstat(2) */ + ret = do_freebsd_fstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */ + ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_nstat: /* undocumented */ + ret = do_freebsd_nstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_nfstat: /* undocumented */ + ret = do_freebsd_nfstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_nlstat: /* undocumented */ + ret = do_freebsd_nlstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_getfh: /* getfh(2) */ + ret = do_freebsd_getfh(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */ + ret = do_freebsd_lgetfh(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */ + ret = do_freebsd_fhopen(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */ + ret = do_freebsd_fhstat(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */ + ret = do_freebsd_fhstatfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_statfs: /* statfs(2) */ + ret = do_freebsd_statfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */ + ret = do_freebsd_fstatfs(arg1, arg2); + break; + + case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */ + ret = do_freebsd_getfsstat(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getdents: /* getdents(2) */ + ret = do_freebsd_getdents(arg1, arg2, arg3); + break; + + case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */ + ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4); + break; + + case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */ + ret = do_freebsd_fcntl(arg1, arg2, arg3); + break; + /* * Memory management system calls. diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 84d2f6f..0db7126 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -343,4 +343,159 @@ struct target_ip_mreqn { int32_t imr_ifindex; }; +/* + * sys/stat.h + */ +#if defined(__FreeBSD_version) && __FreeBSD_version < 900000 +#define st_atim st_atimespec +#define st_ctim st_ctimespec +#define st_mtim st_mtimespec +#define st_birthtim st_birthtimespec +#endif + +struct target_freebsd_stat { + uint32_t st_dev; /* inode's device */ + uint32_t st_ino; /* inode's number */ + int16_t st_mode; /* inode protection mode */ + int16_t st_nlink; /* number of hard links */ + uint32_t st_uid; /* user ID of the file's owner */ + uint32_t st_gid; /* group ID of the file's group */ + uint32_t st_rdev; /* device type */ + struct target_freebsd_timespec st_atim; /* time last accessed */ + struct target_freebsd_timespec st_mtim; /* time last data modification */ + struct target_freebsd_timespec st_ctim; /* time last file status change */ + int64_t st_size; /* file size, in bytes */ + int64_t st_blocks; /* blocks allocated for file */ + uint32_t st_blksize; /* optimal blocksize for I/O */ + uint32_t st_flags; /* user defined flags for file */ + __uint32_t st_gen; /* file generation number */ + __int32_t st_lspare; + struct target_freebsd_timespec st_birthtim; /* time of file creation */ + /* + * Explicitly pad st_birthtim to 16 bytes so that the size of + * struct stat is backwards compatible. We use bitfields instead + * of an array of chars so that this doesn't require a C99 compiler + * to compile if the size of the padding is 0. We use 2 bitfields + * to cover up to 64 bits on 32-bit machines. We assume that + * CHAR_BIT is 8... + */ + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); +} __packed; + +/* struct nstat is the same as stat above but without the st_lspare field */ +struct target_freebsd_nstat { + uint32_t st_dev; /* inode's device */ + uint32_t st_ino; /* inode's number */ + int16_t st_mode; /* inode protection mode */ + int16_t st_nlink; /* number of hard links */ + uint32_t st_uid; /* user ID of the file's owner */ + uint32_t st_gid; /* group ID of the file's group */ + uint32_t st_rdev; /* device type */ + struct target_freebsd_timespec st_atim; /* time last accessed */ + struct target_freebsd_timespec st_mtim; /* time last data modification */ + struct target_freebsd_timespec st_ctim; /* time last file status change */ + int64_t st_size; /* file size, in bytes */ + int64_t st_blocks; /* blocks allocated for file */ + uint32_t st_blksize; /* optimal blocksize for I/O */ + uint32_t st_flags; /* user defined flags for file */ + __uint32_t st_gen; /* file generation number */ + /* __int32_t st_lspare; */ + struct target_freebsd_timespec st_birthtim; /* time of file creation */ + /* + * Explicitly pad st_birthtim to 16 bytes so that the size of + * struct stat is backwards compatible. We use bitfields instead + * of an array of chars so that this doesn't require a C99 compiler + * to compile if the size of the padding is 0. We use 2 bitfields + * to cover up to 64 bits on 32-bit machines. We assume that + * CHAR_BIT is 8... + */ + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); + unsigned int:(8 / 2) * (16 - (int)sizeof(struct target_freebsd_timespec)); +} __packed; + +/* + * sys/mount.h + */ + +/* filesystem id type */ +typedef struct target_freebsd_fsid { int32_t val[2]; } target_freebsd_fsid_t; + +/* filesystem statistics */ +#define TARGET_MFSNAMELEN 16 /* length of type name include null */ +#define TARGET_MNAMELEN 88 /* size of on/from name bufs */ +#define TARGET_STATFS_VERSION 0x20030518 /* current version number */ +struct target_freebsd_statfs { + uint32_t f_version; /* structure version number */ + uint32_t f_type; /* type of filesystem */ + uint64_t f_flags; /* copy of mount exported flags */ + uint64_t f_bsize; /* filesystem fragment size */ + uint64_t f_iosize; /* optimal transfer block size */ + uint64_t f_blocks; /* total data blocks in filesystem */ + uint64_t f_bfree; /* free blocks in filesystem */ + int64_t f_bavail; /* free blocks avail to non-superuser */ + uint64_t f_files; /* total file nodes in filesystem */ + int64_t f_ffree; /* free nodes avail to non-superuser */ + uint64_t f_syncwrites; /* count of sync writes since mount */ + uint64_t f_asyncwrites; /* count of async writes since mount */ + uint64_t f_syncreads; /* count of sync reads since mount */ + uint64_t f_asyncreads; /* count of async reads since mount */ + uint64_t f_spare[10]; /* unused spare */ + uint32_t f_namemax; /* maximum filename length */ + uint32_t f_owner; /* user that mounted the filesystem */ + target_freebsd_fsid_t f_fsid; /* filesystem id */ + char f_charspare[80]; /* spare string space */ + char f_fstypename[TARGET_MFSNAMELEN]; /* filesys type name */ + char f_mntfromname[TARGET_MNAMELEN]; /* mount filesystem */ + char f_mntonname[TARGET_MNAMELEN]; /* dir on which mounted*/ +}; + +/* File identifier. These are unique per filesystem on a single machine. */ +#define TARGET_MAXFIDSZ 16 + +struct target_freebsd_fid { + u_short fid_len; /* len of data in bytes */ + u_short fid_data0; /* force longword align */ + char fid_data[TARGET_MAXFIDSZ]; /* data (variable len) */ +}; + +/* Generic file handle */ +struct target_freebsd_fhandle { + target_freebsd_fsid_t fh_fsid; /* Filesystem id of mount point */ + struct target_freebsd_fid fh_fid; /* Filesys specific id */ +}; +typedef struct target_freebsd_fhandle target_freebsd_fhandle_t; + +/* + * sys/fcntl.h + */ +#define TARGET_F_DUPFD 0 +#define TARGET_F_GETFD 1 +#define TARGET_F_SETFD 2 +#define TARGET_F_GETFL 3 +#define TARGET_F_SETFL 4 +#define TARGET_F_GETOWN 5 +#define TARGET_F_SETOWN 6 +#define TARGET_F_OGETLK 7 +#define TARGET_F_OSETLK 8 +#define TARGET_F_OSETLKW 9 +#define TARGET_F_DUP2FD 10 +#define TARGET_F_GETLK 11 +#define TARGET_F_SETLK 12 +#define TARGET_F_SETLKW 13 +#define TARGET_F_SETLK_REMOTE 14 +#define TARGET_F_READAHEAD 15 +#define TARGET_F_RDAHEAD 16 +#define TARGET_F_DUPFD_CLOEXEC 17 +#define TARGET_F_DUP2FD_CLOEXEC 18 + +struct target_freebsd_flock { + int64_t l_start; + int64_t l_len; + int32_t l_pid; + int16_t l_type; + int16_t l_whence; + int32_t l_sysid; +} QEMU_PACKED; + #endif /* ! _SYSCALL_DEFS_H_ */ -- 1.7.8