hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

syscalls.ha (23277B)


      1 // License: MPL-2.0
      2 // (c) 2021 Alexey Yerin <yyp@disroot.org>
      3 // (c) 2021 Drew DeVault <sir@cmpwn.com>
      4 // (c) 2021 Eyal Sawady <ecs@d2evs.net>
      5 // (c) 2021 Mykyta Holubakha <hilobakho@gmail.com>
      6 // (c) 2021 Thomas Bracht Laumann Jespersen <t@laumann.xyz>
      7 // (c) 2022 Vincent Dagonneau <v@vda.io>
      8 
      9 fn syscall0(_: u64) u64;
     10 fn syscall1(_: u64, _: u64) u64;
     11 fn syscall2(_: u64, _: u64, _: u64) u64;
     12 fn syscall3(_: u64, _: u64, _: u64, _: u64) u64;
     13 fn syscall4(_: u64, _: u64, _: u64, _: u64, _: u64) u64;
     14 fn syscall5(_: u64, _: u64, _: u64, _: u64, _: u64, _: u64) u64;
     15 fn syscall6(_: u64, _: u64, _: u64, _: u64, _: u64, _: u64, _: u64) u64;
     16 
     17 export def PATH_MAX: size = 4096z;
     18 export type path = (str | []u8 | *const char);
     19 let pathbuf: [PATH_MAX + 1]u8 = [0...];
     20 
     21 fn copy_kpath(path: path, buf: []u8) (*const char | errno) = {
     22 	let path = match (path) {
     23 	case let c: *const char =>
     24 		return c;
     25 	case let s: str =>
     26 		let ptr = &s: *struct {
     27 			buf: *[*]u8,
     28 			length: size,
     29 			capacity: size,
     30 		};
     31 		yield ptr.buf[..ptr.length];
     32 	case let b: []u8 =>
     33 		yield b;
     34 	};
     35 	if (len(path) + 1 >= len(pathbuf)) {
     36 		return ENAMETOOLONG;
     37 	};
     38 	memcpy(buf: *[*]u8, path: *[*]u8, len(path));
     39 	buf[len(path)] = 0;
     40 	return buf: *[*]u8: *const char;
     41 };
     42 
     43 // NUL terminates a string and stores it in a static buffer of PATH_MAX+1 bytes
     44 // in length.
     45 fn kpath(path: path) (*const char | errno) = {
     46 	return copy_kpath(path, pathbuf);
     47 };
     48 
     49 export fn read(fd: int, buf: *void, count: size) (size | errno) = {
     50 	return wrap_return(syscall3(SYS_read,
     51 		fd: u64, buf: uintptr: u64, count: u64))?: size;
     52 };
     53 
     54 export fn write(fd: int, buf: *const void, count: size) (size | errno) = {
     55 	return wrap_return(syscall3(SYS_write,
     56 		fd: u64, buf: uintptr: u64, count: u64))?: size;
     57 };
     58 
     59 export fn open(path: path, flags: int, mode: uint) (int | errno) = {
     60 	let path = kpath(path)?;
     61 	return wrap_return(syscall4(SYS_openat, AT_FDCWD: u64,
     62 		path: uintptr: u64, flags: u64, mode: u64))?: int;
     63 };
     64 
     65 fn openat(
     66 	dirfd: int,
     67 	path: *const char,
     68 	flags: int,
     69 	mode: uint,
     70 ) (int | errno) = wrap_return(syscall4(SYS_openat, dirfd: u64,
     71 	path: uintptr: u64, flags: u64, mode: u64))?: int;
     72 
     73 export fn openat2(
     74 	dirfd: int,
     75 	path: path,
     76 	how: *open_how,
     77 	how_sz: size,
     78 ) (int | errno) = {
     79 	let path = kpath(path)?;
     80 	return openat(dirfd, path, how.flags: int, how.mode: uint);
     81 };
     82 
     83 export fn readlinkat(
     84 	dirfd: int,
     85 	path: path,
     86 	buf: []u8,
     87 ) (size | errno) = {
     88 	let path = kpath(path)?;
     89 	return wrap_return(syscall4(SYS_readlinkat,
     90 		dirfd: u64, path: uintptr: u64,
     91 		buf: *[*]u8: uintptr: u64,
     92 		len(buf): u64))?: size;
     93 };
     94 
     95 export fn unlink(path: path) (void | errno) = {
     96 	let path = kpath(path)?;
     97 	wrap_return(syscall3(SYS_unlinkat,
     98 		AT_FDCWD: u64, path: uintptr: u64, 0u64))?;
     99 };
    100 
    101 export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = {
    102 	let path = kpath(path)?;
    103 	wrap_return(syscall3(SYS_unlinkat,
    104 		dirfd: u64, path: uintptr: u64, flags: u64))?;
    105 };
    106 
    107 export fn linkat(
    108 	olddirfd: int,
    109 	oldpath: str,
    110 	newdirfd: int,
    111 	newpath: str,
    112 	flags: int,
    113 ) (void | errno) = {
    114 	let oldpath = kpath(oldpath)?;
    115 	static let newpathbuf: [PATH_MAX + 1]u8 = [0...];
    116 	let newpath = copy_kpath(newpath, newpathbuf)?;
    117 	wrap_return(syscall5(SYS_linkat,
    118 		olddirfd: u64, oldpath: uintptr: u64,
    119 		newdirfd: u64, newpath: uintptr: u64, flags: u64))?;
    120 };
    121 
    122 export fn symlinkat(
    123 	target: str,
    124 	newdirfd: int,
    125 	linkpath: str,
    126 ) (void | errno) = {
    127 	let target = kpath(target)?;
    128 	static let linkpathbuf: [PATH_MAX + 1]u8 = [0...];
    129 	let linkpath = copy_kpath(linkpath, linkpathbuf)?;
    130 	wrap_return(syscall3(SYS_symlinkat, target: uintptr: u64,
    131 		newdirfd: u64, linkpath: uintptr: u64))?;
    132 };
    133 
    134 export fn mknodat(
    135 	dirfd: int,
    136 	path: path,
    137 	mode: mode_t,
    138 	dev: dev_t,
    139 ) (void | errno) = {
    140 	let path = kpath(path)?;
    141 	wrap_return(syscall3(SYS_mknodat,
    142 		path: uintptr: u64, mode: u64, dev: u64))?;
    143 };
    144 
    145 export fn chmod(path: path, mode: uint) (void | errno) = {
    146 	let path = kpath(path)?;
    147 	wrap_return(syscall4(SYS_fchmodat,
    148 		AT_FDCWD: u64, path: uintptr: u64, mode: u64, 0))?;
    149 };
    150 
    151 export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = {
    152 	let path = kpath(path)?;
    153 	wrap_return(syscall4(SYS_fchmodat,
    154 		dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?;
    155 };
    156 
    157 export fn chown(path: path, uid: uint, gid: uint) (void | errno) = {
    158 	let path = kpath(path)?;
    159 	wrap_return(syscall5(SYS_fchownat,
    160 		AT_FDCWD: u64, path: uintptr: u64, uid: u32, gid: u32, 0))?;
    161 };
    162 
    163 export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = {
    164 	let path = kpath(path)?;
    165 	wrap_return(syscall5(SYS_fchownat,
    166 		dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?;
    167 };
    168 
    169 export fn renameat(
    170 	olddirfd: int,
    171 	oldpath: str,
    172 	newdirfd: int,
    173 	newpath: str,
    174 	flags: uint,
    175 ) (void | errno) = {
    176 	let oldpath = kpath(oldpath)?;
    177 	static let newpathbuf: [PATH_MAX + 1]u8 = [0...];
    178 	let newpath = copy_kpath(newpath, newpathbuf)?;
    179 	wrap_return(syscall5(SYS_renameat2,
    180 		olddirfd: u64, oldpath: uintptr: u64,
    181 		newdirfd: u64, newpath: uintptr: u64,
    182 		flags: u64))?;
    183 };
    184 
    185 export fn dup(fd: int) (int | errno) = {
    186 	return wrap_return(syscall1(SYS_dup, fd: u64))?: int;
    187 };
    188 
    189 export fn dup2(oldfd: int, newfd: int) (int | errno) = {
    190 	return dup3(oldfd, newfd, 0);
    191 };
    192 
    193 export fn dup3(oldfd: int, newfd: int, flags: int) (int | errno) = {
    194 	return wrap_return(syscall3(SYS_dup3,
    195 		oldfd: u64, newfd: u64, flags: u64))?: int;
    196 };
    197 
    198 export fn close(fd: int) (void | errno) = {
    199 	wrap_return(syscall1(SYS_close, fd: u64))?;
    200 };
    201 
    202 export fn chdir(path: path) (void | errno) = {
    203 	let path = kpath(path)?;
    204 	wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?;
    205 };
    206 
    207 export fn fchdir(fd: int) (void | errno) = {
    208 	wrap_return(syscall1(SYS_fchdir, fd: u64))?;
    209 };
    210 
    211 export fn chroot(path: path) (void | errno) = {
    212 	let path = kpath(path)?;
    213 	wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?;
    214 };
    215 
    216 export fn mkdir(path: path, mode: uint) (void | errno) = {
    217 	let path = kpath(path)?;
    218 	wrap_return(syscall3(SYS_mkdirat, AT_FDCWD: u64,
    219 		path: uintptr: u64, mode: u64))?;
    220 };
    221 
    222 export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = {
    223 	let path = kpath(path)?;
    224 	wrap_return(syscall3(SYS_mkdirat,
    225 		dirfd: u64, path: uintptr: u64, mode: u64))?;
    226 };
    227 
    228 export fn execveat(dirfd: int, path: path, argv: *[*]nullable *const char,
    229 		envp: *[*]nullable *const char, flags: int) errno = {
    230 	let path = kpath(path)?;
    231 	return match (wrap_return(syscall5(SYS_execveat, dirfd: u64,
    232 		path: uintptr: u64, argv: uintptr: u64,
    233 		envp: uintptr: u64, flags: u64))) {
    234 	case let err: errno =>
    235 		yield err;
    236 	case u64 =>
    237 		abort("unreachable");
    238 	};
    239 };
    240 
    241 export fn execve(path: path, argv: *[*]nullable *const char,
    242 		envp: *[*]nullable *const char) errno = {
    243 	let path = kpath(path)?;
    244 	return match (wrap_return(syscall3(SYS_execve, path: uintptr: u64,
    245 		argv: uintptr, envp: uintptr))) {
    246 	case let err: errno =>
    247 		yield err;
    248 	case u64 =>
    249 		abort("unreachable");
    250 	};
    251 };
    252 
    253 // Returns the new PID to the parent, void to the child, or errno if something
    254 // goes wrong.
    255 export fn fork() (int | void | errno) = clone(null, SIGCHLD, null, null, 0);
    256 
    257 export fn getpid() int = syscall0(SYS_getpid): int;
    258 
    259 export fn wait4(
    260 	pid: int,
    261 	wstatus: *int,
    262 	options: int,
    263 	rusage: *rusage,
    264 ) (int | errno) = {
    265 	return wrap_return(syscall4(SYS_wait4,
    266 		pid: u64, wstatus: uintptr: u64,
    267 		options: u64, rusage: uintptr: u64))?: int;
    268 };
    269 
    270 export fn sendfile(
    271 	out: int,
    272 	in: int,
    273 	offs: nullable *size,
    274 	count: size,
    275 ) (size | errno) = wrap_return(syscall4(SYS_sendfile,
    276 	out: u64, in: u64, offs: uintptr: u64, count: u64))?: size;
    277 
    278 export @noreturn fn exit(status: int) void = {
    279 	syscall1(SYS_exit, status: u64);
    280 };
    281 
    282 export fn kill(pid: int, signal: int) (void | errno) = {
    283 	wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?;
    284 };
    285 
    286 export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = {
    287 	wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?;
    288 };
    289 
    290 export fn mmap(
    291 	addr: nullable *void,
    292 	length: size,
    293 	prot: uint,
    294 	flags: uint,
    295 	fd: int,
    296 	offs: size
    297 ) (*void | errno) = {
    298 	let r = syscall6(SYS_mmap, addr: uintptr: u64,
    299 		length: u64, prot: u64, flags: u64, fd: u64, offs: u64);
    300 	return match (wrap_return(r)) {
    301 	case let err: errno =>
    302 		return if (r: int == -EPERM
    303 				&& addr == null
    304 				&& (flags & MAP_ANON) > 0
    305 				&& (flags & MAP_FIXED) == 0) {
    306 			// Fix up incorrect EPERM from kernel:
    307 			yield wrap_errno(ENOMEM);
    308 		} else err;
    309 	case let n: u64 =>
    310 		yield n: uintptr: *void;
    311 	};
    312 };
    313 
    314 export fn munmap(addr: *void, length: size) (void | errno) = {
    315 	wrap_return(syscall2(SYS_munmap,
    316 		addr: uintptr: u64, length: u64))?;
    317 };
    318 
    319 export fn mprotect(addr: *void, length: size, prot: uint) (void | errno) = {
    320 	wrap_return(syscall3(SYS_mprotect,
    321 		addr: uintptr: u64, length: u64, prot: u64))?;
    322 };
    323 
    324 export fn lseek(fd: int, off: i64, whence: uint) (i64 | errno) = {
    325 	return wrap_return(syscall3(SYS_lseek,
    326 		fd: u64, off: u64, whence: u64))?: i64;
    327 };
    328 
    329 fn faccessat1(dirfd: int, path: *const char, mode: int) (bool | errno) = {
    330 	return match (wrap_return(syscall3(SYS_faccessat, dirfd: u64,
    331 		path: uintptr: u64, mode: u64))) {
    332 	case let err: errno =>
    333 		yield switch (err) {
    334 		case EACCES =>
    335 			yield false;
    336 		case =>
    337 			yield err;
    338 		};
    339 	case let n: u64 =>
    340 		assert(n == 0);
    341 		yield true;
    342 	};
    343 };
    344 
    345 // The use of this function is discouraged, as it can create race conditions.
    346 // TOCTOU is preferred: attempt to simply use the resource you need and handle
    347 // any access errors which occur.
    348 export fn faccessat(
    349 	dirfd: int,
    350 	path: path,
    351 	mode: int,
    352 	flags: int,
    353 ) (bool | errno) = {
    354 	let path = kpath(path)?;
    355 	match (wrap_return(syscall4(SYS_faccessat2, dirfd: u64,
    356 			path: uintptr: u64, mode: u64, flags: u64))) {
    357 	case let err: errno =>
    358 		switch (err) {
    359 		case EACCES =>
    360 			return false;
    361 		case ENOSYS =>
    362 			if (flags == 0) {
    363 				return faccessat1(dirfd, path, mode);
    364 			} else {
    365 				return err;
    366 			};
    367 		case =>
    368 			return err;
    369 		};
    370 	case let n: u64 =>
    371 		assert(n == 0);
    372 		return true;
    373 	};
    374 };
    375 
    376 export fn getdents64(dirfd: int, dirp: *void, count: size) (size | errno) = {
    377 	return wrap_return(syscall3(SYS_getdents64, dirfd: u64,
    378 		dirp: uintptr: u64, count: u64))?: size;
    379 };
    380 
    381 // The use of this function is discouraged, as it can create race conditions.
    382 // TOCTOU is preferred: attempt to simply use the resource you need and handle
    383 // any access errors which occur.
    384 export fn access(path: path, mode: int) (bool | errno) =
    385 	faccessat(AT_FDCWD, path, mode, 0);
    386 
    387 export type fcntl_arg = (void | int | *st_flock | *f_owner_ex | *u64);
    388 
    389 export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = {
    390 	let _fd = fd: u64, _cmd = cmd: u64;
    391 	return wrap_return(match (arg) {
    392 	case void =>
    393 		yield syscall2(SYS_fcntl, _fd, _cmd);
    394 	case let i: int =>
    395 		yield syscall3(SYS_fcntl, _fd, _cmd, i: u64);
    396 	case let l: *st_flock =>
    397 		yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64);
    398 	case let o: *f_owner_ex =>
    399 		yield syscall3(SYS_fcntl, _fd, _cmd, o: uintptr: u64);
    400 	case let u: *u64 =>
    401 		yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64);
    402 	})?: int;
    403 };
    404 
    405 export fn getrandom(buf: *void, bufln: size, flags: uint) (size | errno) = {
    406 	return wrap_return(syscall3(SYS_getrandom,
    407 		buf: uintptr: u64, bufln: u64, flags: u64))?: size;
    408 };
    409 
    410 export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = {
    411 	wrap_return(syscall2(SYS_clock_gettime,
    412 		clock_id: u64, tp: uintptr: u64))?;
    413 };
    414 
    415 export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = {
    416 	wrap_return(syscall2(SYS_nanosleep,
    417 		req: uintptr: u64, rem: uintptr: u64))?;
    418 };
    419 
    420 export fn uname(uts: *utsname) (void | errno) = {
    421 	wrap_return(syscall1(SYS_uname, uts: uintptr: u64))?;
    422 };
    423 
    424 // The return value is statically allocated and must be duplicated before
    425 // calling getcwd again.
    426 export fn getcwd() (*const char | errno) = {
    427 	static let pathbuf: [PATH_MAX + 1]u8 = [0...];
    428 	wrap_return(syscall2(SYS_getcwd,
    429 		&pathbuf: *[*]u8: uintptr: u64,
    430 		PATH_MAX + 1))?;
    431 	return &pathbuf: *const char;
    432 };
    433 
    434 export fn ppoll(
    435 	fds: *[*]pollfd,
    436 	nfds: nfds_t,
    437 	timeout: const nullable *timespec,
    438 	sigmask: const nullable *sigset,
    439 ) (int | errno) = {
    440 	return wrap_return(syscall4(SYS_ppoll, fds: uintptr: u64, nfds: u64,
    441 		timeout: uintptr: u64, sigmask: uintptr: u64))?: int;
    442 };
    443 
    444 export fn poll(fds: *[*]pollfd, nfds: nfds_t, timeout: int) (int | errno) = {
    445 	const ts = timespec {
    446 		tv_sec = timeout % 1000,
    447 		tv_nsec = timeout * 1000000,
    448 	};
    449 	return ppoll(fds, nfds, (if (timeout != -1) &ts else null), null);
    450 };
    451 
    452 export fn epoll_create1(flags: int) (int | errno) = {
    453 	return wrap_return(syscall1(SYS_epoll_create1, flags: u64))?: int;
    454 };
    455 
    456 export fn epoll_create(size_: int) (int | errno) = {
    457 	return epoll_create1(0);
    458 };
    459 
    460 export fn epoll_ctl(
    461 	epfd: int,
    462 	op: int,
    463 	fd: int,
    464 	event: nullable *epoll_event
    465 ) (int | errno) = {
    466 	return wrap_return(syscall4(SYS_epoll_ctl,
    467 		epfd: u64, op: u64, fd: u64, event: uintptr: u64))?: int;
    468 };
    469 
    470 export fn epoll_pwait(
    471 	epfd: int,
    472 	events: *epoll_event,
    473 	maxevents: int,
    474 	timeout: int,
    475 	sigmask: nullable *sigset
    476 ) (int | errno) = {
    477 	return wrap_return(syscall6(SYS_epoll_pwait,
    478 		epfd: u64, events: uintptr: u64,
    479 		maxevents: u64, timeout: u64,
    480 		sigmask: uintptr: u64, size(sigset): u64))?: int;
    481 };
    482 
    483 export fn epoll_wait(
    484 	epfd: int,
    485 	events: *epoll_event,
    486 	maxevents: int,
    487 	timeout: int,
    488 ) (int | errno) = {
    489 	return epoll_pwait(epfd, events, maxevents, timeout, null);
    490 };
    491 
    492 export fn timerfd_create(clock_id: int, flags: int) (int | errno) = {
    493 	return wrap_return(syscall2(SYS_timerfd_create,
    494 		clock_id: u64, flags: u64))?: int;
    495 };
    496 
    497 export fn eventfd(initval: uint, flags: int) (int | errno) = {
    498 	return wrap_return(syscall2(SYS_eventfd2,
    499 		initval: u64, flags: u64))?: int;
    500 };
    501 
    502 export fn timerfd_settime(
    503 	fd: int,
    504 	flags: int,
    505 	new_value: *const itimerspec,
    506 	old_value: nullable *itimerspec
    507 ) (int | errno) = {
    508 	return wrap_return(syscall4(SYS_timerfd_settime,
    509 		fd: u64, flags: u64,
    510 		new_value: uintptr: u64, old_value: uintptr: u64))?: int;
    511 };
    512 
    513 export fn timerfd_gettime(fd: int, curr_value: *itimerspec) (int | errno) = {
    514 	return wrap_return(syscall2(SYS_timerfd_gettime,
    515 		fd: u64, curr_value: uintptr: u64))?: int;
    516 };
    517 
    518 export fn signalfd(fd: int, mask: *const sigset, flags: int) (int | errno) = {
    519 	return wrap_return(syscall4(SYS_signalfd4,
    520 		fd: u64, mask: uintptr: u64, size(sigset): u64,
    521 		flags: u64))?: int;
    522 };
    523 
    524 export fn sigprocmask(
    525 	how: int,
    526 	set: nullable *const sigset,
    527 	old: nullable *sigset
    528 ) (int | errno) = {
    529 	return wrap_return(syscall4(SYS_rt_sigprocmask,
    530 		how: u64, set: uintptr: u64, old: uintptr: u64,
    531 		size(sigset): u64))?: int;
    532 };
    533 
    534 fn restore() void;
    535 fn restore_si() void;
    536 
    537 export fn sigaction(
    538 	signum: int,
    539 	act: *const sigact,
    540 	old: nullable *sigact
    541 ) (int | errno) = {
    542 	let real_act = *act;
    543 	real_act.sa_flags |= SA_RESTORER;
    544 	let restore_fn = if ((act.sa_flags & SA_SIGINFO) != 0) &restore_si else &restore;
    545 	real_act.sa_restorer = &restore;
    546 	return wrap_return(syscall4(SYS_rt_sigaction,
    547 		signum: u64, &real_act: uintptr: u64, old: uintptr: u64,
    548 		size(sigset): u64))?: int;
    549 };
    550 
    551 export fn socket(domain: int, type_: int, protocol: int) (int | errno) = {
    552 	return wrap_return(syscall3(SYS_socket,
    553 		domain: u64, type_: u64, protocol: u64))?: int;
    554 };
    555 
    556 export fn socketpair(
    557 	domain: int,
    558 	type_: int,
    559 	protocol: int,
    560 	sv: *[2]int
    561 ) (int | errno) = {
    562 	return wrap_return(syscall4(SYS_socketpair, domain: u64,
    563 		type_: u64, protocol: u64, sv: uintptr : u64))?: int;
    564 };
    565 
    566 export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
    567 	return wrap_return(syscall3(SYS_connect,
    568 		sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
    569 };
    570 
    571 export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
    572 	return wrap_return(syscall3(SYS_bind,
    573 		sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
    574 };
    575 
    576 export fn listen(sockfd: int, backlog: u32) (int | errno) = {
    577 	return wrap_return(syscall2(SYS_listen,
    578 		sockfd: u64, backlog: u64))?: int;
    579 };
    580 
    581 export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    582 	return wrap_return(syscall3(SYS_accept,
    583 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    584 };
    585 
    586 export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = {
    587 	return wrap_return(syscall4(SYS_accept,
    588 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int;
    589 };
    590 
    591 export fn recvfrom(sockfd: int, buf: *void, len_: size, flags: int,
    592 	src_addr: nullable *sockaddr, addrlen: nullable *u32
    593 ) (size | errno) = {
    594 	return wrap_return(syscall6(SYS_recvfrom,
    595 		sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
    596 		src_addr: uintptr: u64, addrlen: uintptr: u64))?: size;
    597 };
    598 
    599 export fn sendto(sockfd: int, buf: *void, len_: size, flags: int,
    600 	dest_addr: nullable *sockaddr, addrlen: u32
    601 ) (size | errno) = {
    602 	return wrap_return(syscall6(SYS_sendto,
    603 		sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
    604 		dest_addr: uintptr: u64, addrlen: u64))?: size;
    605 };
    606 
    607 export fn recv(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) = {
    608 	return recvfrom(sockfd, buf, len_, flags, null, null);
    609 };
    610 
    611 export fn send(sockfd: int, buf: *void, len_: size, flags: int) (size | errno) = {
    612 	return sendto(sockfd, buf, len_, flags, null, 0);
    613 };
    614 
    615 export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *void, optlen: nullable *u32) (int | errno) = {
    616 	return wrap_return(syscall5(SYS_getsockopt,
    617 		sockfd: u64, level: u64, optname: u64,
    618 		optval: uintptr: u64, optlen: uintptr: u64))?: int;
    619 };
    620 
    621 export fn setsockopt(sockfd: int, level: int, optname: int, optval: *void, optlen: u32) (int | errno) = {
    622 	return wrap_return(syscall5(SYS_setsockopt,
    623 		sockfd: u64, level: u64, optname: u64,
    624 		optval: uintptr: u64, optlen: u64))?: int;
    625 };
    626 
    627 export type ioctl_arg = (nullable *void | u64);
    628 
    629 export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = {
    630 	let fd = fd: u64, req = req: u64;
    631 	return wrap_return(match (arg) {
    632 	case let u: u64 =>
    633 		yield syscall3(SYS_ioctl, fd, req, u);
    634 	case let v: nullable *void =>
    635 		yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64);
    636 	})?: int;
    637 };
    638 
    639 export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    640 	return wrap_return(syscall3(SYS_getsockname,
    641 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    642 };
    643 
    644 export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    645 	return wrap_return(syscall3(SYS_getpeername,
    646 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    647 };
    648 
    649 export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = {
    650 	return wrap_return(syscall3(SYS_readv,
    651 		fd: u64, iov: uintptr: u64, iovcnt: u64))?: size;
    652 };
    653 
    654 export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = {
    655 	return wrap_return(syscall3(SYS_writev,
    656 		fd: u64, iov: uintptr: u64, iovcnt: u64))?: size;
    657 };
    658 
    659 export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = {
    660 	return wrap_return(syscall3(SYS_sendmsg,
    661 		fd: u64, msg: uintptr: u64, flags: u64))?: int;
    662 };
    663 
    664 export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = {
    665 	return wrap_return(syscall3(SYS_recvmsg,
    666 		fd: u64, msg: uintptr: u64, flags: u64))?: int;
    667 };
    668 
    669 export fn umask(mode: mode_t) (mode_t | errno) = {
    670 	return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t;
    671 };
    672 
    673 export fn setresuid(uid: uid_t, euid: uid_t, suid: uid_t) (void | errno) = {
    674 	wrap_return(syscall3(SYS_setresuid, uid: u64, euid: u64, suid: u64))?;
    675 };
    676 
    677 export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = {
    678 	wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?;
    679 };
    680 
    681 export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = {
    682 	wrap_return(syscall3(SYS_getresuid,
    683 		uid: uintptr: u64,
    684 		euid: uintptr: u64,
    685 		suid: uintptr: u64))?;
    686 };
    687 
    688 export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = {
    689 	wrap_return(syscall3(SYS_getresgid,
    690 		gid: uintptr: u64,
    691 		egid: uintptr: u64,
    692 		sgid: uintptr: u64))?;
    693 };
    694 
    695 export fn getpriority(which: int, who: id_t) (int | errno) = {
    696 	return wrap_return(syscall2(SYS_setpriority,
    697 		which: u64, who: u64))?: int;
    698 };
    699 
    700 export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = {
    701 	wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?;
    702 };
    703 
    704 export fn io_uring_setup(entries: u32, params: *void) (int | errno) = {
    705 	return wrap_return(syscall2(SYS_io_uring_setup,
    706 		entries: u64, params: uintptr: u64))?: int;
    707 };
    708 
    709 export fn io_uring_register(
    710 	fd: int,
    711 	opcode: uint,
    712 	arg: nullable *void,
    713 	nr_args: uint,
    714 ) (int | errno) = wrap_return(syscall4(SYS_io_uring_register,
    715 	fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?: int;
    716 
    717 export fn io_uring_enter(
    718 	fd: int,
    719 	to_submit: uint,
    720 	min_complete: uint,
    721 	flags: uint,
    722 	sig: const nullable *sigset,
    723 ) (uint | errno) = {
    724 	return wrap_return(syscall5(SYS_io_uring_enter,
    725 		fd: u64, to_submit: u64, min_complete: u64,
    726 		flags: u64, sig: uintptr: u64))?: uint;
    727 };
    728 
    729 export fn mlock2(addr: *void, length: size, flags: uint) (void | errno) = {
    730 	return wrap_return(syscall3(SYS_mlock2, addr: uintptr: u64,
    731 		length: u64, flags: u64))?: void;
    732 };
    733 
    734 export fn munlock(addr: *void, length: size) (void | errno) = {
    735 	return wrap_return(syscall2(SYS_munlock, addr: uintptr: u64,
    736 		length: u64))?: void;
    737 };
    738 
    739 export fn mlockall(flags: uint) (void | errno) = {
    740 	return wrap_return(syscall1(SYS_mlockall, flags: u64))?: void;
    741 };
    742 
    743 export fn munlockall() (void | errno) = {
    744 	return wrap_return(syscall0(SYS_munlockall))?: void;
    745 };
    746 
    747 export fn prctl(
    748 	option: int,
    749 	arg2: u64,
    750 	arg3: u64,
    751 	arg4: u64,
    752 	arg5: u64,
    753 ) (int | errno) = {
    754 	return wrap_return(syscall5(SYS_prctl, option: u64, arg2, arg3, arg4,
    755 		arg5))?: int;
    756 };
    757 
    758 export fn add_key(
    759 	keytype: *const char,
    760 	name: *const char,
    761 	payload: *void,
    762 	plen: size,
    763 	keyring: int,
    764 ) (int | errno) = {
    765 	return wrap_return(syscall5(SYS_add_key,
    766 		keytype: uintptr: u64, name: uintptr: u64,
    767 		payload: uintptr: u64, plen: u64,
    768 		keyring: u64))?: int;
    769 };
    770 
    771 export fn keyctl(
    772 	operation: int,
    773 	arg2: u64,
    774 	arg3: u64,
    775 	arg4: u64,
    776 	arg5: u64,
    777 ) (int | errno) = {
    778 	return wrap_return(syscall5(SYS_keyctl, operation: u64,
    779 		arg2, arg3, arg4, arg5))?: int;
    780 };
    781 
    782 export fn getsid(pid: int) (int | errno) = {
    783 	return wrap_return(syscall1(SYS_getsid, pid: u64))?: int;
    784 };
    785 
    786 export fn setsid() (void | errno) = {
    787 	return wrap_return(syscall0(SYS_setsid))?: void;
    788 };
    789 
    790 export fn mount(
    791 	source: *const char,
    792 	target: *const char,
    793 	filesystemtype: *const char,
    794 	mountflags: u64,
    795 	data: nullable *void
    796 ) (void | errno) = {
    797 	wrap_return(syscall5(SYS_mount, source: uintptr, target: uintptr,
    798 		filesystemtype: uintptr, mountflags: u64, data: uintptr))?;
    799 };
    800 
    801 export fn umount2(target: *const char, flags: int) (void | errno) = {
    802 	wrap_return(syscall2(SYS_umount2, target: uintptr, flags: u64))?;
    803 };
    804 
    805 export fn ptrace(
    806 	request: int,
    807 	pid: int,
    808 	addr: uintptr,
    809 	data: uintptr,
    810 ) (u64 | errno) = {
    811 	// PTRACE_PEEK* requests write into *data instead of just returing
    812 	// the word that they read
    813 	let result = 0u64;
    814 	const wrdata = request >= PTRACE_PEEKTEXT && request <= PTRACE_PEEKUSER;
    815 	if (wrdata) {
    816 		data = &result: uintptr;
    817 	};
    818 	const ret = wrap_return(syscall4(SYS_ptrace, request: u64, pid: u64,
    819 		addr, data))?: u64;
    820 	if (wrdata) {
    821 		return result;
    822 	} else {
    823 		return ret;
    824 	};
    825 };