hare

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

syscalls.ha (28864B)


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