945 lines · 17.5 KB · C
RawDownload
/* 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> */ /* make sure to include all global symbols */#include "nolibc.h" #ifndef _NOLIBC_SYS_H#define _NOLIBC_SYS_H #include "std.h" /* system includes */#include <linux/unistd.h>#include <linux/signal.h>  /* for SIGCHLD */#include <linux/termios.h>#include <linux/mman.h>#include <linux/fs.h>#include <linux/loop.h>#include <linux/time.h>#include <linux/auxvec.h>#include <linux/fcntl.h> /* for O_* and AT_* */#include <linux/sched.h> /* for CLONE_* */#include <linux/stat.h>  /* for statx() */ #include "errno.h"#include "stdarg.h"#include "types.h"  /* Syscall return helper: takes the syscall value in argument and checks for an * error in it. This may only be used with signed returns (int or long), but * not with pointers. An error is any value < 0. When an error is encountered, * -ret is set into errno and -1 is returned. Otherwise the returned value is * passed as-is with its type preserved. */ #define __sysret(arg)							\({									\	__typeof__(arg) __sysret_arg = (arg);				\	(__sysret_arg < 0)                              /* error ? */	\		? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \		: __sysret_arg;                         /* return original value */ \}) /* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile * time validation and a debugging hook. */ #if defined(NOLIBC_COMPILE_TIME_ENOSYS)static __inline__ int __nolibc_enosys(const char *syscall, ...){	(void)syscall;	return -ENOSYS;} #elif __nolibc_has_attribute(error)__attribute__((error("system call not implemented")))extern int __nolibc_enosys(const char *syscall, ...); #elsestatic __inline__ int __nolibc_enosys(const char *syscall, ...){	extern int __nolibc_enosys_error;	(void)syscall; 	return __nolibc_enosys_error;}#endif  /* * Helper for 32-bit machines where a 64-bit syscall arg needs to be split into * two 32-bit parts while making sure the order of the low/high parts are correct * for the endianness: * __NOLIBC_LLARGPART(x, 0), __NOLIBC_LLARGPART(x, 1) */#define __NOLIBC_LLARGPART(_arg, _part) \	(((union { long long ll; long l[2]; }) { .ll = _arg }).l[_part])  /* 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 *)(unsigned long)__nolibc_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){	/* first call to find current end */	void *ret = _sys_brk(NULL); 	if (ret && _sys_brk(ret + inc) == ret + inc)		return ret + inc; 	SET_ERRNO(ENOMEM);	return (void *)-1;}  /* * int chdir(const char *path); * int fchdir(int fildes); */ static __attribute__((unused))int _sys_chdir(const char *path){	return __nolibc_syscall1(__NR_chdir, path);} static __attribute__((unused))int chdir(const char *path){	return __sysret(_sys_chdir(path));} static __attribute__((unused))int _sys_fchdir(int fildes){	return __nolibc_syscall1(__NR_fchdir, fildes);} static __attribute__((unused))int fchdir(int fildes){	return __sysret(_sys_fchdir(fildes));}  /* * int chmod(const char *path, mode_t mode); */ static __attribute__((unused))int _sys_chmod(const char *path, mode_t mode){#if defined(__NR_fchmodat)	return __nolibc_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0);#else	return __nolibc_syscall2(__NR_chmod, path, mode);#endif} static __attribute__((unused))int chmod(const char *path, mode_t mode){	return __sysret(_sys_chmod(path, mode));}  /* * 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){#if defined(__NR_fchownat)	return __nolibc_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0);#else	return __nolibc_syscall3(__NR_chown, path, owner, group);#endif} static __attribute__((unused))int chown(const char *path, uid_t owner, gid_t group){	return __sysret(_sys_chown(path, owner, group));}  /* * int chroot(const char *path); */ static __attribute__((unused))int _sys_chroot(const char *path){	return __nolibc_syscall1(__NR_chroot, path);} static __attribute__((unused))int chroot(const char *path){	return __sysret(_sys_chroot(path));}  /* * int close(int fd); */ static __attribute__((unused))int _sys_close(int fd){	return __nolibc_syscall1(__NR_close, fd);} static __attribute__((unused))int close(int fd){	return __sysret(_sys_close(fd));}  /* * int dup(int fd); */ static __attribute__((unused))int _sys_dup(int fd){	return __nolibc_syscall1(__NR_dup, fd);} static __attribute__((unused))int dup(int fd){	return __sysret(_sys_dup(fd));}  /* * int dup2(int old, int new); */ static __attribute__((unused))int _sys_dup2(int old, int new){#if defined(__NR_dup3)	int ret, nr_fcntl; #ifdef __NR_fcntl64	nr_fcntl = __NR_fcntl64;#else	nr_fcntl = __NR_fcntl;#endif 	if (old == new) {		ret = __nolibc_syscall2(nr_fcntl, old, F_GETFD);		return ret < 0 ? ret : old;	} 	return __nolibc_syscall3(__NR_dup3, old, new, 0);#else	return __nolibc_syscall2(__NR_dup2, old, new);#endif} static __attribute__((unused))int dup2(int old, int new){	return __sysret(_sys_dup2(old, new));}  /* * int dup3(int old, int new, int flags); */ #if defined(__NR_dup3)static __attribute__((unused))int _sys_dup3(int old, int new, int flags){	return __nolibc_syscall3(__NR_dup3, old, new, flags);} static __attribute__((unused))int dup3(int old, int new, int flags){	return __sysret(_sys_dup3(old, new, flags));}#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 __nolibc_syscall3(__NR_execve, filename, argv, envp);} static __attribute__((unused))int execve(const char *filename, char *const argv[], char *const envp[]){	return __sysret(_sys_execve(filename, argv, envp));}  /* * void exit(int status); */ static __attribute__((noreturn,unused))void _sys_exit(int status){	__nolibc_syscall1(__NR_exit, status & 255);	while(1); /* shut the "noreturn" warnings. */} static __attribute__((noreturn,unused))void _exit(int status){	_sys_exit(status);} static __attribute__((noreturn,unused))void exit(int status){	_exit(status);}  /* * pid_t fork(void); */ #ifndef _sys_forkstatic __attribute__((unused))pid_t _sys_fork(void){#if defined(__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 __nolibc_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0);#else	return __nolibc_syscall0(__NR_fork);#endif}#endif static __attribute__((unused))pid_t fork(void){	return __sysret(_sys_fork());} #ifndef _sys_vforkstatic __attribute__((unused))pid_t _sys_vfork(void){#if defined(__NR_clone)	/* See the note in _sys_fork(). */	return __nolibc_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0);#elif defined(__NR_vfork)	return __nolibc_syscall0(__NR_vfork);#endif}#endif static __attribute__((unused))pid_t vfork(void){	return __sysret(_sys_vfork());} /* * int fsync(int fd); */ static __attribute__((unused))int _sys_fsync(int fd){	return __nolibc_syscall1(__NR_fsync, fd);} static __attribute__((unused))int fsync(int fd){	return __sysret(_sys_fsync(fd));}  /* * 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 __nolibc_syscall3(__NR_getdents64, fd, dirp, count);} static __attribute__((unused))int getdents64(int fd, struct linux_dirent64 *dirp, int count){	return __sysret(_sys_getdents64(fd, dirp, count));}  /* * uid_t geteuid(void); */ static __attribute__((unused))uid_t _sys_geteuid(void){#if defined(__NR_geteuid32)	return __nolibc_syscall0(__NR_geteuid32);#else	return __nolibc_syscall0(__NR_geteuid);#endif} static __attribute__((unused))uid_t geteuid(void){	return _sys_geteuid();}  /* * pid_t getpgid(pid_t pid); */ static __attribute__((unused))pid_t _sys_getpgid(pid_t pid){	return __nolibc_syscall1(__NR_getpgid, pid);} static __attribute__((unused))pid_t getpgid(pid_t pid){	return __sysret(_sys_getpgid(pid));}  /* * 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)

Lines 1–500 of 945.