liblinux++

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

linux.hpp (6771B)


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