hare

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

syscalls.ha (18904B)


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