hare

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

syscalls.ha (26791B)


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