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;