package sys_freebsd /* (c) Copyright 2024 Feoramund . Made available under Odin's license. List of contributors: Feoramund: Initial implementation. */ import "base:intrinsics" import "core:c" // FreeBSD 15 syscall numbers // See: https://alfonsosiciliano.gitlab.io/posts/2023-08-28-freebsd-15-system-calls.html SYS_read : uintptr : 3 SYS_write : uintptr : 4 SYS_open : uintptr : 5 SYS_close : uintptr : 6 SYS_getpid : uintptr : 20 SYS_recvfrom : uintptr : 29 SYS_accept : uintptr : 30 SYS_getpeername: uintptr : 31 SYS_getsockname: uintptr : 32 SYS_fcntl : uintptr : 92 SYS_fsync : uintptr : 95 SYS_socket : uintptr : 97 SYS_connect : uintptr : 98 SYS_bind : uintptr : 104 SYS_listen : uintptr : 106 SYS_sendto : uintptr : 133 SYS_shutdown : uintptr : 134 SYS_setsockopt : uintptr : 105 SYS_sysctl : uintptr : 202 SYS__umtx_op : uintptr : 454 SYS_pread : uintptr : 475 SYS_pwrite : uintptr : 476 SYS_accept4 : uintptr : 541 // // Odin syscall wrappers // // Read input. // // The read() function appeared in Version 1 AT&T UNIX. read :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { result, ok := intrinsics.syscall_bsd(SYS_read, cast(uintptr)fd, cast(uintptr)raw_data(buf), cast(uintptr)len(buf)) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Write output. // // The write() function appeared in Version 1 AT&T UNIX. write :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { result, ok := intrinsics.syscall_bsd(SYS_write, cast(uintptr)fd, cast(uintptr)raw_data(buf), cast(uintptr)len(buf)) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Open or create a file for reading, writing or executing. // // The open() function appeared in Version 1 AT&T UNIX. // The openat() function was introduced in FreeBSD 8.0. open :: proc "contextless" (path: string, flags: File_Status_Flags, mode: int = 0o000) -> (Fd, Errno) { result, ok := intrinsics.syscall_bsd(SYS_open, cast(uintptr)raw_data(path), cast(uintptr)transmute(c.int)flags, cast(uintptr)mode) if !ok { return 0, cast(Errno)result } return cast(Fd)result, nil } // Delete a descriptor. // // The open() function appeared in Version 1 AT&T UNIX. close :: proc "contextless" (fd: Fd) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_close, cast(uintptr)fd) return cast(Errno)result } // Get parent or calling process identification. // // The getpid() function appeared in Version 7 AT&T UNIX. getpid :: proc "contextless" () -> pid_t { // This always succeeds. result, _ := intrinsics.syscall_bsd(SYS_getpid) return cast(pid_t)result } // Receive message(s) from a socket. // // The recv() function appeared in 4.2BSD. // The recvmmsg() function appeared in FreeBSD 11.0. recvfrom :: proc "contextless" (s: Fd, buf: []u8, flags: Recv_Flags, from: ^$T) -> (int, Errno) where intrinsics.type_is_subtype_of(T, Socket_Address_Header) { fromlen: socklen_t = size_of(T) result, ok := intrinsics.syscall_bsd(SYS_recvfrom, cast(uintptr)s, cast(uintptr)raw_data(buf), cast(uintptr)len(buf), cast(uintptr)flags, cast(uintptr)from, cast(uintptr)&fromlen) // `from.len` will be modified by the syscall, so we shouldn't need to pass // `fromlen` back from this API. if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Receive message(s) from a socket. // // The recv() function appeared in 4.2BSD. // The recvmmsg() function appeared in FreeBSD 11.0. recv :: proc "contextless" (s: Fd, buf: []u8, flags: Recv_Flags) -> (int, Errno) { // This is a wrapper over recvfrom(). result, ok := intrinsics.syscall_bsd(SYS_recvfrom, cast(uintptr)s, cast(uintptr)raw_data(buf), cast(uintptr)len(buf), cast(uintptr)flags, 0, 0) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Accept a connection on a socket. // // The accept() system call appeared in 4.2BSD. accept_T :: proc "contextless" (s: Fd, sockaddr: ^$T) -> (Fd, Errno) where intrinsics.type_is_subtype_of(T, Socket_Address_Header) { // sockaddr must contain a valid pointer, or this will segfault because // we're telling the syscall that there's memory available to write to. addrlen: socklen_t = size_of(T) result, ok := intrinsics.syscall_bsd(SYS_accept, cast(uintptr)s, cast(uintptr)sockaddr, cast(uintptr)&addrlen) if !ok { return 0, cast(Errno)result } sockaddr.len = cast(u8)addrlen return cast(Fd)result, nil } // Accept a connection on a socket. // // The accept() system call appeared in 4.2BSD. accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) { result, ok := intrinsics.syscall_bsd(SYS_accept, cast(uintptr)s, cast(uintptr)0, cast(uintptr)0) if !ok { return 0, cast(Errno)result } return cast(Fd)result, nil } accept :: proc { accept_T, accept_nil } getsockname_or_peername :: proc "contextless" (s: Fd, sockaddr: ^$T, is_peer: bool) -> Errno { // sockaddr must contain a valid pointer, or this will segfault because // we're telling the syscall that there's memory available to write to. addrlen: socklen_t = size_of(T) result, ok := intrinsics.syscall_bsd( is_peer ? SYS_getpeername : SYS_getsockname, cast(uintptr)s, cast(uintptr)sockaddr, cast(uintptr)&addrlen) if !ok { return cast(Errno)result } return nil } // Get name of connected peer // // The getpeername() system call appeared in 4.2BSD. getpeername :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno { return getsockname_or_peername(s, sockaddr, true) } // Get socket name. // // The getsockname() system call appeared in 4.2BSD. getsockname :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno { return getsockname_or_peername(s, sockaddr, false) } // Synchronize changes to a file. // // The fsync() system call appeared in 4.2BSD. fsync :: proc "contextless" (fd: Fd) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fsync, cast(uintptr)fd) return cast(Errno)result } // File control. // // The fcntl() system call appeared in 4.2BSD. // The F_DUP2FD constant first appeared in FreeBSD 7.1. // // NOTE: If you know at compile-time what command you're calling, use one of the // `fcntl_*` procedures instead to preserve type safety. fcntl :: proc "contextless" (fd: Fd, cmd: File_Control_Command, arg: c.int) -> (int, Errno) { result, ok := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)cmd, cast(uintptr)arg) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // TODO: Implement more type-safe fcntl commands. fcntl_dupfd :: proc "contextless" (fd: Fd, newfd: Fd) -> (Fd, Errno) { result, ok := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.DUPFD, cast(uintptr)newfd) if !ok { return 0, cast(Errno)result } return cast(Fd)result, nil } fcntl_getfd :: proc "contextless" (fd: Fd) -> (bool, Errno) { result, ok := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.GETFD) if !ok { return false, cast(Errno)result } return result & FD_CLOEXEC > 0, nil } fcntl_setfd :: proc "contextless" (fd: Fd, close_on_exec: bool) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.SETFD, (close_on_exec ? FD_CLOEXEC : 0)) return cast(Errno)result } fcntl_getfl :: proc "contextless" (fd: Fd) -> (File_Status_Flags, Errno) { result, ok := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.GETFL) if !ok { return nil, cast(Errno)result } return transmute(File_Status_Flags)cast(c.int)result, nil } fcntl_setfl :: proc "contextless" (fd: Fd, flags: File_Status_Flags) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.SETFL, cast(uintptr)transmute(c.int)flags) return cast(Errno)result } fcntl_getown :: proc "contextless" (fd: Fd) -> (pid_t, Errno) { result, ok := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.GETOWN) if !ok { return 0, cast(Errno)result } return cast(pid_t)result, nil } fcntl_setown :: proc "contextless" (fd: Fd, pid: pid_t) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.SETOWN, cast(uintptr)pid) return cast(Errno)result } fcntl_getlk :: proc "contextless" (fd: Fd, flock: ^File_Lock) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.GETLK, cast(uintptr)flock) return cast(Errno)result } fcntl_setlk :: proc "contextless" (fd: Fd, flock: ^File_Lock) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.SETLK, cast(uintptr)flock) return cast(Errno)result } fcntl_add_seals :: proc "contextless" (fd: Fd, seals: File_Seals) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.ADD_SEALS, cast(uintptr)transmute(c.int)seals) return cast(Errno)result } fcntl_get_seals :: proc "contextless" (fd: Fd) -> (File_Seals, Errno) { result, ok := intrinsics.syscall_bsd(SYS_fcntl, cast(uintptr)fd, cast(uintptr)File_Control_Command.GET_SEALS) if !ok { return nil, cast(Errno)result } return transmute(File_Seals)cast(c.int)result, nil } // // End type-safe fcntl commands. // // Create an endpoint for communication. // // The socket() system call appeared in 4.2BSD. socket :: proc "contextless" (domain: Protocol_Family, type: Socket_Type, protocol: Protocol) -> (Fd, Errno) { result, ok := intrinsics.syscall_bsd(SYS_socket, cast(uintptr)domain, cast(uintptr)type, cast(uintptr)protocol) if !ok { return 0, cast(Errno)result } return cast(Fd)result, nil } // Initiate a connection on a socket. // // The connect() system call appeared in 4.2BSD. connect :: proc "contextless" (fd: Fd, sockaddr: ^$T, addrlen: socklen_t) -> Errno where intrinsics.type_is_subtype_of(T, Socket_Address_Header) { result, _ := intrinsics.syscall_bsd(SYS_connect, cast(uintptr)fd, cast(uintptr)sockaddr, cast(uintptr)addrlen) return cast(Errno)result } // Assign a local protocol address to a socket. // // The bind() system call appeared in 4.2BSD. bind :: proc "contextless" (s: Fd, sockaddr: ^$T, addrlen: socklen_t) -> Errno where intrinsics.type_is_subtype_of(T, Socket_Address_Header) { result, _ := intrinsics.syscall_bsd(SYS_bind, cast(uintptr)s, cast(uintptr)sockaddr, cast(uintptr)addrlen) return cast(Errno)result } // Listen for connections on a socket. // // The listen() system call appeared in 4.2BSD. listen :: proc "contextless" (s: Fd, backlog: int) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_listen, cast(uintptr)s, cast(uintptr)backlog) return cast(Errno)result } // Send message(s) from a socket. // // The send() function appeared in 4.2BSD. // The sendmmsg() function appeared in FreeBSD 11.0. sendto :: proc "contextless" (s: Fd, msg: []u8, flags: Send_Flags, to: ^$T) -> (int, Errno) where intrinsics.type_is_subtype_of(T, Socket_Address_Header) { result, ok := intrinsics.syscall_bsd(SYS_sendto, cast(uintptr)s, cast(uintptr)raw_data(msg), cast(uintptr)len(msg), cast(uintptr)flags, cast(uintptr)to, cast(uintptr)to.len) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Send message(s) from a socket. // // The send() function appeared in 4.2BSD. // The sendmmsg() function appeared in FreeBSD 11.0. send :: proc "contextless" (s: Fd, msg: []u8, flags: Send_Flags) -> (int, Errno) { // This is a wrapper over sendto(). result, ok := intrinsics.syscall_bsd(SYS_sendto, cast(uintptr)s, cast(uintptr)raw_data(msg), cast(uintptr)len(msg), cast(uintptr)flags, 0, 0) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Disable sends and/or receives on a socket. // // The shutdown() system call appeared in 4.2BSD. shutdown :: proc "contextless" (s: Fd, how: Shutdown_Method) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_shutdown, cast(uintptr)s, cast(uintptr)how) return cast(Errno)result } // Get and set options on sockets. // // The getsockopt() and setsockopt() system calls appeared in 4.2BSD. setsockopt :: proc "contextless" (s: Fd, level: Valid_Socket_Option_Level, optname: Socket_Option, optval: rawptr, optlen: socklen_t) -> Errno { real_level: uintptr switch which in level { case Protocol_Family: real_level = cast(uintptr)which case Socket_Option_Level: real_level = cast(uintptr)which } result, _ := intrinsics.syscall_bsd(SYS_setsockopt, cast(uintptr)s, real_level, cast(uintptr)optname, cast(uintptr)optval, cast(uintptr)optlen) return cast(Errno)result } // Get or set system information. // // The sysctl() function first appeared in 4.4BSD. sysctl :: proc "contextless" (mib: []MIB_Identifier, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> Errno { result, _ := intrinsics.syscall_bsd(SYS_sysctl, cast(uintptr)raw_data(mib), cast(uintptr)len(mib), cast(uintptr)oldp, cast(uintptr)oldlenp, cast(uintptr)newp, cast(uintptr)newlen) return cast(Errno)result } // Interface for implementation of userspace threading synchronization primitives. // // The _umtx_op() system call is non-standard and is used by the 1:1 Threading // Library (libthr, -lthr) to implement IEEE Std 1003.1-2001 (“POSIX.1”) // pthread(3) functionality. _umtx_op :: proc "contextless" (obj: rawptr, op: Userland_Mutex_Operation, val: c.ulong, uaddr, uaddr2: rawptr) -> Errno { result, _ := intrinsics.syscall_bsd(SYS__umtx_op, cast(uintptr)obj, cast(uintptr)op, cast(uintptr)val, cast(uintptr)uaddr, cast(uintptr)uaddr2) return cast(Errno)result } // Read input without modifying the file pointer. // // The pread() function appeared in AT&T System V Release 4 UNIX. pread :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) { result, ok := intrinsics.syscall_bsd(SYS_pread, cast(uintptr)fd, cast(uintptr)raw_data(buf), cast(uintptr)len(buf), cast(uintptr)offset) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Write output without modifying the file pointer. // // The pwrite() function appeared in AT&T System V Release 4 UNIX. // // BUGS // // The pwrite() system call appends the file without changing the file // offset if O_APPEND is set, contrary to IEEE Std 1003.1-2008 (“POSIX.1”) // where pwrite() writes into offset regardless of whether O_APPEND is set. pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) { result, ok := intrinsics.syscall_bsd(SYS_pwrite, cast(uintptr)fd, cast(uintptr)raw_data(buf), cast(uintptr)len(buf), cast(uintptr)offset) if !ok { return 0, cast(Errno)result } return cast(int)result, nil } // Accept a connection on a socket. // // The accept4() system call appeared in FreeBSD 10.0. accept4_T :: proc "contextless" (s: Fd, sockaddr: ^$T, flags: Socket_Flags = {}) -> (Fd, Errno) where intrinsics.type_is_subtype_of(T, Socket_Address_Header) { // `sockaddr` must contain a valid pointer, or this will segfault because // we're telling the syscall that there's memory available to write to. addrlen: u32 = size_of(T) result, ok := intrinsics.syscall_bsd(SYS_accept4, cast(uintptr)s, cast(uintptr)sockaddr, cast(uintptr)&addrlen, cast(uintptr)transmute(c.int)flags) if !ok { return 0, cast(Errno)result } sockaddr.len = cast(u8)addrlen return cast(Fd)result, nil } // Accept a connection on a socket. // // The accept4() system call appeared in FreeBSD 10.0. accept4_nil :: proc "contextless" (s: Fd, flags: Socket_Flags = {}) -> (Fd, Errno) { result, ok := intrinsics.syscall_bsd(SYS_accept4, cast(uintptr)s, cast(uintptr)0, cast(uintptr)0, cast(uintptr)transmute(c.int)flags) if !ok { return 0, cast(Errno)result } return cast(Fd)result, nil } accept4 :: proc { accept4_nil, accept4_T }