hare

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

syscalls.ha (28252B)


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