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