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;