diff --git a/lib/ff_syscall_wrapper.c b/lib/ff_syscall_wrapper.c index 18b97b0e5..0c99d2f64 100644 --- a/lib/ff_syscall_wrapper.c +++ b/lib/ff_syscall_wrapper.c @@ -177,6 +177,31 @@ /* ioctl define end */ +/* fcntl define start */ + +#define LINUX_F_DUPFD 0 +#define LINUX_F_GETFD 1 +#define LINUX_F_SETFD 2 +#define LINUX_F_GETFL 3 +#define LINUX_F_SETFL 4 +#define LINUX_F_GETLK 5 +#define LINUX_F_SETLK 6 +#define LINUX_F_SETLKW 7 +#define LINUX_F_SETOWN 8 +#define LINUX_F_GETOWN 9 +#define LINUX_F_OFD_GETLK 36 +#define LINUX_F_OFD_SETLK 37 +#define LINUX_F_OFD_SETLKW 38 + +#define LINUX_O_APPEND 0x400 +#define LINUX_O_NONBLOCK 0x800 +#define LINUX_O_ASYNC 0x2000 +#define LINUX_O_DIRECT 0x4000 +#define LINUX_O_NOATIME 0x40000 +#define LINUX_O_CLOEXEC 0x80000 + +/* fcntl define end */ + /* af define start */ #define LINUX_AF_INET6 10 @@ -246,6 +271,140 @@ struct linux_cmsghdr extern int sendit(struct thread *td, int s, struct msghdr *mp, int flags); +/* convert linux argp to freebsd argp. */ +static inline int +linux2freebsd_fcntl(int cmd, intptr_t *argp) +{ + switch(cmd) { + case LINUX_F_DUPFD: + return F_DUPFD; + case LINUX_F_GETFD: + return F_GETFD; + case LINUX_F_SETFD: + if (*argp & LINUX_O_CLOEXEC) { + //clear linux O_CLOEXEC, set freebsd O_CLOEXEC. + *argp &= ~LINUX_O_CLOEXEC; + *argp |= O_CLOEXEC; + } + + return F_SETFD; + case LINUX_F_GETFL: + return F_GETFL; + case LINUX_F_SETFL: + if (*argp & LINUX_O_NONBLOCK) { + //clear linux O_NONBLOCK, set freebsd O_NONBLOCK. + *argp &= ~LINUX_O_NONBLOCK; + *argp |= O_NONBLOCK; + } + + if (*argp & LINUX_O_APPEND) { + //clear linux O_APPEND, set freebsd O_APPEND. + *argp &= ~LINUX_O_APPEND; + *argp |= O_APPEND; + } + + if (*argp & LINUX_O_ASYNC) { + //clear linux O_ASYNC, set freebsd O_ASYNC. + *argp &= ~LINUX_O_ASYNC; + *argp |= O_ASYNC; + } + + if (*argp & LINUX_O_DIRECT) { + //clear linux O_DIRECT, set freebsd O_DIRECT. + *argp &= ~LINUX_O_DIRECT; + *argp |= O_DIRECT; + } + + return F_SETFL; + case LINUX_F_GETLK: + return F_GETLK; + case LINUX_F_SETLK: + return F_SETLK; + case LINUX_F_SETLKW: + return F_SETLKW; + case LINUX_F_SETOWN: + return F_SETOWN; + case LINUX_F_GETOWN: + return F_GETOWN; + case LINUX_F_OFD_GETLK: + return F_OGETLK; + case LINUX_F_OFD_SETLK: + return F_OSETLK; + case LINUX_F_OFD_SETLKW: + return F_OSETLKW; + default: + return cmd; + } +} + +/* + * convert freebsd flags to linux flags. + * cmd has been converted to freebsd mode. + */ +static inline int +freebsd2linux_fcntl(int cmd, int flags) +{ + switch(cmd) { + case F_DUPFD: + return flags; + case F_GETFD: + if (flags & O_CLOEXEC) { + //clear freebsd O_DIRECT, set linux O_DIRECT. + flags &= ~O_CLOEXEC; + flags |= LINUX_O_CLOEXEC; + } + return flags; + case F_SETFD: + return flags; + case F_GETFL: + if (flags & O_NONBLOCK) { + //clear linux O_NONBLOCK, set freebsd O_NONBLOCK. + flags &= ~O_NONBLOCK; + flags |= LINUX_O_NONBLOCK; + } + + if (flags & O_APPEND) { + //clear linux O_APPEND, set freebsd O_APPEND. + flags &= ~O_APPEND; + flags |= LINUX_O_APPEND; + } + + if (flags & O_ASYNC) { + //clear linux O_ASYNC, set freebsd O_ASYNC. + flags &= ~O_ASYNC; + flags |= LINUX_O_ASYNC; + } + + if (flags & O_DIRECT) { + //clear linux O_DIRECT, set freebsd O_DIRECT. + flags &= ~O_DIRECT; + flags |= LINUX_O_DIRECT; + } + + return flags; + case LINUX_F_SETFL: + return flags; + case F_GETLK: + return flags; + case F_SETLK: + return flags; + case F_SETLKW: + return flags; + case F_SETOWN: + return flags; + case F_GETOWN: + return flags; + case F_OGETLK: + return flags; + case F_OSETLK: + return flags; + case F_OSETLKW: + return flags; + default: + return flags; + } +} + static long linux2freebsd_ioctl(unsigned long request) { @@ -1150,9 +1309,11 @@ ff_fcntl(int fd, int cmd, ...) argp = va_arg(ap, uintptr_t); va_end(ap); + cmd = linux2freebsd_fcntl(cmd, &argp); + if ((rc = kern_fcntl(curthread, fd, cmd, argp))) goto kern_fail; - rc = curthread->td_retval[0]; + rc = freebsd2linux_fcntl(cmd, curthread->td_retval[0]); return (rc); kern_fail: ff_os_errno(rc);