/* 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,