| /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ |
| /* |
| * Syscall definitions for NOLIBC (those in man(2)) |
| * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> |
| */ |
| |
| #ifndef _NOLIBC_SYS_H |
| #define _NOLIBC_SYS_H |
| |
| #include <stdarg.h> |
| #include "std.h" |
| |
| /* system includes */ |
| #include <asm/unistd.h> |
| #include <asm/signal.h> // for SIGCHLD |
| #include <asm/ioctls.h> |
| #include <asm/mman.h> |
| #include <linux/fs.h> |
| #include <linux/loop.h> |
| #include <linux/time.h> |
| |
| #include "arch.h" |
| #include "errno.h" |
| #include "types.h" |
| |
| |
| /* Functions in this file only describe syscalls. They're declared static so |
| * that the compiler usually decides to inline them while still being allowed |
| * to pass a pointer to one of their instances. Each syscall exists in two |
| * versions: |
| * - the "internal" ones, which matches the raw syscall interface at the |
| * kernel level, which may sometimes slightly differ from the documented |
| * libc-level ones. For example most of them return either a valid value |
| * or -errno. All of these are prefixed with "sys_". They may be called |
| * by non-portable applications if desired. |
| * |
| * - the "exported" ones, whose interface must closely match the one |
| * documented in man(2), that applications are supposed to expect. These |
| * ones rely on the internal ones, and set errno. |
| * |
| * Each syscall will be defined with the two functions, sorted in alphabetical |
| * order applied to the exported names. |
| * |
| * In case of doubt about the relevance of a function here, only those which |
| * set errno should be defined here. Wrappers like those appearing in man(3) |
| * should not be placed here. |
| */ |
| |
| |
| /* |
| * int brk(void *addr); |
| * void *sbrk(intptr_t inc) |
| */ |
| |
| static __attribute__((unused)) |
| void *sys_brk(void *addr) |
| { |
| return (void *)my_syscall1(__NR_brk, addr); |
| } |
| |
| static __attribute__((unused)) |
| int brk(void *addr) |
| { |
| void *ret = sys_brk(addr); |
| |
| if (!ret) { |
| SET_ERRNO(ENOMEM); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static __attribute__((unused)) |
| void *sbrk(intptr_t inc) |
| { |
| void *ret; |
| |
| /* first call to find current end */ |
| if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) |
| return ret + inc; |
| |
| SET_ERRNO(ENOMEM); |
| return (void *)-1; |
| } |
| |
| |
| /* |
| * int chdir(const char *path); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_chdir(const char *path) |
| { |
| return my_syscall1(__NR_chdir, path); |
| } |
| |
| static __attribute__((unused)) |
| int chdir(const char *path) |
| { |
| int ret = sys_chdir(path); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int chmod(const char *path, mode_t mode); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_chmod(const char *path, mode_t mode) |
| { |
| #ifdef __NR_fchmodat |
| return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); |
| #elif defined(__NR_chmod) |
| return my_syscall2(__NR_chmod, path, mode); |
| #else |
| #error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int chmod(const char *path, mode_t mode) |
| { |
| int ret = sys_chmod(path, mode); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int chown(const char *path, uid_t owner, gid_t group); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_chown(const char *path, uid_t owner, gid_t group) |
| { |
| #ifdef __NR_fchownat |
| return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); |
| #elif defined(__NR_chown) |
| return my_syscall3(__NR_chown, path, owner, group); |
| #else |
| #error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int chown(const char *path, uid_t owner, gid_t group) |
| { |
| int ret = sys_chown(path, owner, group); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int chroot(const char *path); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_chroot(const char *path) |
| { |
| return my_syscall1(__NR_chroot, path); |
| } |
| |
| static __attribute__((unused)) |
| int chroot(const char *path) |
| { |
| int ret = sys_chroot(path); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int close(int fd); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_close(int fd) |
| { |
| return my_syscall1(__NR_close, fd); |
| } |
| |
| static __attribute__((unused)) |
| int close(int fd) |
| { |
| int ret = sys_close(fd); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int dup(int fd); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_dup(int fd) |
| { |
| return my_syscall1(__NR_dup, fd); |
| } |
| |
| static __attribute__((unused)) |
| int dup(int fd) |
| { |
| int ret = sys_dup(fd); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int dup2(int old, int new); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_dup2(int old, int new) |
| { |
| #ifdef __NR_dup3 |
| return my_syscall3(__NR_dup3, old, new, 0); |
| #elif defined(__NR_dup2) |
| return my_syscall2(__NR_dup2, old, new); |
| #else |
| #error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int dup2(int old, int new) |
| { |
| int ret = sys_dup2(old, new); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int dup3(int old, int new, int flags); |
| */ |
| |
| #ifdef __NR_dup3 |
| static __attribute__((unused)) |
| int sys_dup3(int old, int new, int flags) |
| { |
| return my_syscall3(__NR_dup3, old, new, flags); |
| } |
| |
| static __attribute__((unused)) |
| int dup3(int old, int new, int flags) |
| { |
| int ret = sys_dup3(old, new, flags); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| #endif |
| |
| |
| /* |
| * int execve(const char *filename, char *const argv[], char *const envp[]); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_execve(const char *filename, char *const argv[], char *const envp[]) |
| { |
| return my_syscall3(__NR_execve, filename, argv, envp); |
| } |
| |
| static __attribute__((unused)) |
| int execve(const char *filename, char *const argv[], char *const envp[]) |
| { |
| int ret = sys_execve(filename, argv, envp); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * void exit(int status); |
| */ |
| |
| static __attribute__((noreturn,unused)) |
| void sys_exit(int status) |
| { |
| my_syscall1(__NR_exit, status & 255); |
| while(1); // shut the "noreturn" warnings. |
| } |
| |
| static __attribute__((noreturn,unused)) |
| void exit(int status) |
| { |
| sys_exit(status); |
| } |
| |
| |
| /* |
| * pid_t fork(void); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_fork(void) |
| { |
| #ifdef __NR_clone |
| /* note: some archs only have clone() and not fork(). Different archs |
| * have a different API, but most archs have the flags on first arg and |
| * will not use the rest with no other flag. |
| */ |
| return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); |
| #elif defined(__NR_fork) |
| return my_syscall0(__NR_fork); |
| #else |
| #error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| pid_t fork(void) |
| { |
| pid_t ret = sys_fork(); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int fsync(int fd); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_fsync(int fd) |
| { |
| return my_syscall1(__NR_fsync, fd); |
| } |
| |
| static __attribute__((unused)) |
| int fsync(int fd) |
| { |
| int ret = sys_fsync(fd); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int getdents64(int fd, struct linux_dirent64 *dirp, int count); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) |
| { |
| return my_syscall3(__NR_getdents64, fd, dirp, count); |
| } |
| |
| static __attribute__((unused)) |
| int getdents64(int fd, struct linux_dirent64 *dirp, int count) |
| { |
| int ret = sys_getdents64(fd, dirp, count); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * pid_t getpgid(pid_t pid); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_getpgid(pid_t pid) |
| { |
| return my_syscall1(__NR_getpgid, pid); |
| } |
| |
| static __attribute__((unused)) |
| pid_t getpgid(pid_t pid) |
| { |
| pid_t ret = sys_getpgid(pid); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * pid_t getpgrp(void); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_getpgrp(void) |
| { |
| return sys_getpgid(0); |
| } |
| |
| static __attribute__((unused)) |
| pid_t getpgrp(void) |
| { |
| return sys_getpgrp(); |
| } |
| |
| |
| /* |
| * pid_t getpid(void); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_getpid(void) |
| { |
| return my_syscall0(__NR_getpid); |
| } |
| |
| static __attribute__((unused)) |
| pid_t getpid(void) |
| { |
| return sys_getpid(); |
| } |
| |
| |
| /* |
| * pid_t getppid(void); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_getppid(void) |
| { |
| return my_syscall0(__NR_getppid); |
| } |
| |
| static __attribute__((unused)) |
| pid_t getppid(void) |
| { |
| return sys_getppid(); |
| } |
| |
| |
| /* |
| * pid_t gettid(void); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_gettid(void) |
| { |
| return my_syscall0(__NR_gettid); |
| } |
| |
| static __attribute__((unused)) |
| pid_t gettid(void) |
| { |
| return sys_gettid(); |
| } |
| |
| |
| /* |
| * int gettimeofday(struct timeval *tv, struct timezone *tz); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_gettimeofday(struct timeval *tv, struct timezone *tz) |
| { |
| return my_syscall2(__NR_gettimeofday, tv, tz); |
| } |
| |
| static __attribute__((unused)) |
| int gettimeofday(struct timeval *tv, struct timezone *tz) |
| { |
| int ret = sys_gettimeofday(tv, tz); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int ioctl(int fd, unsigned long req, void *value); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_ioctl(int fd, unsigned long req, void *value) |
| { |
| return my_syscall3(__NR_ioctl, fd, req, value); |
| } |
| |
| static __attribute__((unused)) |
| int ioctl(int fd, unsigned long req, void *value) |
| { |
| int ret = sys_ioctl(fd, req, value); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| /* |
| * int kill(pid_t pid, int signal); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_kill(pid_t pid, int signal) |
| { |
| return my_syscall2(__NR_kill, pid, signal); |
| } |
| |
| static __attribute__((unused)) |
| int kill(pid_t pid, int signal) |
| { |
| int ret = sys_kill(pid, signal); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int link(const char *old, const char *new); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_link(const char *old, const char *new) |
| { |
| #ifdef __NR_linkat |
| return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); |
| #elif defined(__NR_link) |
| return my_syscall2(__NR_link, old, new); |
| #else |
| #error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int link(const char *old, const char *new) |
| { |
| int ret = sys_link(old, new); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * off_t lseek(int fd, off_t offset, int whence); |
| */ |
| |
| static __attribute__((unused)) |
| off_t sys_lseek(int fd, off_t offset, int whence) |
| { |
| return my_syscall3(__NR_lseek, fd, offset, whence); |
| } |
| |
| static __attribute__((unused)) |
| off_t lseek(int fd, off_t offset, int whence) |
| { |
| off_t ret = sys_lseek(fd, offset, whence); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int mkdir(const char *path, mode_t mode); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_mkdir(const char *path, mode_t mode) |
| { |
| #ifdef __NR_mkdirat |
| return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); |
| #elif defined(__NR_mkdir) |
| return my_syscall2(__NR_mkdir, path, mode); |
| #else |
| #error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int mkdir(const char *path, mode_t mode) |
| { |
| int ret = sys_mkdir(path, mode); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int mknod(const char *path, mode_t mode, dev_t dev); |
| */ |
| |
| static __attribute__((unused)) |
| long sys_mknod(const char *path, mode_t mode, dev_t dev) |
| { |
| #ifdef __NR_mknodat |
| return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); |
| #elif defined(__NR_mknod) |
| return my_syscall3(__NR_mknod, path, mode, dev); |
| #else |
| #error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int mknod(const char *path, mode_t mode, dev_t dev) |
| { |
| int ret = sys_mknod(path, mode, dev); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| #ifndef MAP_SHARED |
| #define MAP_SHARED 0x01 /* Share changes */ |
| #define MAP_PRIVATE 0x02 /* Changes are private */ |
| #define MAP_SHARED_VALIDATE 0x03 /* share + validate extension flags */ |
| #endif |
| |
| #ifndef MAP_FAILED |
| #define MAP_FAILED ((void *)-1) |
| #endif |
| |
| static __attribute__((unused)) |
| void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, |
| off_t offset) |
| { |
| #ifndef my_syscall6 |
| /* Function not implemented. */ |
| return (void *)-ENOSYS; |
| #else |
| |
| int n; |
| |
| #if defined(__NR_mmap2) |
| n = __NR_mmap2; |
| offset >>= 12; |
| #else |
| n = __NR_mmap; |
| #endif |
| |
| return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) |
| { |
| void *ret = sys_mmap(addr, length, prot, flags, fd, offset); |
| |
| if ((unsigned long)ret >= -4095UL) { |
| SET_ERRNO(-(long)ret); |
| ret = MAP_FAILED; |
| } |
| return ret; |
| } |
| |
| static __attribute__((unused)) |
| int sys_munmap(void *addr, size_t length) |
| { |
| return my_syscall2(__NR_munmap, addr, length); |
| } |
| |
| static __attribute__((unused)) |
| int munmap(void *addr, size_t length) |
| { |
| int ret = sys_munmap(addr, length); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| /* |
| * int mount(const char *source, const char *target, |
| * const char *fstype, unsigned long flags, |
| * const void *data); |
| */ |
| static __attribute__((unused)) |
| int sys_mount(const char *src, const char *tgt, const char *fst, |
| unsigned long flags, const void *data) |
| { |
| return my_syscall5(__NR_mount, src, tgt, fst, flags, data); |
| } |
| |
| static __attribute__((unused)) |
| int mount(const char *src, const char *tgt, |
| const char *fst, unsigned long flags, |
| const void *data) |
| { |
| int ret = sys_mount(src, tgt, fst, flags, data); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int open(const char *path, int flags[, mode_t mode]); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_open(const char *path, int flags, mode_t mode) |
| { |
| #ifdef __NR_openat |
| return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); |
| #elif defined(__NR_open) |
| return my_syscall3(__NR_open, path, flags, mode); |
| #else |
| #error Neither __NR_openat nor __NR_open defined, cannot implement sys_open() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int open(const char *path, int flags, ...) |
| { |
| mode_t mode = 0; |
| int ret; |
| |
| if (flags & O_CREAT) { |
| va_list args; |
| |
| va_start(args, flags); |
| mode = va_arg(args, mode_t); |
| va_end(args); |
| } |
| |
| ret = sys_open(path, flags, mode); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int pivot_root(const char *new, const char *old); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_pivot_root(const char *new, const char *old) |
| { |
| return my_syscall2(__NR_pivot_root, new, old); |
| } |
| |
| static __attribute__((unused)) |
| int pivot_root(const char *new, const char *old) |
| { |
| int ret = sys_pivot_root(new, old); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int poll(struct pollfd *fds, int nfds, int timeout); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_poll(struct pollfd *fds, int nfds, int timeout) |
| { |
| #if defined(__NR_ppoll) |
| struct timespec t; |
| |
| if (timeout >= 0) { |
| t.tv_sec = timeout / 1000; |
| t.tv_nsec = (timeout % 1000) * 1000000; |
| } |
| return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); |
| #elif defined(__NR_poll) |
| return my_syscall3(__NR_poll, fds, nfds, timeout); |
| #else |
| #error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int poll(struct pollfd *fds, int nfds, int timeout) |
| { |
| int ret = sys_poll(fds, nfds, timeout); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * ssize_t read(int fd, void *buf, size_t count); |
| */ |
| |
| static __attribute__((unused)) |
| ssize_t sys_read(int fd, void *buf, size_t count) |
| { |
| return my_syscall3(__NR_read, fd, buf, count); |
| } |
| |
| static __attribute__((unused)) |
| ssize_t read(int fd, void *buf, size_t count) |
| { |
| ssize_t ret = sys_read(fd, buf, count); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int reboot(int cmd); |
| * <cmd> is among LINUX_REBOOT_CMD_* |
| */ |
| |
| static __attribute__((unused)) |
| ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) |
| { |
| return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); |
| } |
| |
| static __attribute__((unused)) |
| int reboot(int cmd) |
| { |
| int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int sched_yield(void); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_sched_yield(void) |
| { |
| return my_syscall0(__NR_sched_yield); |
| } |
| |
| static __attribute__((unused)) |
| int sched_yield(void) |
| { |
| int ret = sys_sched_yield(); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int select(int nfds, fd_set *read_fds, fd_set *write_fds, |
| * fd_set *except_fds, struct timeval *timeout); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) |
| { |
| #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) |
| struct sel_arg_struct { |
| unsigned long n; |
| fd_set *r, *w, *e; |
| struct timeval *t; |
| } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; |
| return my_syscall1(__NR_select, &arg); |
| #elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) |
| struct timespec t; |
| |
| if (timeout) { |
| t.tv_sec = timeout->tv_sec; |
| t.tv_nsec = timeout->tv_usec * 1000; |
| } |
| return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); |
| #elif defined(__NR__newselect) || defined(__NR_select) |
| #ifndef __NR__newselect |
| #define __NR__newselect __NR_select |
| #endif |
| return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); |
| #else |
| #error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) |
| { |
| int ret = sys_select(nfds, rfds, wfds, efds, timeout); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int setpgid(pid_t pid, pid_t pgid); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_setpgid(pid_t pid, pid_t pgid) |
| { |
| return my_syscall2(__NR_setpgid, pid, pgid); |
| } |
| |
| static __attribute__((unused)) |
| int setpgid(pid_t pid, pid_t pgid) |
| { |
| int ret = sys_setpgid(pid, pgid); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * pid_t setsid(void); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_setsid(void) |
| { |
| return my_syscall0(__NR_setsid); |
| } |
| |
| static __attribute__((unused)) |
| pid_t setsid(void) |
| { |
| pid_t ret = sys_setsid(); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int stat(const char *path, struct stat *buf); |
| * Warning: the struct stat's layout is arch-dependent. |
| */ |
| |
| static __attribute__((unused)) |
| int sys_stat(const char *path, struct stat *buf) |
| { |
| struct sys_stat_struct stat; |
| long ret; |
| |
| #ifdef __NR_newfstatat |
| /* only solution for arm64 */ |
| ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); |
| #elif defined(__NR_stat) |
| ret = my_syscall2(__NR_stat, path, &stat); |
| #else |
| #error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() |
| #endif |
| buf->st_dev = stat.st_dev; |
| buf->st_ino = stat.st_ino; |
| buf->st_mode = stat.st_mode; |
| buf->st_nlink = stat.st_nlink; |
| buf->st_uid = stat.st_uid; |
| buf->st_gid = stat.st_gid; |
| buf->st_rdev = stat.st_rdev; |
| buf->st_size = stat.st_size; |
| buf->st_blksize = stat.st_blksize; |
| buf->st_blocks = stat.st_blocks; |
| buf->st_atime = stat.st_atime; |
| buf->st_mtime = stat.st_mtime; |
| buf->st_ctime = stat.st_ctime; |
| return ret; |
| } |
| |
| static __attribute__((unused)) |
| int stat(const char *path, struct stat *buf) |
| { |
| int ret = sys_stat(path, buf); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int symlink(const char *old, const char *new); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_symlink(const char *old, const char *new) |
| { |
| #ifdef __NR_symlinkat |
| return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); |
| #elif defined(__NR_symlink) |
| return my_syscall2(__NR_symlink, old, new); |
| #else |
| #error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int symlink(const char *old, const char *new) |
| { |
| int ret = sys_symlink(old, new); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * mode_t umask(mode_t mode); |
| */ |
| |
| static __attribute__((unused)) |
| mode_t sys_umask(mode_t mode) |
| { |
| return my_syscall1(__NR_umask, mode); |
| } |
| |
| static __attribute__((unused)) |
| mode_t umask(mode_t mode) |
| { |
| return sys_umask(mode); |
| } |
| |
| |
| /* |
| * int umount2(const char *path, int flags); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_umount2(const char *path, int flags) |
| { |
| return my_syscall2(__NR_umount2, path, flags); |
| } |
| |
| static __attribute__((unused)) |
| int umount2(const char *path, int flags) |
| { |
| int ret = sys_umount2(path, flags); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * int unlink(const char *path); |
| */ |
| |
| static __attribute__((unused)) |
| int sys_unlink(const char *path) |
| { |
| #ifdef __NR_unlinkat |
| return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); |
| #elif defined(__NR_unlink) |
| return my_syscall1(__NR_unlink, path); |
| #else |
| #error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() |
| #endif |
| } |
| |
| static __attribute__((unused)) |
| int unlink(const char *path) |
| { |
| int ret = sys_unlink(path); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * pid_t wait(int *status); |
| * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage); |
| * pid_t waitpid(pid_t pid, int *status, int options); |
| */ |
| |
| static __attribute__((unused)) |
| pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) |
| { |
| return my_syscall4(__NR_wait4, pid, status, options, rusage); |
| } |
| |
| static __attribute__((unused)) |
| pid_t wait(int *status) |
| { |
| pid_t ret = sys_wait4(-1, status, 0, NULL); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| static __attribute__((unused)) |
| pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) |
| { |
| pid_t ret = sys_wait4(pid, status, options, rusage); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| static __attribute__((unused)) |
| pid_t waitpid(pid_t pid, int *status, int options) |
| { |
| pid_t ret = sys_wait4(pid, status, options, NULL); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| |
| /* |
| * ssize_t write(int fd, const void *buf, size_t count); |
| */ |
| |
| static __attribute__((unused)) |
| ssize_t sys_write(int fd, const void *buf, size_t count) |
| { |
| return my_syscall3(__NR_write, fd, buf, count); |
| } |
| |
| static __attribute__((unused)) |
| ssize_t write(int fd, const void *buf, size_t count) |
| { |
| ssize_t ret = sys_write(fd, buf, count); |
| |
| if (ret < 0) { |
| SET_ERRNO(-ret); |
| ret = -1; |
| } |
| return ret; |
| } |
| |
| /* make sure to include all global symbols */ |
| #include "nolibc.h" |
| |
| #endif /* _NOLIBC_SYS_H */ |