Files
gingerBill 842cfee0f3 Change Odin's LICENSE to zlib from BSD 3-clause
This change was made in order to allow things produced with Odin and using Odin's core library, to not require the LICENSE to also be distributed alongside the binary form.
2025-10-28 14:38:25 +00:00

637 lines
16 KiB
Odin

package sys_freebsd
/*
(c) Copyright 2024 Feoramund <rune@swevencraft.org>.
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_pwrite,
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 }