diff options
Diffstat (limited to 'libc-top-half/musl/src/fcntl/fcntl.c')
-rw-r--r-- | libc-top-half/musl/src/fcntl/fcntl.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/fcntl/fcntl.c b/libc-top-half/musl/src/fcntl/fcntl.c new file mode 100644 index 0000000..d3bff5c --- /dev/null +++ b/libc-top-half/musl/src/fcntl/fcntl.c @@ -0,0 +1,48 @@ +#define _GNU_SOURCE +#include <fcntl.h> +#include <stdarg.h> +#include <errno.h> +#include "syscall.h" + +int fcntl(int fd, int cmd, ...) +{ + unsigned long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, unsigned long); + va_end(ap); + if (cmd == F_SETFL) arg |= O_LARGEFILE; + if (cmd == F_SETLKW) return syscall_cp(SYS_fcntl, fd, cmd, (void *)arg); + if (cmd == F_GETOWN) { + struct f_owner_ex ex; + int ret = __syscall(SYS_fcntl, fd, F_GETOWN_EX, &ex); + if (ret == -EINVAL) return __syscall(SYS_fcntl, fd, cmd, (void *)arg); + if (ret) return __syscall_ret(ret); + return ex.type == F_OWNER_PGRP ? -ex.pid : ex.pid; + } + if (cmd == F_DUPFD_CLOEXEC) { + int ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, arg); + if (ret != -EINVAL) { + if (ret >= 0) + __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC); + return __syscall_ret(ret); + } + ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, 0); + if (ret != -EINVAL) { + if (ret >= 0) __syscall(SYS_close, ret); + return __syscall_ret(-EINVAL); + } + ret = __syscall(SYS_fcntl, fd, F_DUPFD, arg); + if (ret >= 0) __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC); + return __syscall_ret(ret); + } + switch (cmd) { + case F_SETLK: + case F_GETLK: + case F_GETOWN_EX: + case F_SETOWN_EX: + return syscall(SYS_fcntl, fd, cmd, (void *)arg); + default: + return syscall(SYS_fcntl, fd, cmd, arg); + } +} |