liblinux++

A hosted C++ runtime without any libc.
git clone git://henryandlizzy.uk/liblinux++
Log | Files | Refs

linux.hpp (6749B)


      1 #pragma once
      2 
      3 using uint64_t = unsigned long;
      4 using int64_t = signed long;
      5 using uint32_t = unsigned int;
      6 using int32_t = signed int;
      7 using uint16_t = unsigned short;
      8 using int16_t = signed short;
      9 using uint8_t = unsigned char;
     10 using int8_t = signed char;
     11 
     12 using size_t = uint64_t;
     13 using ssize_t = int64_t;
     14 using uintptr_t = uint64_t;
     15 using intptr_t = int64_t;
     16 using ino64_t = uint64_t;
     17 using off64_t = int64_t;
     18 using time_t = int64_t;
     19 using socklen_t = uint32_t;
     20 
     21 enum {
     22 	O_RDONLY = 0,
     23 	O_WRONLY = 1,
     24 	O_RDWR = 2,
     25 	O_CREAT = 0100,
     26 	O_PATH = 010000000,
     27 
     28 	PROT_READ = 0x1,
     29 	PROT_WRITE = 0x2,
     30 	PROT_EXEC = 0x4,
     31 	MAP_FIXED = 0x10,
     32 	MAP_ANONYMOUS = 0x20,
     33 	MAP_SHARED = 0x1,
     34 	MAP_PRIVATE = 0x2,
     35 
     36 	DT_UNKNOWN = 0,
     37 	DT_FIFO = 1,
     38 	DT_CHR = 2,
     39 	DT_DIR = 4,
     40 	DT_BLK = 6,
     41 	DT_REG = 8,
     42 	DT_LNK = 10,
     43 	DT_SOCK = 12,
     44 	DT_WHT = 14,
     45 };
     46 
     47 #define assert(condition) if (not (condition)) __builtin_trap();
     48 
     49 template <typename T>
     50 struct span
     51 {
     52 	constexpr span() = default;
     53 	constexpr span(T* p, size_t n) noexcept
     54 	: ptr{p}
     55 	, len{n}
     56 	{}
     57 
     58 	constexpr span(T* p, T* end) noexcept
     59 	: ptr{p}
     60 	, len{static_cast<size_t>(end - p)}
     61 	{
     62 		assert(p <= end);
     63 	}
     64 
     65 	template <size_t N>
     66 	constexpr explicit span(T (&arr)[N]) noexcept
     67 	: span{arr, N}
     68 	{}
     69 
     70 	size_t size() const noexcept
     71 	{
     72 		return len;
     73 	}
     74 	T* begin() const noexcept
     75 	{
     76 		return ptr;
     77 	}
     78 	T* end() const noexcept
     79 	{
     80 		return begin() + size();
     81 	}
     82 	T& operator[](size_t n) noexcept
     83 	{
     84 		assert(n < len);
     85 		return ptr[n];
     86 	}
     87 
     88 	bool operator == (span<T> rhs) const noexcept
     89 	{
     90 		if (size() != rhs.size())
     91 			return false;
     92 		for (size_t i = 0; i < size(); ++i)
     93 			if (ptr[i] != rhs[i])
     94 				return false;
     95 		return true;
     96 	}
     97 private:
     98 	T* ptr = nullptr;
     99 	size_t len = 0;
    100 };
    101 
    102 constexpr span<char const> operator ""_sp(char const* begin, size_t size) noexcept
    103 {
    104 	return {begin, size};
    105 }
    106 
    107 #include "errno.hpp"
    108 
    109 struct fd
    110 {
    111 	constexpr fd() = default;
    112 	constexpr explicit fd(int n) noexcept : num{n} {}
    113 	constexpr operator bool() const noexcept { return num >= 0; }
    114 private:
    115 	int num = -1;
    116 };
    117 
    118 constexpr fd const AT_FDCWD{-100};
    119 constexpr fd const stdin{0};
    120 constexpr fd const stdout{1};
    121 constexpr fd const stderr{2};
    122 
    123 template <typename T>
    124 struct [[nodiscard]] syscall_result
    125 {
    126 	explicit operator bool() const noexcept { return val >= 0; }
    127 	T operator*() const noexcept
    128 	{
    129 		assert(*this);
    130 		if constexpr (__is_pointer(T))
    131 			return reinterpret_cast<T>(val);
    132 		else
    133 			return static_cast<T>(val);
    134 	}
    135 	errno_t err() const noexcept
    136 	{
    137 		assert(not *this);
    138 		return static_cast<errno_t>(val);
    139 	}
    140 private:
    141 	int64_t val;
    142 };
    143 
    144 struct c_str
    145 {
    146 	constexpr c_str(char const *p) noexcept
    147 	: str{p}
    148 	{}
    149 
    150 	template <size_t N>
    151 	constexpr c_str(char const (&arr)[N]) noexcept
    152 	: str{arr}
    153 	{
    154 		static_assert(N > 0);
    155 		static_assert(arr[N-1] == '\0');
    156 	}
    157 	size_t length() const noexcept
    158 	{
    159 		if (not str)
    160 			return 0;
    161 
    162 		char const* p = str;
    163 		while (*p)
    164 			++p;
    165 
    166 		return p - str;
    167 	}
    168 	char const* begin() { return str; }
    169 	char const* end() { return begin() + length(); }
    170 
    171 private:
    172 	char const* str;
    173 };
    174 
    175 [[noreturn]]
    176 extern void exit(int error_code) noexcept;
    177 
    178 extern syscall_result<size_t> read(fd src, char data[], size_t count) noexcept;
    179 extern syscall_result<size_t> read(fd src, span<char> data) noexcept;
    180 inline syscall_result<size_t> read(fd src, char* begin, char* end) noexcept
    181 {
    182 	return read(src, begin, end - begin);
    183 }
    184 
    185 extern syscall_result<size_t> write(fd dst, char const data[], size_t count) noexcept;
    186 extern syscall_result<size_t> write(fd dst, span<char const> data) noexcept;
    187 extern syscall_result<size_t> write(fd dst, span<span<char const> const> data) noexcept;
    188 inline syscall_result<size_t> write(fd dst, char const* begin, char const* end) noexcept
    189 {
    190 	return write(dst, begin, end - begin);
    191 }
    192 
    193 extern syscall_result<fd> openat(fd dir, c_str name, int flags, int mode) noexcept;
    194 
    195 extern syscall_result<void> close(fd) noexcept;
    196 
    197 struct [[gnu::packed]] linux_dirent64 {
    198 	ino64_t        d_ino;    /* 64-bit inode number */
    199 	off64_t        d_off;    /* Not an offset; see getdents() */
    200 	unsigned short d_reclen; /* Size of this dirent */
    201 	unsigned char  d_type;   /* File type */
    202 
    203 	linux_dirent64* next() noexcept { return reinterpret_cast<linux_dirent64*>(reinterpret_cast<char*>(this) + d_reclen); }
    204 	char* name() noexcept { return reinterpret_cast<char*>(this) + sizeof(*this); }
    205 };
    206 extern syscall_result<size_t> getdents64(fd dir, span<char> buffer) noexcept;
    207 
    208 extern syscall_result<void*> mmap(void* addr, size_t len, unsigned long prot, unsigned long flags, fd file, size_t off) noexcept;
    209 extern syscall_result<void> munmap(void* addr, size_t len) noexcept;
    210 
    211 struct timespec {
    212 	time_t tv_sec;     /* Seconds */
    213 	uint32_t tv_nsec;  /* Nanoseconds [0, 999'999'999] */
    214 };
    215 
    216 extern syscall_result<void> nanosleep(const timespec &duration, timespec */*_Nullable*/ rem) noexcept;
    217 
    218 enum class rename_flags : unsigned int
    219 {
    220        NOREPLACE = 0b001,
    221        EXCHANGE  = 0b010,
    222        WHITEOUT  = 0b100,
    223 };
    224 
    225 extern syscall_result<void> renameat2(fd olddir, c_str oldpath, fd newdir, c_str newpath, rename_flags flags) noexcept;
    226 
    227 enum class unlink_flags : int
    228 {
    229 	REMOVEDIR = 0x200,
    230 };
    231 
    232 extern syscall_result<void> unlinkat(fd dir, c_str path, unlink_flags flags) noexcept;
    233 
    234 extern syscall_result<void> execve(c_str path, char *const /*_Nullable*/ argv[], char *const /*_Nullable*/ envp[]) noexcept;
    235 
    236 extern syscall_result<fd> socket(int domain, int type, int protocol) noexcept;
    237 
    238 struct addr_ref
    239 {
    240 	span<char const> fat_ptr;
    241 };
    242 
    243 struct un_addr
    244 {
    245 	explicit un_addr(span<char const> addr)
    246 	{
    247 		size_t slen = addr.size();
    248 		assert(slen <= sizeof(path));
    249 		slen += sizeof(family);
    250 		length = slen;
    251 		char* p = path;
    252 		for (auto c : addr)
    253 			*p++ = c;
    254 	}
    255 	operator addr_ref() const noexcept { return {.fat_ptr = {(char const*)this, length}}; }
    256 private:
    257 	[[maybe_unused]] uint16_t family = 1;
    258 	[[maybe_unused]] char path[108];
    259 	uint8_t length;
    260 };
    261 
    262 struct in_addr
    263 {
    264 	explicit in_addr(uint16_t port, uint32_t ipv4) noexcept
    265 	: data{
    266 		uint8_t((port & 0xFF00) >> 8),
    267 		uint8_t((port & 0x00FF) >> 0),
    268 		uint8_t((ipv4 & 0xFF00'0000) >> 24),
    269 		uint8_t((ipv4 & 0x00FF'0000) >> 16),
    270 		uint8_t((ipv4 & 0x0000'FF00) >> 8),
    271 		uint8_t((ipv4 & 0x0000'00FF) >> 0),
    272 	}
    273 	{}
    274 
    275 	operator addr_ref() const noexcept { return {.fat_ptr = {(char const*)this, sizeof(*this)}}; }
    276 private:
    277 	[[maybe_unused]] uint16_t family = 2;
    278 	[[maybe_unused]] uint8_t data[14];
    279 };
    280 
    281 extern syscall_result<void> bind(fd socket, addr_ref addr) noexcept;
    282 extern syscall_result<void> listen(fd socket, int backlog) noexcept;
    283 extern syscall_result<fd> accept(fd socket, void* addr_buf, socklen_t* addr_len) noexcept;
    284 syscall_result<void> setsockopt(fd socket, int level, int option_name, span<char const> value);
    285 extern syscall_result<fd> dup(fd oldfd, fd newfd, int flags = 0) noexcept;