hare

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

syscalls.ha (30436B)


      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 clock_settime(clock_id: int, tp: *const timespec) (void | errno) = {
    483 	wrap_return(syscall2(SYS_clock_settime,
    484 		clock_id: u64, tp: uintptr: u64))?;
    485 };
    486 
    487 export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = {
    488 	wrap_return(syscall2(SYS_nanosleep,
    489 		req: uintptr: u64, rem: uintptr: u64))?;
    490 };
    491 
    492 export fn uname(uts: *utsname) (void | errno) = {
    493 	wrap_return(syscall1(SYS_uname, uts: uintptr: u64))?;
    494 };
    495 
    496 // The return value is statically allocated and must be duplicated before
    497 // calling getcwd again.
    498 export fn getcwd() (*const u8 | errno) = {
    499 	static let pathbuf: [PATH_MAX]u8 = [0...];
    500 	wrap_return(syscall2(SYS_getcwd,
    501 		&pathbuf: *[*]u8: uintptr: u64,
    502 		PATH_MAX))?;
    503 	return &pathbuf: *const u8;
    504 };
    505 
    506 export fn ppoll(
    507 	fds: *[*]pollfd,
    508 	nfds: nfds_t,
    509 	timeout: const nullable *timespec,
    510 	sigmask: const nullable *sigset,
    511 ) (int | errno) = {
    512 	return wrap_return(syscall4(SYS_ppoll, fds: uintptr: u64, nfds: u64,
    513 		timeout: uintptr: u64, sigmask: uintptr: u64))?: int;
    514 };
    515 
    516 export fn poll(fds: *[*]pollfd, nfds: nfds_t, timeout: int) (int | errno) = {
    517 	const ts = timespec {
    518 		tv_sec = timeout % 1000,
    519 		tv_nsec = timeout * 1000000,
    520 	};
    521 	return ppoll(fds, nfds, (if (timeout != -1) &ts else null), null);
    522 };
    523 
    524 export fn epoll_create1(flags: int) (int | errno) = {
    525 	return wrap_return(syscall1(SYS_epoll_create1, flags: u64))?: int;
    526 };
    527 
    528 export fn epoll_create(size_: int) (int | errno) = {
    529 	return epoll_create1(0);
    530 };
    531 
    532 export fn epoll_ctl(
    533 	epfd: int,
    534 	op: int,
    535 	fd: int,
    536 	event: nullable *epoll_event
    537 ) (void | errno) = {
    538 	wrap_return(syscall4(SYS_epoll_ctl,
    539 		epfd: u64, op: u64, fd: u64, event: uintptr: u64))?;
    540 };
    541 
    542 export fn epoll_pwait(
    543 	epfd: int,
    544 	events: *epoll_event,
    545 	maxevents: int,
    546 	timeout: int,
    547 	sigmask: nullable *sigset
    548 ) (int | errno) = {
    549 	return wrap_return(syscall6(SYS_epoll_pwait,
    550 		epfd: u64, events: uintptr: u64,
    551 		maxevents: u64, timeout: u64,
    552 		sigmask: uintptr: u64, size(sigset): u64))?: int;
    553 };
    554 
    555 export fn epoll_wait(
    556 	epfd: int,
    557 	events: *epoll_event,
    558 	maxevents: int,
    559 	timeout: int,
    560 ) (int | errno) = {
    561 	return epoll_pwait(epfd, events, maxevents, timeout, null);
    562 };
    563 
    564 export fn timerfd_create(clock_id: int, flags: int) (int | errno) = {
    565 	return wrap_return(syscall2(SYS_timerfd_create,
    566 		clock_id: u64, flags: u64))?: int;
    567 };
    568 
    569 export fn eventfd(initval: uint, flags: int) (int | errno) = {
    570 	return wrap_return(syscall2(SYS_eventfd2,
    571 		initval: u64, flags: u64))?: int;
    572 };
    573 
    574 export fn timerfd_settime(
    575 	fd: int,
    576 	flags: int,
    577 	new_value: *const itimerspec,
    578 	old_value: nullable *itimerspec
    579 ) (int | errno) = {
    580 	return wrap_return(syscall4(SYS_timerfd_settime,
    581 		fd: u64, flags: u64,
    582 		new_value: uintptr: u64, old_value: uintptr: u64))?: int;
    583 };
    584 
    585 export fn timerfd_gettime(fd: int, curr_value: *itimerspec) (int | errno) = {
    586 	return wrap_return(syscall2(SYS_timerfd_gettime,
    587 		fd: u64, curr_value: uintptr: u64))?: int;
    588 };
    589 
    590 export fn signalfd(fd: int, mask: *const sigset, flags: int) (int | errno) = {
    591 	return wrap_return(syscall4(SYS_signalfd4,
    592 		fd: u64, mask: uintptr: u64, size(sigset): u64,
    593 		flags: u64))?: int;
    594 };
    595 
    596 export fn sigprocmask(
    597 	how: int,
    598 	set: nullable *const sigset,
    599 	old: nullable *sigset
    600 ) (int | errno) = {
    601 	return wrap_return(syscall4(SYS_rt_sigprocmask,
    602 		how: u64, set: uintptr: u64, old: uintptr: u64,
    603 		size(sigset): u64))?: int;
    604 };
    605 
    606 fn restore() void;
    607 fn restore_si() void;
    608 
    609 export fn sigaction(
    610 	signum: int,
    611 	act: *const sigact,
    612 	old: nullable *sigact
    613 ) (int | errno) = {
    614 	let real_act = *act;
    615 	real_act.sa_flags |= SA_RESTORER;
    616 	let restore_fn = if ((act.sa_flags & SA_SIGINFO) != 0) &restore_si else &restore;
    617 	real_act.sa_restorer = &restore;
    618 	return wrap_return(syscall4(SYS_rt_sigaction,
    619 		signum: u64, &real_act: uintptr: u64, old: uintptr: u64,
    620 		size(sigset): u64))?: int;
    621 };
    622 
    623 export fn sigaltstack(
    624 	ss: nullable *stack_t,
    625 	old_ss: nullable *stack_t,
    626 ) (void | errno) = {
    627 	wrap_return(syscall2(SYS_sigaltstack,
    628 		ss: uintptr: u64, old_ss: uintptr: u64))?;
    629 };
    630 
    631 export fn socket(domain: int, type_: int, protocol: int) (int | errno) = {
    632 	return wrap_return(syscall3(SYS_socket,
    633 		domain: u64, type_: u64, protocol: u64))?: int;
    634 };
    635 
    636 export fn socketpair(
    637 	domain: int,
    638 	type_: int,
    639 	protocol: int,
    640 	sv: *[2]int
    641 ) (int | errno) = {
    642 	return wrap_return(syscall4(SYS_socketpair, domain: u64,
    643 		type_: u64, protocol: u64, sv: uintptr : u64))?: int;
    644 };
    645 
    646 export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
    647 	return wrap_return(syscall3(SYS_connect,
    648 		sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
    649 };
    650 
    651 export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
    652 	return wrap_return(syscall3(SYS_bind,
    653 		sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
    654 };
    655 
    656 export fn listen(sockfd: int, backlog: u32) (int | errno) = {
    657 	return wrap_return(syscall2(SYS_listen,
    658 		sockfd: u64, backlog: u64))?: int;
    659 };
    660 
    661 export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    662 	return wrap_return(syscall3(SYS_accept,
    663 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    664 };
    665 
    666 export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = {
    667 	return wrap_return(syscall4(SYS_accept4,
    668 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int;
    669 };
    670 
    671 export fn recvfrom(sockfd: int, buf: *opaque, len_: size, flags: int,
    672 	src_addr: nullable *sockaddr, addrlen: nullable *u32
    673 ) (size | errno) = {
    674 	return wrap_return(syscall6(SYS_recvfrom,
    675 		sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
    676 		src_addr: uintptr: u64, addrlen: uintptr: u64))?: size;
    677 };
    678 
    679 export fn sendto(sockfd: int, buf: *opaque, len_: size, flags: int,
    680 	dest_addr: nullable *sockaddr, addrlen: u32
    681 ) (size | errno) = {
    682 	return wrap_return(syscall6(SYS_sendto,
    683 		sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
    684 		dest_addr: uintptr: u64, addrlen: u64))?: size;
    685 };
    686 
    687 export fn recv(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = {
    688 	return recvfrom(sockfd, buf, len_, flags, null, null);
    689 };
    690 
    691 export fn send(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = {
    692 	return sendto(sockfd, buf, len_, flags, null, 0);
    693 };
    694 
    695 export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *opaque, optlen: nullable *u32) (int | errno) = {
    696 	return wrap_return(syscall5(SYS_getsockopt,
    697 		sockfd: u64, level: u64, optname: u64,
    698 		optval: uintptr: u64, optlen: uintptr: u64))?: int;
    699 };
    700 
    701 export fn setsockopt(sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32) (int | errno) = {
    702 	return wrap_return(syscall5(SYS_setsockopt,
    703 		sockfd: u64, level: u64, optname: u64,
    704 		optval: uintptr: u64, optlen: u64))?: int;
    705 };
    706 
    707 export type ioctl_arg = (nullable *opaque | u64);
    708 
    709 export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = {
    710 	let fd = fd: u64, req = req: u64;
    711 	return wrap_return(match (arg) {
    712 	case let u: u64 =>
    713 		yield syscall3(SYS_ioctl, fd, req, u);
    714 	case let v: nullable *opaque =>
    715 		yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64);
    716 	})?: int;
    717 };
    718 
    719 export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    720 	return wrap_return(syscall3(SYS_getsockname,
    721 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    722 };
    723 
    724 export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    725 	return wrap_return(syscall3(SYS_getpeername,
    726 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    727 };
    728 
    729 export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = {
    730 	return wrap_return(syscall3(SYS_readv,
    731 		fd: u64, iov: uintptr: u64, iovcnt: u64))?: size;
    732 };
    733 
    734 export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = {
    735 	return wrap_return(syscall3(SYS_writev,
    736 		fd: u64, iov: uintptr: u64, iovcnt: u64))?: size;
    737 };
    738 
    739 export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = {
    740 	return wrap_return(syscall3(SYS_sendmsg,
    741 		fd: u64, msg: uintptr: u64, flags: u64))?: int;
    742 };
    743 
    744 export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = {
    745 	return wrap_return(syscall3(SYS_recvmsg,
    746 		fd: u64, msg: uintptr: u64, flags: u64))?: int;
    747 };
    748 
    749 export fn umask(mode: mode_t) (mode_t | errno) = {
    750 	return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t;
    751 };
    752 
    753 export fn setresuid(uid: uid_t, euid: uid_t, suid: uid_t) (void | errno) = {
    754 	wrap_return(syscall3(SYS_setresuid, uid: u64, euid: u64, suid: u64))?;
    755 };
    756 
    757 export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = {
    758 	wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?;
    759 };
    760 
    761 export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = {
    762 	wrap_return(syscall3(SYS_getresuid,
    763 		uid: uintptr: u64,
    764 		euid: uintptr: u64,
    765 		suid: uintptr: u64))?;
    766 };
    767 
    768 export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = {
    769 	wrap_return(syscall3(SYS_getresgid,
    770 		gid: uintptr: u64,
    771 		egid: uintptr: u64,
    772 		sgid: uintptr: u64))?;
    773 };
    774 
    775 export fn getgroups(gids: []gid_t) (uint | errno) = {
    776 	return wrap_return(syscall2(SYS_getgroups,
    777 		len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint;
    778 };
    779 
    780 export fn setgroups(gids: []gid_t) (void | errno) = {
    781 	wrap_return(syscall2(SYS_setgroups,
    782 		len(gids): u64, gids: *[*]gid_t: uintptr: u64))?;
    783 };
    784 
    785 export fn getpriority(which: int, who: id_t) (int | errno) = {
    786 	return wrap_return(syscall2(SYS_setpriority,
    787 		which: u64, who: u64))?: int;
    788 };
    789 
    790 export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = {
    791 	wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?;
    792 };
    793 
    794 export fn io_uring_setup(entries: u32, params: *io_uring_params) (int | errno) = {
    795 	return wrap_return(syscall2(SYS_io_uring_setup,
    796 		entries: u64, params: uintptr: u64))?: int;
    797 };
    798 
    799 export fn io_uring_register(
    800 	fd: int,
    801 	opcode: uint,
    802 	arg: nullable *opaque,
    803 	nr_args: uint,
    804 ) (int | errno) = wrap_return(syscall4(SYS_io_uring_register,
    805 	fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?: int;
    806 
    807 export fn io_uring_enter(
    808 	fd: int,
    809 	to_submit: uint,
    810 	min_complete: uint,
    811 	flags: uint,
    812 	sig: const nullable *sigset,
    813 ) (uint | errno) = {
    814 	return wrap_return(syscall5(SYS_io_uring_enter,
    815 		fd: u64, to_submit: u64, min_complete: u64,
    816 		flags: u64, sig: uintptr: u64))?: uint;
    817 };
    818 
    819 export fn io_uring_enter2(
    820 	fd: int,
    821 	to_submit: uint,
    822 	min_complete: uint,
    823 	flags: uint,
    824 	arg: const nullable *opaque,
    825 	argsz: size,
    826 ) (uint | errno) = {
    827 	return wrap_return(syscall6(SYS_io_uring_enter,
    828 		fd: u64, to_submit: u64, min_complete: u64,
    829 		flags: u64, arg: uintptr: u64, argsz: u64))?: uint;
    830 };
    831 
    832 export fn mlock2(addr: *opaque, length: size, flags: uint) (void | errno) = {
    833 	return wrap_return(syscall3(SYS_mlock2, addr: uintptr: u64,
    834 		length: u64, flags: u64))?: void;
    835 };
    836 
    837 export fn munlock(addr: *opaque, length: size) (void | errno) = {
    838 	return wrap_return(syscall2(SYS_munlock, addr: uintptr: u64,
    839 		length: u64))?: void;
    840 };
    841 
    842 export fn mlockall(flags: uint) (void | errno) = {
    843 	return wrap_return(syscall1(SYS_mlockall, flags: u64))?: void;
    844 };
    845 
    846 export fn munlockall() (void | errno) = {
    847 	return wrap_return(syscall0(SYS_munlockall))?: void;
    848 };
    849 
    850 export fn prctl(
    851 	option: int,
    852 	arg2: u64,
    853 	arg3: u64,
    854 	arg4: u64,
    855 	arg5: u64,
    856 ) (int | errno) = {
    857 	return wrap_return(syscall5(SYS_prctl, option: u64, arg2, arg3, arg4,
    858 		arg5))?: int;
    859 };
    860 
    861 export fn add_key(
    862 	keytype: *const u8,
    863 	name: *const u8,
    864 	payload: *opaque,
    865 	plen: size,
    866 	keyring: int,
    867 ) (int | errno) = {
    868 	return wrap_return(syscall5(SYS_add_key,
    869 		keytype: uintptr: u64, name: uintptr: u64,
    870 		payload: uintptr: u64, plen: u64,
    871 		keyring: u64))?: int;
    872 };
    873 
    874 export fn keyctl(
    875 	operation: int,
    876 	arg2: u64,
    877 	arg3: u64,
    878 	arg4: u64,
    879 	arg5: u64,
    880 ) (int | errno) = {
    881 	return wrap_return(syscall5(SYS_keyctl, operation: u64,
    882 		arg2, arg3, arg4, arg5))?: int;
    883 };
    884 
    885 export fn getsid(pid: pid_t) (pid_t | errno) = {
    886 	return wrap_return(syscall1(SYS_getsid, pid: u64))?: pid_t;
    887 };
    888 
    889 export fn setsid() (void | errno) = {
    890 	return wrap_return(syscall0(SYS_setsid))?: void;
    891 };
    892 
    893 export fn mount(
    894 	source: path,
    895 	target: path,
    896 	filesystemtype: *const u8,
    897 	mountflags: u64,
    898 	data: nullable *opaque
    899 ) (void | errno) = {
    900 	let source = kpath(source)?;
    901 	let target = kpath(target)?;
    902 	wrap_return(syscall5(SYS_mount, source: uintptr, target: uintptr,
    903 		filesystemtype: uintptr, mountflags: u64, data: uintptr))?;
    904 };
    905 
    906 export fn umount2(target: path, flags: int) (void | errno) = {
    907 	let target = kpath(target)?;
    908 	wrap_return(syscall2(SYS_umount2, target: uintptr, flags: u64))?;
    909 };
    910 
    911 export fn ptrace(
    912 	request: int,
    913 	pid: pid_t,
    914 	addr: uintptr,
    915 	data: uintptr,
    916 ) (u64 | errno) = {
    917 	// PTRACE_PEEK* requests write into *data instead of just returning
    918 	// the word that they read
    919 	let result = 0u64;
    920 	const wrdata = request >= PTRACE_PEEKTEXT && request <= PTRACE_PEEKUSER;
    921 	if (wrdata) {
    922 		data = &result: uintptr;
    923 	};
    924 	const ret = wrap_return(syscall4(SYS_ptrace, request: u64, pid: u64,
    925 		addr, data))?: u64;
    926 	if (wrdata) {
    927 		return result;
    928 	} else {
    929 		return ret;
    930 	};
    931 };
    932 
    933 
    934 export fn sync() void = {
    935 	wrap_return(syscall0(SYS_sync))!;
    936 };
    937 
    938 export fn memfd_create(name: path, flags: uint) (int | errno) = {
    939 	let path = kpath(name)?;
    940 	return wrap_return(syscall2(SYS_memfd_create,
    941 		path: uintptr: u64, flags: u64))?: int;
    942 };
    943 
    944 export fn splice(
    945 	fd_in: int,
    946 	off_in: nullable *u64,
    947 	fd_out: int,
    948 	off_out: nullable *u64,
    949 	ln: size,
    950 	flags: uint,
    951 ) (size | errno) = {
    952 	return wrap_return(syscall6(SYS_splice,
    953 		fd_in: u64, off_in: uintptr: u64,
    954 		fd_out: u64, off_out: uintptr: u64,
    955 		ln: u64, flags: u64))?: size;
    956 };
    957 
    958 export fn tee(fd_in: int, fd_out: int, ln: size, flags: uint) (size | errno) = {
    959 	return wrap_return(syscall4(SYS_tee,
    960 		fd_in: u64, fd_out: u64,
    961 		ln: u64, flags: u64))?: size;
    962 };
    963 
    964 export fn fallocate(fd: int, mode: int, off: i64, ln: i64) (void | errno) = {
    965 	wrap_return(syscall4(SYS_fallocate,
    966 		fd: u64, mode: u64, off: u64, ln: u64))?;
    967 };
    968 
    969 export fn posix_fallocate(fd: int, off: i64, ln: i64) (void | errno) = {
    970 	fallocate(fd, 0, off, ln)?;
    971 };
    972 
    973 export fn flock(fd: int, op: int) (void | errno) = {
    974 	wrap_return(syscall2(SYS_flock,
    975 		fd: u64, op: u64))?;
    976 };
    977 
    978 export def NAME_MAX: size = 255z;
    979 export def INOTIFY_EVENT_MAX_SIZE: size = size(int) + size(u32)*3 + NAME_MAX + 1z;
    980 
    981 export fn inotify_init() (int | errno) = {
    982 	return wrap_return(syscall1(SYS_inotify_init1, 0))?: int;
    983 };
    984 
    985 export fn inotify_init1(flags: int) (int | errno) = {
    986 	return wrap_return(syscall1(SYS_inotify_init1, flags: u64))?: int;
    987 };
    988 
    989 export fn inotify_add_watch(fd: int, path: path, mask: u32) (int | errno) = {
    990 	let path = kpath(path)?;
    991 	return wrap_return(syscall3(SYS_inotify_add_watch,
    992 		fd: u64, path: uintptr: u64, mask))?: int;
    993 };
    994 
    995 export fn inotify_rm_watch(fd: int, wd: int) (int | errno) = {
    996 	return wrap_return(syscall2(SYS_inotify_rm_watch,
    997 		fd: u64, wd: u64))?: int;
    998 };
    999 
   1000 export type inotify_event = struct {
   1001 	wd: int,
   1002 	mask: u32,
   1003 	cookie: u32,
   1004 	length: u32,
   1005 	name: [*]u8,
   1006 };
   1007 
   1008 export fn shmat(id: int, addr: *const opaque, flag: int) *opaque = {
   1009 	return syscall3(SYS_shmat, id: u64, addr: uintptr: u64,
   1010 		flag: u64): uintptr: *opaque;
   1011 };
   1012 
   1013 export fn sched_getaffinity(
   1014 	pid: pid_t,
   1015 	cpusetsize: size,
   1016 	mask: *cpu_set,
   1017 ) (void | errno) = {
   1018 	wrap_return(syscall3(SYS_sched_getaffinity,
   1019 		pid: u64, cpusetsize: u64, mask: uintptr: u64))?;
   1020 };
   1021 
   1022 export fn sched_setaffinity(
   1023 	pid: pid_t,
   1024 	cpusetsize: size,
   1025 	mask: *const cpu_set,
   1026 ) (void | errno) = {
   1027 	wrap_return(syscall3(SYS_sched_setaffinity,
   1028 		pid: u64, cpusetsize: u64, mask: uintptr: u64))?;
   1029 };
   1030 
   1031 export fn getrlimit(resource: int, rlim: *rlimit) (void | errno) = {
   1032 	wrap_return(syscall2(SYS_getrlimit,
   1033 		resource: u64, rlim: uintptr: u64))?;
   1034 };
   1035 
   1036 export fn setrlimit(resource: int, rlim: *const rlimit) (void | errno) = {
   1037 	wrap_return(syscall2(SYS_setrlimit,
   1038 		resource: u64, rlim: uintptr: u64))?;
   1039 };
   1040 
   1041 export fn shutdown(sockfd: int, how: int) (void | errno) = {
   1042 	wrap_return(syscall2(SYS_shutdown,
   1043 		sockfd: u64, how: u64))?;
   1044 };
   1045 
   1046 // Sets an extended file attribute.
   1047 export fn setxattr(
   1048 	path: path,
   1049 	name: str,
   1050 	value: []u8,
   1051 	flags: int = 0
   1052 ) (void | errno) = {
   1053 	let path = kpath(path)?;
   1054 	static let namebuf: [PATH_MAX]u8 = [0...];
   1055 	let name = copy_kpath(name, namebuf)?;
   1056 
   1057 	wrap_return(syscall5(SYS_setxattr,
   1058 		path: uintptr: u64,
   1059 		name: uintptr: u64,
   1060 		value: *[*]u8: uintptr: u64,
   1061 		len(value): u64,
   1062 		flags: u64
   1063 	))?;
   1064 };
   1065 
   1066 // Gets an extended file attribute.
   1067 export fn getxattr(path: path, name: str, value: []u8) (u64 | errno) = {
   1068 	let path = kpath(path)?;
   1069 	static let namebuf: [PATH_MAX]u8 = [0...];
   1070 	let name = copy_kpath(name, namebuf)?;
   1071 
   1072 	return wrap_return(syscall4(SYS_getxattr,
   1073 		path: uintptr,
   1074 		name: uintptr,
   1075 		value: *[*]u8: uintptr: u64,
   1076 		len(value): u64,
   1077 	));
   1078 };
   1079 
   1080 // Removes an extended file attribute.
   1081 export fn removexattr(path: path, name: str) (void | errno) = {
   1082 	let path = kpath(path)?;
   1083 	static let namebuf: [PATH_MAX]u8 = [0...];
   1084 	let name = copy_kpath(name, namebuf)?;
   1085 
   1086 	wrap_return(syscall2(SYS_removexattr, path: uintptr, name: uintptr))?;
   1087 };
   1088 
   1089 export fn fsync(fd: int) (void | errno) = {
   1090 	wrap_return(syscall1(SYS_fsync, fd: u64))?;
   1091 };
   1092 
   1093 export fn fdatasync(fd: int) (void | errno) = {
   1094 	wrap_return(syscall1(SYS_fdatasync, fd: u64))?;
   1095 };
   1096 
   1097 export fn sigqueueinfo(tgid: pid_t, sig: int, info: *siginfo) (void | errno) = {
   1098 	wrap_return(syscall3(SYS_rt_sigqueueinfo, tgid: u64,
   1099 		sig: u64, info: uintptr: u64))?;
   1100 };