// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
/* platform-specific include files coming from the compiler */
#include <limits.h>
/* libc-specific include files
* The program may be built in 3 ways:
* $(CC) -nostdlib -include /path/to/nolibc.h => NOLIBC already defined
* $(CC) -nostdlib -I/path/to/nolibc/sysroot => _NOLIBC_* guards are present
* $(CC) with default libc => NOLIBC* never defined
*/
#ifndef NOLIBC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _NOLIBC_STDIO_H
/* standard libcs need more includes */
#include <linux/reboot.h>
#include <sys/io.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/sysmacros.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sched.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#endif
#endif
/* will be used by nolibc by getenv() */
char **environ;
/* definition of a series of tests */
struct test {
const char *name; // test name
int (*func)(int min, int max); // handler
};
#ifndef _NOLIBC_STDLIB_H
char *itoa(int i)
{
static char buf[12];
int ret;
ret = snprintf(buf, sizeof(buf), "%d", i);
return (ret >= 0 && ret < sizeof(buf)) ? buf : "#err";
}
#endif
#define CASE_ERR(err) \
case err: return #err
/* returns the error name (e.g. "ENOENT") for common errors, "SUCCESS" for 0,
* or the decimal value for less common ones.
*/
const char *errorname(int err)
{
switch (err) {
case 0: return "SUCCESS";
CASE_ERR(EPERM);
CASE_ERR(ENOENT);
CASE_ERR(ESRCH);
CASE_ERR(EINTR);
CASE_ERR(EIO);
CASE_ERR(ENXIO);
CASE_ERR(E2BIG);
CASE_ERR(ENOEXEC);
CASE_ERR(EBADF);
CASE_ERR(ECHILD);
CASE_ERR(EAGAIN);
CASE_ERR(ENOMEM);
CASE_ERR(EACCES);
CASE_ERR(EFAULT);
CASE_ERR(ENOTBLK);
CASE_ERR(EBUSY);
CASE_ERR(EEXIST);
CASE_ERR(EXDEV);
CASE_ERR(ENODEV);
CASE_ERR(ENOTDIR);
CASE_ERR(EISDIR);
CASE_ERR(EINVAL);
CASE_ERR(ENFILE);
CASE_ERR(EMFILE);
CASE_ERR(ENOTTY);
CASE_ERR(ETXTBSY);
CASE_ERR(EFBIG);
CASE_ERR(ENOSPC);
CASE_ERR(ESPIPE);
CASE_ERR(EROFS);
CASE_ERR(EMLINK);
CASE_ERR(EPIPE);
CASE_ERR(EDOM);
CASE_ERR(ERANGE);
CASE_ERR(ENOSYS);
default:
return itoa(err);
}
}
static int pad_spc(int llen, int cnt, const char *fmt, ...)
{
va_list args;
int len;
int ret;
for (len = 0; len < cnt - llen; len++)
putchar(' ');
va_start(args, fmt);
ret = vfprintf(stdout, fmt, args);
va_end(args);
return ret < 0 ? ret : ret + len;
}
/* The tests below are intended to be used by the macroes, which evaluate
* expression <expr>, print the status to stdout, and update the "ret"
* variable to count failures. The functions themselves return the number
* of failures, thus either 0 or 1.
*/
#define EXPECT_ZR(cond, expr) \
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_zr(expr, llen); } while (0)
static int expect_zr(int expr, int llen)
{
int ret = !(expr == 0);
llen += printf(" = %d ", expr);
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_NZ(cond, expr, val) \
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_nz(expr, llen; } while (0)
static int expect_nz(int expr, int llen)
{
int ret = !(expr != 0);
llen += printf(" = %d ", expr);
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_EQ(cond, expr, val) \
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_eq(expr, llen, val); } while (0)
static int expect_eq(uint64_t expr, int llen, uint64_t val)
{
int ret = !(expr == val);
llen += printf(" = %lld ", expr);
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_NE(cond, expr, val) \
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ne(expr, llen, val); } while (0)
static int expect_ne(int expr, int llen, int val)
{
int ret = !(expr != val);
llen += printf(" = %d ", expr);
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_GE(cond, expr, val) \
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_ge(expr, llen, val); } while (0)
static int expect_ge(int expr, int llen, int val)
{
int ret = !(expr >= val);
llen += printf(" = %d ", expr);
pad_spc(llen, 64, ret ? "[FAIL]\n" : " [OK]\n");
return ret;
}
#define EXPECT_GT(cond, expr, val) \
do { if (!cond) pad_spc(llen, 64, "[SKIPPED]\n"); else ret += expect_gt(expr, llen, val); } while (0)
static int expect_gt(int expr, int llen, int val)
{
int ret = !(expr > val);
llen += printf(" = %d ", expr)