hare

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

syscalls.ha (19939B)


      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 NAME_MAX: size = 255z;
     26 export def PATH_MAX: size = 1024z;
     27 export type path = (str | []u8 | *const u8);
     28 let pathbuf: [PATH_MAX]u8 = [0...];
     29 
     30 fn copy_kpath(path: path, buf: []u8) (*const u8 | errno) = {
     31 	let path = match (path) {
     32 	case let c: *const u8 =>
     33 		return c;
     34 	case let s: str =>
     35 		let ptr = &s: *struct {
     36 			buf: *[*]u8,
     37 			length: size,
     38 			capacity: size,
     39 		};
     40 		yield ptr.buf[..ptr.length];
     41 	case let b: []u8 =>
     42 		yield b;
     43 	};
     44 	if (len(path) + 1 >= len(pathbuf)) {
     45 		return ENAMETOOLONG;
     46 	};
     47 	memcpy(buf: *[*]u8, path: *[*]u8, len(path));
     48 	buf[len(path)] = 0;
     49 	return buf: *[*]u8: *const u8;
     50 };
     51 
     52 // NUL terminates a string and stores it in a static buffer of PATH_MAX bytes in
     53 // length.
     54 fn kpath(path: path) (*const u8 | errno) = {
     55 	return copy_kpath(path, pathbuf);
     56 };
     57 
     58 export fn read(fd: int, buf: *opaque, count: size) (size | errno) = {
     59 	return wrap_return(syscall3(SYS_read,
     60 		fd: u64, buf: uintptr: u64, count: u64))?: size;
     61 };
     62 
     63 export fn write(fd: int, buf: *const opaque, count: size) (size | errno) = {
     64 	return wrap_return(syscall3(SYS_write,
     65 		fd: u64, buf: uintptr: u64, count: u64))?: size;
     66 };
     67 
     68 export fn readv(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = {
     69 	return wrap_return(syscall3(SYS_readv,
     70 		fd: u64, iov: uintptr: u64, iovcnt: u64))?: size;
     71 };
     72 
     73 export fn writev(fd: int, iov: const *[*]iovec, iovcnt: int) (size | errno) = {
     74 	return wrap_return(syscall3(SYS_writev,
     75 		fd: u64, iov: uintptr: u64, iovcnt: u64))?: size;
     76 };
     77 
     78 export fn close(fd: int) (void | errno) = {
     79 	wrap_return(syscall1(SYS_close, fd: u64))?;
     80 };
     81 
     82 export fn lseek(fd: int, off: i64, whence: int) (i64 | errno) = {
     83 	return wrap_return(syscall3(SYS_lseek,
     84 		fd: u64, off: u64, whence: u64))?: i64;
     85 };
     86 
     87 export fn ftruncate(fd: int, ln: off_t) (void | errno) = {
     88 	wrap_return(syscall2(SYS_ftruncate, fd: u64, ln: u32))?;
     89 };
     90 
     91 export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = {
     92 	wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?;
     93 };
     94 
     95 export type ioctl_arg = (nullable *opaque | u64);
     96 
     97 export fn ioctl(fd: int, req: u64, arg: ioctl_arg) (int | errno) = {
     98 	let fd = fd: u64, req = req: u64;
     99 	return wrap_return(match (arg) {
    100 	case let u: u64 =>
    101 		yield syscall3(SYS_ioctl, fd, req, u);
    102 	case let v: nullable *opaque =>
    103 		yield syscall3(SYS_ioctl, fd, req, v: uintptr: u64);
    104 	})?: int;
    105 };
    106 
    107 export fn openat(
    108 	dirfd: int,
    109 	path: path,
    110 	flags: int,
    111 	mode: uint,
    112 ) (int | errno) = {
    113 	let path = kpath(path)?;
    114 	return wrap_return(syscall4(SYS_openat, dirfd: u64,
    115 		path: uintptr: u64, flags: u64, mode: u64))?: int;
    116 };
    117 
    118 export fn open(path: str, flags: int, mode: uint) (int | errno) = {
    119 	return openat(AT_FDCWD, path, flags, mode);
    120 };
    121 
    122 export fn unlink(path: path) (void | errno) = {
    123 	let path = kpath(path)?;
    124 	wrap_return(syscall3(SYS_unlinkat,
    125 		AT_FDCWD: u64, path: uintptr: u64, 0u64))?;
    126 };
    127 
    128 export fn renameat(
    129 	olddirfd: int,
    130 	oldpath: str,
    131 	newdirfd: int,
    132 	newpath: str,
    133 ) (void | errno) = {
    134 	let oldpath = kpath(oldpath)?;
    135 	static let newpathbuf: [PATH_MAX]u8 = [0...];
    136 	let newpath = copy_kpath(newpath, newpathbuf)?;
    137 	wrap_return(syscall4(SYS_renameat,
    138 		olddirfd: u64, oldpath: uintptr: u64,
    139 		newdirfd: u64, newpath: uintptr: u64))?;
    140 };
    141 
    142 export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = {
    143 	let path = kpath(path)?;
    144 	wrap_return(syscall3(SYS_unlinkat,
    145 		dirfd: u64, path: uintptr: u64, flags: u64))?;
    146 };
    147 
    148 export fn fstatat(fd: int, path: path, stat: *st, flag: int) (void | errno) = {
    149 	let path = kpath(path)?;
    150 	let fbstat = freebsd11_stat { ... };
    151 	wrap_return(syscall4(SYS_freebsd11_fstatat, fd: u64,
    152 		path: uintptr: u64, &fbstat: uintptr: u64, flag: u64))?;
    153 	stat.dev = fbstat.st_dev;
    154 	stat.ino = fbstat.st_ino;
    155 	stat.mode = fbstat.st_mode;
    156 	stat.nlink = fbstat.st_nlink;
    157 	stat.uid = fbstat.st_uid;
    158 	stat.gid = fbstat.st_gid;
    159 	stat.rdev = fbstat.st_rdev;
    160 	stat.atime.tv_sec = fbstat.st_atim.tv_sec;
    161 	stat.atime.tv_nsec = fbstat.st_atim.tv_nsec: i64;
    162 	stat.mtime.tv_sec = fbstat.st_mtim.tv_sec;
    163 	stat.mtime.tv_nsec = fbstat.st_mtim.tv_nsec: i64;
    164 	stat.ctime.tv_sec = fbstat.st_ctim.tv_sec;
    165 	stat.ctime.tv_nsec = fbstat.st_ctim.tv_nsec: i64;
    166 	stat.btime.tv_sec = fbstat.st_birthtim.tv_sec;
    167 	stat.btime.tv_nsec = fbstat.st_birthtim.tv_nsec: i64;
    168 	stat.sz = fbstat.st_size;
    169 	stat.blocks = fbstat.st_blocks;
    170 	stat.blksz = fbstat.st_blksize;
    171 	stat.flags = fbstat.st_flags;
    172 };
    173 
    174 export fn fstat(fd: int, stat: *st) (errno | void) =
    175 	fstatat(fd, "", stat, AT_EMPTY_PATH);
    176 
    177 export fn readlinkat(
    178 	dirfd: int,
    179 	path: path,
    180 	buf: []u8,
    181 ) (size | errno) = {
    182 	let path = kpath(path)?;
    183 	return wrap_return(syscall4(SYS_readlinkat,
    184 		dirfd: u64, path: uintptr: u64,
    185 		buf: *[*]u8: uintptr: u64,
    186 		len(buf): u64))?: size;
    187 };
    188 
    189 export fn mkdirat(dirfd: int, path: path, mode: uint) (void | errno) = {
    190 	let path = kpath(path)?;
    191 	wrap_return(syscall3(SYS_mkdirat,
    192 		dirfd: u64, path: uintptr: u64, mode: u64))?;
    193 };
    194 
    195 
    196 export fn fchmod(fd: int, mode: uint) (void | errno) = {
    197 	wrap_return(syscall2(SYS_fchmod,
    198 		fd: u64, mode: u64))?;
    199 };
    200 
    201 export fn fchmodat(dirfd: int, path: path, mode: uint, flags: int) (void | errno) = {
    202 	let path = kpath(path)?;
    203 	wrap_return(syscall4(SYS_fchmodat,
    204 		dirfd: u64, path: uintptr: u64, mode: u64, flags: u64))?;
    205 };
    206 
    207 export fn fchown(fd: int, uid: uint, gid: uint) (void | errno) = {
    208 	wrap_return(syscall3(SYS_fchown,
    209 		fd: u64, uid: u32, gid: u32))?;
    210 };
    211 
    212 export fn fchownat(dirfd: int, path: path, uid: uint, gid: uint, flags: int) (void | errno) = {
    213 	let path = kpath(path)?;
    214 	wrap_return(syscall5(SYS_fchownat,
    215 		dirfd: u64, path: uintptr: u64, uid: u32, gid: u32, flags: u64))?;
    216 };
    217 
    218 export fn utimensat(dirfd: int, path: str, ts: *[2]timespec, flags: int) (void | errno) = {
    219 	let path = kpath(path)?;
    220 	wrap_return(syscall4(SYS_utimensat,
    221 		dirfd: u64, path: uintptr: u64, ts: uintptr: u64, flags: u64))?;
    222 };
    223 
    224 export fn futimens(fd: int, ts: *[2]timespec) (void | errno) = {
    225 	wrap_return(syscall2(SYS_futimens,
    226 		fd: u64, ts: uintptr: u64))?;
    227 };
    228 
    229 export fn faccessat(
    230 	dirfd: int,
    231 	path: path,
    232 	mode: int,
    233 	flags: int,
    234 ) (bool | errno) = {
    235 	let path = kpath(path)?;
    236 	match (wrap_return(syscall4(SYS_faccessat, dirfd: u64,
    237 		path: uintptr: u64, mode: u64, flags: u64))) {
    238 	case let err: errno =>
    239 		switch (err) {
    240 		case EACCES =>
    241 			return false;
    242 		case =>
    243 			return err;
    244 		};
    245 	case let n: u64 =>
    246 		assert(n == 0);
    247 		return true;
    248 	};
    249 };
    250 
    251 // The use of this function is discouraged, as it can create race conditions.
    252 // TOCTOU is preferred: attempt to simply use the resource you need and handle
    253 // any access errors which occur.
    254 export fn access(path: path, mode: int) (bool | errno) =
    255 	faccessat(AT_FDCWD, path, mode, 0);
    256 
    257 // TODO: Consider updating this to use SYS_freebsd11_getdirentries
    258 export fn getdents(dirfd: int, buf: *opaque, nbytes: size) (size | errno) = {
    259 	return wrap_return(syscall3(SYS_freebsd11_getdents, dirfd: u64,
    260 		buf: uintptr: u64, nbytes: u64))?: size;
    261 };
    262 
    263 // The return value is statically allocated and must be duplicated before
    264 // calling getcwd again.
    265 export fn getcwd() (*const u8 | errno) = {
    266 	static let pathbuf: [PATH_MAX]u8 = [0...];
    267 	wrap_return(syscall2(SYS___getcwd,
    268 		&pathbuf: *[*]u8: uintptr: u64,
    269 		PATH_MAX))?;
    270 	return &pathbuf: *const u8;
    271 };
    272 
    273 export fn fchdir(fd: int) (void | errno) = {
    274 	wrap_return(syscall1(SYS_fchdir, fd: u64))?;
    275 };
    276 
    277 export fn chdir(path: path) (void | errno) = {
    278 	let path = kpath(path)?;
    279 	wrap_return(syscall1(SYS_chdir, path: uintptr: u64))?;
    280 };
    281 
    282 export fn chroot(path: path) (void | errno) = {
    283 	let path = kpath(path)?;
    284 	wrap_return(syscall1(SYS_chroot, path: uintptr: u64))?;
    285 };
    286 
    287 export fn mmap(
    288 	addr: nullable *opaque,
    289 	length: size,
    290 	prot: uint,
    291 	flags: uint,
    292 	fd: int,
    293 	offs: size
    294 ) (errno | *opaque) = {
    295 	return wrap_return(syscall6(SYS_mmap, addr: uintptr: u64,
    296 		length: u64, prot: u64, flags: u64,
    297 		fd: u64, offs: u64))?: uintptr: *opaque;
    298 };
    299 
    300 export fn munmap(addr: *opaque, length: size) (void | errno) = {
    301 	wrap_return(syscall2(SYS_munmap, addr: uintptr: u64, length: u64))?;
    302 };
    303 
    304 export fn exit(status: int) never = {
    305 	syscall1(SYS_exit, status: u64);
    306 	abort();
    307 };
    308 
    309 export fn kill(pid: pid_t, signal: int) (void | errno) = {
    310 	wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?;
    311 };
    312 
    313 export fn fork() (pid_t | void | errno) = {
    314 	let n = wrap_return(syscall0(SYS_fork))?: pid_t;
    315 	switch (n) {
    316 	case 0 =>
    317 		return;
    318 	case =>
    319 		return n;
    320 	};
    321 };
    322 
    323 export fn fexecve(fd: int, argv: *[*]nullable *const u8,
    324 		envp: *[*]nullable *const u8) errno = {
    325 	return match (wrap_return(syscall3(SYS_fexecve, fd: u64,
    326 		argv: uintptr: u64, envp: uintptr: u64))) {
    327 	case let err: errno =>
    328 		yield err;
    329 	case u64 =>
    330 		abort("unreachable");
    331 	};
    332 };
    333 
    334 export fn wait4(
    335 	pid: pid_t,
    336 	wstatus: nullable *int,
    337 	options: int,
    338 	rusage: nullable *rusage,
    339 ) (int | errno) = {
    340 	return wrap_return(syscall4(SYS_wait4,
    341 		pid: u64, wstatus: uintptr: u64,
    342 		options: u64, rusage: uintptr: u64))?: int;
    343 };
    344 
    345 export fn wifexited(status: int) bool = wtermsig(status) == 0;
    346 export fn wexitstatus(status: int) int = (status & 0xff00) >> 8;
    347 
    348 export fn wtermsig(status: int) int = status & 0x7f;
    349 export fn wifsignaled(status: int) bool =
    350 	wtermsig(status) != 0o177 && wtermsig(status) != 0 && status != 0x13;
    351 
    352 export fn getpid() pid_t = syscall0(SYS_getpid): pid_t;
    353 
    354 export fn getppid() pid_t = syscall0(SYS_getppid): pid_t;
    355 
    356 export fn getpgrp() pid_t = syscall0(SYS_getpgrp): pid_t;
    357 
    358 export fn getpgid(pid: pid_t) (pid_t | errno) = {
    359 	return wrap_return(syscall1(SYS_getpgid, pid))?: pid_t;
    360 };
    361 
    362 export fn getsid(pid: pid_t) (pid_t | errno) = {
    363 	return wrap_return(syscall1(SYS_getsid, pid))?: pid_t;
    364 };
    365 
    366 export fn getpriority(which: int, who: id_t) (int | errno) = {
    367 	return wrap_return(syscall2(SYS_getpriority,
    368 		which: u64, who: u64))?: int;
    369 };
    370 
    371 export fn setpriority(which: int, who: id_t, prio: int) (void | errno) = {
    372 	wrap_return(syscall3(SYS_setpriority, which: u64, who: u64, prio: u64))?;
    373 };
    374 
    375 export fn umask(mode: mode_t) (mode_t | errno) = {
    376 	return wrap_return(syscall1(SYS_umask, mode: u64))?: mode_t;
    377 };
    378 
    379 export fn setresuid(uid: uid_t, euid: uid_t, suid: uid_t) (void | errno) = {
    380 	wrap_return(syscall3(SYS_setresuid, uid: u64, euid: u64, suid: u64))?;
    381 };
    382 
    383 export fn setresgid(gid: gid_t, egid: gid_t, sgid: gid_t) (void | errno) = {
    384 	wrap_return(syscall3(SYS_setresgid, gid: u64, egid: u64, sgid: u64))?;
    385 };
    386 
    387 export fn getgroups(gids: []gid_t) (uint | errno) = {
    388 	return wrap_return(syscall2(SYS_getgroups,
    389 		len(gids): u64, gids: *[*]gid_t: uintptr: u64))?: uint;
    390 };
    391 
    392 export fn setgroups(gids: []gid_t) (void | errno) = {
    393 	wrap_return(syscall2(SYS_setgroups,
    394 		len(gids): u64, gids: *[*]gid_t: uintptr: u64))?;
    395 };
    396 
    397 export fn getresuid(uid: *uid_t, euid: *uid_t, suid: *uid_t) (void | errno) = {
    398 	wrap_return(syscall3(SYS_getresuid,
    399 		uid: uintptr: u64,
    400 		euid: uintptr: u64,
    401 		suid: uintptr: u64))?;
    402 };
    403 
    404 export fn getresgid(gid: *gid_t, egid: *gid_t, sgid: *gid_t) (void | errno) = {
    405 	wrap_return(syscall3(SYS_getresgid,
    406 		gid: uintptr: u64,
    407 		egid: uintptr: u64,
    408 		sgid: uintptr: u64))?;
    409 };
    410 
    411 export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = {
    412 	wrap_return(syscall2(SYS_clock_gettime,
    413 		clock_id: u64, tp: uintptr: u64))?;
    414 };
    415 
    416 export fn clock_settime(clock_id: int, tp: *const timespec) (void | errno) = {
    417 	wrap_return(syscall2(SYS_clock_settime,
    418 		clock_id: u64, tp: uintptr: u64))?;
    419 };
    420 
    421 export fn nanosleep(req: *const timespec, rem: *timespec) (void | errno) = {
    422 	wrap_return(syscall2(SYS_nanosleep,
    423 		req: uintptr: u64, rem: uintptr: u64))?;
    424 };
    425 
    426 export fn getrandom(buf: *opaque, bufln: size, flags: uint) (size | errno) = {
    427 	return wrap_return(syscall3(SYS_getrandom,
    428 		buf: uintptr: u64, bufln: u64, flags: u64))?: size;
    429 };
    430 
    431 export type fcntl_arg = (void | int | *st_flock | *u64);
    432 
    433 export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = {
    434 	let _fd = fd: u64, _cmd = cmd: u64;
    435 	return wrap_return(match (arg) {
    436 	case void =>
    437 		yield syscall2(SYS_fcntl, _fd, _cmd);
    438 	case let i: int =>
    439 		yield syscall3(SYS_fcntl, _fd, _cmd, i: u64);
    440 	case let l: *st_flock =>
    441 		yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64);
    442 	case let u: *u64 =>
    443 		yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64);
    444 	})?: int;
    445 };
    446 
    447 export fn ppoll(
    448 	fds: *[*]pollfd,
    449 	nfds: nfds_t,
    450 	timeout: const nullable *timespec,
    451 	sigmask: const nullable *sigset,
    452 ) (int | errno) = {
    453 	return wrap_return(syscall4(SYS_ppoll, fds: uintptr: u64, nfds: u64,
    454 		timeout: uintptr: u64, sigmask: uintptr: u64))?: int;
    455 };
    456 
    457 export fn poll(fds: *[*]pollfd, nfds: nfds_t, timeout: int) (int | errno) = {
    458 	const ts = timespec {
    459 		tv_sec = timeout % 1000,
    460 		tv_nsec = timeout * 1000000,
    461 	};
    462 	return ppoll(fds, nfds, (if (timeout != -1) &ts else null), null);
    463 };
    464 
    465 export fn socket(domain: int, type_: int, protocol: int) (int | errno) = {
    466 	return wrap_return(syscall3(SYS_socket,
    467 		domain: u64, type_: u64, protocol: u64))?: int;
    468 };
    469 
    470 export fn socketpair(
    471 	domain: int,
    472 	type_: int,
    473 	protocol: int,
    474 	sv: *[*]int,
    475 ) (int | errno) = {
    476 	return wrap_return(syscall4(SYS_socketpair, domain: u64,
    477 		type_: u64, protocol: u64, sv: uintptr : u64))?: int;
    478 };
    479 
    480 export fn connect(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
    481 	return wrap_return(syscall3(SYS_connect,
    482 		sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
    483 };
    484 
    485 export fn bind(sockfd: int, addr: *const sockaddr, addrlen: u32) (int | errno) = {
    486 	return wrap_return(syscall3(SYS_bind,
    487 		sockfd: u64, addr: uintptr: u64, addrlen: u64))?: int;
    488 };
    489 
    490 export fn listen(sockfd: int, backlog: u32) (int | errno) = {
    491 	return wrap_return(syscall2(SYS_listen,
    492 		sockfd: u64, backlog: u64))?: int;
    493 };
    494 
    495 export fn accept(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    496 	return wrap_return(syscall3(SYS_accept,
    497 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    498 };
    499 
    500 export fn accept4(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32, flags: int) (int | errno) = {
    501 	return wrap_return(syscall4(SYS_accept4,
    502 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64, flags: u64))?: int;
    503 };
    504 
    505 export fn recvfrom(sockfd: int, buf: *opaque, len_: size, flags: int,
    506 	src_addr: nullable *sockaddr, addrlen: nullable *u32
    507 ) (size | errno) = {
    508 	return wrap_return(syscall6(SYS_recvfrom,
    509 		sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
    510 		src_addr: uintptr: u64, addrlen: uintptr: u64))?: size;
    511 };
    512 
    513 export fn sendto(sockfd: int, buf: *opaque, len_: size, flags: int,
    514 	dest_addr: nullable *sockaddr, addrlen: u32
    515 ) (size | errno) = {
    516 	return wrap_return(syscall6(SYS_sendto,
    517 		sockfd: u64, buf: uintptr: u64, len_: u64, flags: u64,
    518 		dest_addr: uintptr: u64, addrlen: u64))?: size;
    519 };
    520 
    521 export fn recv(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = {
    522 	return recvfrom(sockfd, buf, len_, flags, null, null);
    523 };
    524 
    525 export fn send(sockfd: int, buf: *opaque, len_: size, flags: int) (size | errno) = {
    526 	return sendto(sockfd, buf, len_, flags, null, 0);
    527 };
    528 
    529 export fn sendmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = {
    530 	return wrap_return(syscall3(SYS_sendmsg,
    531 		fd: u64, msg: uintptr: u64, flags: u64))?: int;
    532 };
    533 
    534 export fn recvmsg(fd: int, msg: *const msghdr, flags: int) (int | errno) = {
    535 	return wrap_return(syscall3(SYS_recvmsg,
    536 		fd: u64, msg: uintptr: u64, flags: u64))?: int;
    537 };
    538 
    539 export fn getsockopt(sockfd: int, level: int, optname: int, optval: nullable *opaque, optlen: nullable *u32) (int | errno) = {
    540 	return wrap_return(syscall5(SYS_getsockopt,
    541 		sockfd: u64, level: u64, optname: u64,
    542 		optval: uintptr: u64, optlen: uintptr: u64))?: int;
    543 };
    544 
    545 export fn setsockopt(sockfd: int, level: int, optname: int, optval: *opaque, optlen: u32) (int | errno) = {
    546 	return wrap_return(syscall5(SYS_setsockopt,
    547 		sockfd: u64, level: u64, optname: u64,
    548 		optval: uintptr: u64, optlen: u64))?: int;
    549 };
    550 
    551 export fn getsockname(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    552 	return wrap_return(syscall3(SYS_getsockname,
    553 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    554 };
    555 
    556 export fn getpeername(sockfd: int, addr: nullable *sockaddr, addrlen: nullable *u32) (int | errno) = {
    557 	return wrap_return(syscall3(SYS_getpeername,
    558 		sockfd: u64, addr: uintptr: u64, addrlen: uintptr: u64))?: int;
    559 };
    560 
    561 export fn sysctlbyname(name: str, oldp: nullable *opaque, oldlenp: nullable *size,
    562 		newp: nullable *const opaque, newlen: size) (void | errno) = {
    563 	let kname = kpath(name)?;
    564 	wrap_return(syscall6(SYS___sysctlbyname,
    565 		kname: uintptr: u64, len(name): u64,
    566 		oldp: uintptr: u64, oldlenp: uintptr: u64,
    567 		newp: uintptr: u64, newlen: u64))?;
    568 };
    569 
    570 export fn dup2(oldfd: int, newfd: int) (int | errno) = {
    571 	return wrap_return(syscall2(SYS_dup2, oldfd: u64, newfd: u64))?: int;
    572 };
    573 
    574 export fn posix_openpt(flags: int) (int | errno) = {
    575 	return wrap_return(syscall1(SYS_posix_openpt, flags: u64))?: int;
    576 };
    577 
    578 export fn posix_fallocate(fd: int, off: i64, ln: i64) (void | errno) = {
    579 	wrap_return(syscall3(SYS_posix_fallocate,
    580 		fd: u64, off: u64, ln: u64))?;
    581 };
    582 
    583 export fn flock(fd: int, op: int) (void | errno) = {
    584 	wrap_return(syscall2(SYS_flock,
    585 		fd: u64, op: u64))?;
    586 };
    587 
    588 export fn shm_open(
    589 	shm_path: path,
    590 	oflags: int,
    591 	mode: mode_t,
    592 	shmflags: int,
    593 	anon_path: path,
    594 ) (int | errno) = {
    595 	const shm_path = match (shm_path) {
    596 	case let string: *const u8 =>
    597 		if (string == SHM_ANON) yield SHM_ANON;
    598 		yield kpath(shm_path)?;
    599 	case =>
    600 		yield kpath(shm_path)?;
    601 	};
    602 	const anon_path = kpath(anon_path)?;
    603 	return wrap_return(syscall5(SYS_shm_open2,
    604 			shm_path: uintptr: u64,
    605 			oflags: u64,
    606 			mode: u64,
    607 			shmflags: u64,
    608 			anon_path: uintptr: u64))?: int;
    609 };
    610 
    611 export fn shm_unlink(shm_path: path) (void | errno) = {
    612 	const path = kpath(shm_path)?;
    613 	wrap_return(syscall1(SYS_shm_unlink, path: uintptr: u64))?;
    614 };
    615 
    616 export fn shmat(id: int, addr: *const opaque, flag: int) *opaque = {
    617 	return syscall3(SYS_shmat, id: u64, addr: uintptr: u64,
    618 		flag: u64): uintptr: *opaque;
    619 };
    620 
    621 export fn getrlimit(resource: int, rlim: *rlimit) (void | errno) = {
    622 	wrap_return(syscall2(SYS_getrlimit,
    623 		resource: u64, rlim: uintptr: u64))?;
    624 };
    625 
    626 export fn setrlimit(resource: int, rlim: *const rlimit) (void | errno) = {
    627 	wrap_return(syscall2(SYS_setrlimit,
    628 		resource: u64, rlim: uintptr: u64))?;
    629 };
    630 
    631 export fn sigprocmask(
    632 	how: int,
    633 	set: nullable *const sigset,
    634 	old: nullable *sigset,
    635 ) (int | errno) = {
    636 	return wrap_return(syscall3(SYS_sigprocmask,
    637 		how: u64, set: uintptr: u64, old: uintptr: u64))?: int;
    638 };
    639 
    640 export fn sigaction(
    641 	signum: int,
    642 	act: *const sigact,
    643 	old: nullable *sigact,
    644 ) (int | errno) = {
    645 	return wrap_return(syscall3(SYS_sigaction,
    646 		signum: u64, act: uintptr: u64, old: uintptr: u64))?: int;
    647 };
    648 
    649 export fn sigaltstack(
    650 	ss: nullable *stack_t,
    651 	old_ss: nullable *stack_t,
    652 ) (void | errno) = {
    653 	wrap_return(syscall2(SYS_sigaltstack,
    654 		ss: uintptr: u64, old_ss: uintptr: u64))?;
    655 };
    656 
    657 export fn shutdown(sockfd: int, how: int) (void | errno) = {
    658 	wrap_return(syscall2(SYS_shutdown,
    659 		sockfd: u64, how: u64))?;
    660 };
    661 
    662 export fn fsync(fd: int) (void | errno) = {
    663 	wrap_return(syscall1(SYS_fsync, fd: u64))?;
    664 };
    665 
    666 export fn fdatasync(fd: int) (void | errno) = {
    667 	wrap_return(syscall1(SYS_fdatasync, fd: u64))?;
    668 };