diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin index e5c194220..86fc425d6 100644 --- a/core/crypto/rand_linux.odin +++ b/core/crypto/rand_linux.odin @@ -1,8 +1,8 @@ package crypto import "core:fmt" -import "core:os" -import "core:sys/unix" + +import "core:sys/linux" _MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1 @@ -12,26 +12,25 @@ _rand_bytes :: proc (dst: []byte) { for l > 0 { to_read := min(l, _MAX_PER_CALL_BYTES) - ret := unix.sys_getrandom(raw_data(dst), uint(to_read), 0) - if ret < 0 { - switch os.Errno(-ret) { - case os.EINTR: - // Call interupted by a signal handler, just retry the - // request. - continue - case os.ENOSYS: - // The kernel is apparently prehistoric (< 3.17 circa 2014) - // and does not support getrandom. - panic("crypto: getrandom not available in kernel") - case: - // All other failures are things that should NEVER happen - // unless the kernel interface changes (ie: the Linux - // developers break userland). - panic(fmt.tprintf("crypto: getrandom failed: %d", ret)) - } + n_read, errno := linux.getrandom(dst[:to_read], {}) + #partial switch errno { + case .NONE: + // Do nothing + case .EINTR: + // Call interupted by a signal handler, just retry the + // request. + continue + case .ENOSYS: + // The kernel is apparently prehistoric (< 3.17 circa 2014) + // and does not support getrandom. + panic("crypto: getrandom not available in kernel") + case: + // All other failures are things that should NEVER happen + // unless the kernel interface changes (ie: the Linux + // developers break userland). + panic(fmt.tprintf("crypto: getrandom failed: %v", errno)) } - - l -= ret - dst = dst[ret:] + l -= n_read + dst = dst[n_read:] } } diff --git a/core/math/rand/system_linux.odin b/core/math/rand/system_linux.odin index 2923b77be..42c9f86fa 100644 --- a/core/math/rand/system_linux.odin +++ b/core/math/rand/system_linux.odin @@ -1,27 +1,28 @@ package rand -import "core:sys/unix" +import "core:sys/linux" @(require_results) _system_random :: proc() -> u64 { for { value: u64 - ret := unix.sys_getrandom(([^]u8)(&value), size_of(value), 0) - if ret < 0 { - switch ret { - case -4: // EINTR - // Call interupted by a signal handler, just retry the request. - continue - case -38: // ENOSYS - // The kernel is apparently prehistoric (< 3.17 circa 2014) - // and does not support getrandom. - panic("getrandom not available in kernel") - case: - // All other failures are things that should NEVER happen - // unless the kernel interface changes (ie: the Linux - // developers break userland). - panic("getrandom failed") - } + value_buf := (cast([^]u8)&value)[:size_of(u64)] + _, errno := linux.getrandom(value_buf, {}) + #partial switch errno { + case .NONE: + // Do nothing + case .EINTR: + // Call interupted by a signal handler, just retry the request. + continue + case .ENOSYS: + // The kernel is apparently prehistoric (< 3.17 circa 2014) + // and does not support getrandom. + panic("getrandom not available in kernel") + case: + // All other failures are things that should NEVER happen + // unless the kernel interface changes (ie: the Linux + // developers break userland). + panic("getrandom failed") } return value } diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index 0f376312f..7ffc7643e 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -2,100 +2,49 @@ //+private package mem_virtual -import "core:c" -import "core:intrinsics" -import "core:sys/unix" - -PROT_NONE :: 0x0 -PROT_READ :: 0x1 -PROT_WRITE :: 0x2 -PROT_EXEC :: 0x4 -PROT_GROWSDOWN :: 0x01000000 -PROT_GROWSUP :: 0x02000000 - -MAP_FIXED :: 0x1 -MAP_PRIVATE :: 0x2 -MAP_SHARED :: 0x4 -MAP_ANONYMOUS :: 0x20 - -MADV_NORMAL :: 0 -MADV_RANDOM :: 1 -MADV_SEQUENTIAL :: 2 -MADV_WILLNEED :: 3 -MADV_DONTNEED :: 4 -MADV_FREE :: 8 -MADV_REMOVE :: 9 -MADV_DONTFORK :: 10 -MADV_DOFORK :: 11 -MADV_MERGEABLE :: 12 -MADV_UNMERGEABLE :: 13 -MADV_HUGEPAGE :: 14 -MADV_NOHUGEPAGE :: 15 -MADV_DONTDUMP :: 16 -MADV_DODUMP :: 17 -MADV_WIPEONFORK :: 18 -MADV_KEEPONFORK :: 19 -MADV_HWPOISON :: 100 - -mmap :: proc "contextless" (addr: rawptr, length: uint, prot: c.int, flags: c.int, fd: c.int, offset: uintptr) -> int { - res := intrinsics.syscall(unix.SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset) - return int(res) -} - -munmap :: proc "contextless" (addr: rawptr, length: uint) -> c.int { - res := intrinsics.syscall(unix.SYS_munmap, uintptr(addr), uintptr(length)) - return c.int(res) -} - -mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: c.int) -> c.int { - res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot)) - return c.int(res) -} - -madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.int { - res := intrinsics.syscall(unix.SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice)) - return c.int(res) -} - +import "core:sys/linux" _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { - result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) - if result < 0 && result > -4096 { + addr, errno := linux.mmap(0, size, {}, {.PRIVATE, .ANONYMOUS}) + if errno == .ENOMEM { return nil, .Out_Of_Memory + } else if errno == .EINVAL { + return nil, .Invalid_Argument } - return ([^]byte)(uintptr(result))[:size], nil + return (cast([^]byte)addr)[:size], nil } _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { - result := mprotect(data, size, PROT_READ|PROT_WRITE) - if result != 0 { - // TODO(bill): Handle error value correctly + errno := linux.mprotect(data, size, {.READ, .WRITE}) + if errno == .EINVAL { + return .Invalid_Pointer + } else if errno == .ENOMEM { return .Out_Of_Memory } return nil } + _decommit :: proc "contextless" (data: rawptr, size: uint) { - mprotect(data, size, PROT_NONE) - madvise(data, size, MADV_FREE) + _ = linux.mprotect(data, size, {}) + _ = linux.madvise(data, size, .FREE) } + _release :: proc "contextless" (data: rawptr, size: uint) { - munmap(data, size) + _ = linux.munmap(data, size) } + _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { - pflags: c.int - pflags = PROT_NONE - if .Read in flags { pflags |= PROT_READ } - if .Write in flags { pflags |= PROT_WRITE } - if .Execute in flags { pflags |= PROT_EXEC } - err := mprotect(data, size, pflags) - return err != 0 + pflags: linux.Mem_Protection + pflags = {} + if .Read in flags { pflags |= {.READ} } + if .Write in flags { pflags |= {.WRITE} } + if .Execute in flags { pflags |= {.EXEC} } + errno := linux.mprotect(data, size, pflags) + return errno != .NONE } - - _platform_memory_init :: proc() { DEFAULT_PAGE_SIZE = 4096 - // is power of two assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin index d76132ad5..2370dd0d8 100644 --- a/core/net/errors_linux.odin +++ b/core/net/errors_linux.odin @@ -16,182 +16,184 @@ package net Tetralux: Initial implementation Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver Jeroen van Rijn: Cross platform unification, code style, documentation + flysand: Move dependency from core:linux.Errno to core:sys/linux */ import "core:c" -import "core:os" +import "core:sys/linux" Create_Socket_Error :: enum c.int { None = 0, - Family_Not_Supported_For_This_Socket = c.int(os.EAFNOSUPPORT), - No_Socket_Descriptors_Available = c.int(os.EMFILE), - No_Buffer_Space_Available = c.int(os.ENOBUFS), - No_Memory_Available_Available = c.int(os.ENOMEM), - Protocol_Unsupported_By_System = c.int(os.EPROTONOSUPPORT), - Wrong_Protocol_For_Socket = c.int(os.EPROTONOSUPPORT), - Family_And_Socket_Type_Mismatch = c.int(os.EPROTONOSUPPORT), + Family_Not_Supported_For_This_Socket = c.int(linux.Errno.EAFNOSUPPORT), + No_Socket_Descriptors_Available = c.int(linux.Errno.EMFILE), + No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), + No_Memory_Available_Available = c.int(linux.Errno.ENOMEM), + Protocol_Unsupported_By_System = c.int(linux.Errno.EPROTONOSUPPORT), + Wrong_Protocol_For_Socket = c.int(linux.Errno.EPROTONOSUPPORT), + Family_And_Socket_Type_Mismatch = c.int(linux.Errno.EPROTONOSUPPORT), } Dial_Error :: enum c.int { None = 0, Port_Required = -1, - Address_In_Use = c.int(os.EADDRINUSE), - In_Progress = c.int(os.EINPROGRESS), - Cannot_Use_Any_Address = c.int(os.EADDRNOTAVAIL), - Wrong_Family_For_Socket = c.int(os.EAFNOSUPPORT), - Refused = c.int(os.ECONNREFUSED), - Is_Listening_Socket = c.int(os.EACCES), - Already_Connected = c.int(os.EISCONN), - Network_Unreachable = c.int(os.ENETUNREACH), // Device is offline - Host_Unreachable = c.int(os.EHOSTUNREACH), // Remote host cannot be reached - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Not_Socket = c.int(os.ENOTSOCK), - Timeout = c.int(os.ETIMEDOUT), + Address_In_Use = c.int(linux.Errno.EADDRINUSE), + In_Progress = c.int(linux.Errno.EINPROGRESS), + Cannot_Use_Any_Address = c.int(linux.Errno.EADDRNOTAVAIL), + Wrong_Family_For_Socket = c.int(linux.Errno.EAFNOSUPPORT), + Refused = c.int(linux.Errno.ECONNREFUSED), + Is_Listening_Socket = c.int(linux.Errno.EACCES), + Already_Connected = c.int(linux.Errno.EISCONN), + Network_Unreachable = c.int(linux.Errno.ENETUNREACH), // Device is offline + Host_Unreachable = c.int(linux.Errno.EHOSTUNREACH), // Remote host cannot be reached + No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), + Not_Socket = c.int(linux.Errno.ENOTSOCK), + Timeout = c.int(linux.Errno.ETIMEDOUT), // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = c.int(os.EWOULDBLOCK), + Would_Block = c.int(linux.Errno.EWOULDBLOCK), } Bind_Error :: enum c.int { None = 0, - Address_In_Use = c.int(os.EADDRINUSE), // Another application is currently bound to this endpoint. - Given_Nonlocal_Address = c.int(os.EADDRNOTAVAIL), // The address is not a local address on this machine. - Broadcast_Disabled = c.int(os.EACCES), // To bind a UDP socket to the broadcast address, the appropriate socket option must be set. - Address_Family_Mismatch = c.int(os.EFAULT), // The address family of the address does not match that of the socket. - Already_Bound = c.int(os.EINVAL), // The socket is already bound to an address. - No_Ports_Available = c.int(os.ENOBUFS), // There are not enough ephemeral ports available. + Address_In_Use = c.int(linux.Errno.EADDRINUSE), // Another application is currently bound to this endpoint. + Given_Nonlocal_Address = c.int(linux.Errno.EADDRNOTAVAIL), // The address is not a local address on this machine. + Broadcast_Disabled = c.int(linux.Errno.EACCES), // To bind a UDP socket to the broadcast address, the appropriate socket option must be set. + Address_Family_Mismatch = c.int(linux.Errno.EFAULT), // The address family of the address does not match that of the socket. + Already_Bound = c.int(linux.Errno.EINVAL), // The socket is already bound to an address. + No_Ports_Available = c.int(linux.Errno.ENOBUFS), // There are not enough ephemeral ports available. } Listen_Error :: enum c.int { None = 0, - Address_In_Use = c.int(os.EADDRINUSE), - Already_Connected = c.int(os.EISCONN), - No_Socket_Descriptors_Available = c.int(os.EMFILE), - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Nonlocal_Address = c.int(os.EADDRNOTAVAIL), - Not_Socket = c.int(os.ENOTSOCK), - Listening_Not_Supported_For_This_Socket = c.int(os.EOPNOTSUPP), + Address_In_Use = c.int(linux.Errno.EADDRINUSE), + Already_Connected = c.int(linux.Errno.EISCONN), + No_Socket_Descriptors_Available = c.int(linux.Errno.EMFILE), + No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), + Nonlocal_Address = c.int(linux.Errno.EADDRNOTAVAIL), + Not_Socket = c.int(linux.Errno.ENOTSOCK), + Listening_Not_Supported_For_This_Socket = c.int(linux.Errno.EOPNOTSUPP), } Accept_Error :: enum c.int { None = 0, - Not_Listening = c.int(os.EINVAL), - No_Socket_Descriptors_Available_For_Client_Socket = c.int(os.EMFILE), - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Not_Socket = c.int(os.ENOTSOCK), - Not_Connection_Oriented_Socket = c.int(os.EOPNOTSUPP), + Not_Listening = c.int(linux.Errno.EINVAL), + No_Socket_Descriptors_Available_For_Client_Socket = c.int(linux.Errno.EMFILE), + No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), + Not_Socket = c.int(linux.Errno.ENOTSOCK), + Not_Connection_Oriented_Socket = c.int(linux.Errno.EOPNOTSUPP), // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = c.int(os.EWOULDBLOCK), + Would_Block = c.int(linux.Errno.EWOULDBLOCK), } TCP_Recv_Error :: enum c.int { None = 0, - Shutdown = c.int(os.ESHUTDOWN), - Not_Connected = c.int(os.ENOTCONN), - Connection_Broken = c.int(os.ENETRESET), - Not_Socket = c.int(os.ENOTSOCK), - Aborted = c.int(os.ECONNABORTED), + Shutdown = c.int(linux.Errno.ESHUTDOWN), + Not_Connected = c.int(linux.Errno.ENOTCONN), + Connection_Broken = c.int(linux.Errno.ENETRESET), + Not_Socket = c.int(linux.Errno.ENOTSOCK), + Aborted = c.int(linux.Errno.ECONNABORTED), // TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them? - Connection_Closed = c.int(os.ECONNRESET), - Offline = c.int(os.ENETDOWN), - Host_Unreachable = c.int(os.EHOSTUNREACH), - Interrupted = c.int(os.EINTR), - Timeout = c.int(os.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets... + Connection_Closed = c.int(linux.Errno.ECONNRESET), + Offline = c.int(linux.Errno.ENETDOWN), + Host_Unreachable = c.int(linux.Errno.EHOSTUNREACH), + Interrupted = c.int(linux.Errno.EINTR), + Timeout = c.int(linux.Errno.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets... } UDP_Recv_Error :: enum c.int { None = 0, - Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost. - Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. - Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor. - Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory. - Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). + Buffer_Too_Small = c.int(linux.Errno.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost. + Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. + Not_Descriptor = c.int(linux.Errno.EBADF), // The so-called socket is, in fact, not even a valid descriptor. + Bad_Buffer = c.int(linux.Errno.EFAULT), // The buffer did not point to a valid location in memory. + Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). // The send timeout duration passed before all data was received. See Socket_Option.Receive_Timeout. // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(os.EWOULDBLOCK), - Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't. + Timeout = c.int(linux.Errno.EWOULDBLOCK), + Socket_Not_Bound = c.int(linux.Errno.EINVAL), // The socket must be bound for this operation, but isn't. } TCP_Send_Error :: enum c.int { None = 0, - Aborted = c.int(os.ECONNABORTED), - Connection_Closed = c.int(os.ECONNRESET), - Not_Connected = c.int(os.ENOTCONN), - Shutdown = c.int(os.ESHUTDOWN), + Aborted = c.int(linux.Errno.ECONNABORTED), + Connection_Closed = c.int(linux.Errno.ECONNRESET), + Not_Connected = c.int(linux.Errno.ENOTCONN), + Shutdown = c.int(linux.Errno.ESHUTDOWN), // The send queue was full. // This is usually a transient issue. // // This also shouldn't normally happen on Linux, as data is dropped if it // doesn't fit in the send queue. - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Offline = c.int(os.ENETDOWN), - Host_Unreachable = c.int(os.EHOSTUNREACH), - Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). - Timeout = c.int(os.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. - Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. + No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), + Offline = c.int(linux.Errno.ENETDOWN), + Host_Unreachable = c.int(linux.Errno.EHOSTUNREACH), + Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). + Timeout = c.int(linux.Errno.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. + Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. } // TODO UDP_Send_Error :: enum c.int { None = 0, - Message_Too_Long = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent. + Message_Too_Long = c.int(linux.Errno.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent. // TODO: not sure what the exact circumstances for this is yet - Network_Unreachable = c.int(os.ENETUNREACH), - No_Outbound_Ports_Available = c.int(os.EAGAIN), // There are no more emphemeral outbound ports available to bind the socket to, in order to send. + Network_Unreachable = c.int(linux.Errno.ENETUNREACH), + No_Outbound_Ports_Available = c.int(linux.Errno.EAGAIN), // There are no more emphemeral outbound ports available to bind the socket to, in order to send. // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(os.EWOULDBLOCK), - Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. - Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor. - Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory. - Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). + Timeout = c.int(linux.Errno.EWOULDBLOCK), + Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. + Not_Descriptor = c.int(linux.Errno.EBADF), // The so-called socket is, in fact, not even a valid descriptor. + Bad_Buffer = c.int(linux.Errno.EFAULT), // The buffer did not point to a valid location in memory. + Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). // The send queue was full. // This is usually a transient issue. // // This also shouldn't normally happen on Linux, as data is dropped if it // doesn't fit in the send queue. - No_Buffer_Space_Available = c.int(os.ENOBUFS), - No_Memory_Available = c.int(os.ENOMEM), // No memory was available to properly manage the send queue. + No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), + No_Memory_Available = c.int(linux.Errno.ENOMEM), // No memory was available to properly manage the send queue. } +// TODO(flysand): slight regression Shutdown_Manner :: enum c.int { - Receive = c.int(os.SHUT_RD), - Send = c.int(os.SHUT_WR), - Both = c.int(os.SHUT_RDWR), + Receive = c.int(linux.Shutdown_How.RD), + Send = c.int(linux.Shutdown_How.WR), + Both = c.int(linux.Shutdown_How.RDWR), } Shutdown_Error :: enum c.int { None = 0, - Aborted = c.int(os.ECONNABORTED), - Reset = c.int(os.ECONNRESET), - Offline = c.int(os.ENETDOWN), - Not_Connected = c.int(os.ENOTCONN), - Not_Socket = c.int(os.ENOTSOCK), - Invalid_Manner = c.int(os.EINVAL), + Aborted = c.int(linux.Errno.ECONNABORTED), + Reset = c.int(linux.Errno.ECONNRESET), + Offline = c.int(linux.Errno.ENETDOWN), + Not_Connected = c.int(linux.Errno.ENOTCONN), + Not_Socket = c.int(linux.Errno.ENOTSOCK), + Invalid_Manner = c.int(linux.Errno.EINVAL), } Socket_Option_Error :: enum c.int { None = 0, - Offline = c.int(os.ENETDOWN), - Timeout_When_Keepalive_Set = c.int(os.ENETRESET), - Invalid_Option_For_Socket = c.int(os.ENOPROTOOPT), - Reset_When_Keepalive_Set = c.int(os.ENOTCONN), - Not_Socket = c.int(os.ENOTSOCK), + Offline = c.int(linux.Errno.ENETDOWN), + Timeout_When_Keepalive_Set = c.int(linux.Errno.ENETRESET), + Invalid_Option_For_Socket = c.int(linux.Errno.ENOPROTOOPT), + Reset_When_Keepalive_Set = c.int(linux.Errno.ENOTCONN), + Not_Socket = c.int(linux.Errno.ENOTSOCK), } Set_Blocking_Error :: enum c.int { None = 0, // TODO: add errors occuring on followig calls: - // flags, _ := os.fcntl(sd, os.F_GETFL, 0) - // os.fcntl(sd, os.F_SETFL, flags | int(os.O_NONBLOCK)) + // flags, _ := linux.Errno.fcntl(sd, linux.Errno.F_GETFL, 0) + // linux.Errno.fcntl(sd, linux.Errno.F_SETFL, flags | int(linux.Errno.O_NONBLOCK)) } \ No newline at end of file diff --git a/core/net/interface_linux.odin b/core/net/interface_linux.odin index e889cfa97..7c99cf23b 100644 --- a/core/net/interface_linux.odin +++ b/core/net/interface_linux.odin @@ -21,120 +21,124 @@ package net TODO: When we have raw sockets, split off into its own file for Linux so we can use the NETLINK protocol and bypass libc. */ -import "core:os" -import "core:strings" +//import "core:strings" + +// TODO(flysand): regression +// NOTE(flysand): https://man7.org/linux/man-pages/man7/netlink.7.html +// apparently musl libc uses this to enumerate network interfaces @(private) _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { context.allocator = allocator - head: ^os.ifaddrs + // head: ^os.ifaddrs - if res := os._getifaddrs(&head); res < 0 { - return {}, .Unable_To_Enumerate_Network_Interfaces - } + // if res := os._getifaddrs(&head); res < 0 { + // return {}, .Unable_To_Enumerate_Network_Interfaces + // } - /* - Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct. - We're going to have to iterate over a list and coalesce information as we go. - */ - ifaces: map[string]^Network_Interface - defer delete(ifaces) + // /* + // Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct. + // We're going to have to iterate over a list and coalesce information as we go. + // */ + // ifaces: map[string]^Network_Interface + // defer delete(ifaces) - for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next { - adapter_name := string(ifaddr.name) + // for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next { + // adapter_name := string(ifaddr.name) - /* - Check if we have seen this interface name before so we can reuse the `Network_Interface`. - Else, create a new one. - */ - if adapter_name not_in ifaces { - ifaces[adapter_name] = new(Network_Interface) - ifaces[adapter_name].adapter_name = strings.clone(adapter_name) - } - iface := ifaces[adapter_name] + // /* + // Check if we have seen this interface name before so we can reuse the `Network_Interface`. + // Else, create a new one. + // */ + // if adapter_name not_in ifaces { + // ifaces[adapter_name] = new(Network_Interface) + // ifaces[adapter_name].adapter_name = strings.clone(adapter_name) + // } + // iface := ifaces[adapter_name] - address: Address - netmask: Netmask + // address: Address + // netmask: Netmask - if ifaddr.address != nil { - switch int(ifaddr.address.sa_family) { - case os.AF_INET, os.AF_INET6: - address = _sockaddr_basic_to_endpoint(ifaddr.address).address + // if ifaddr.address != nil { + // switch int(ifaddr.address.sa_family) { + // case os.AF_INET, os.AF_INET6: + // address = _sockaddr_basic_to_endpoint(ifaddr.address).address - case os.AF_PACKET: - /* - For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a - 32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count - is truncated beyond usefulness. + // case os.AF_PACKET: + // /* + // For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a + // 32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count + // is truncated beyond usefulness. - We're not going to retrieve stats now. Instead this serves as a reminder to use - the NETLINK protocol for this purpose. + // We're not going to retrieve stats now. Instead this serves as a reminder to use + // the NETLINK protocol for this purpose. - But in case you were curious: - stats := transmute(^os.rtnl_link_stats)ifaddr.data - fmt.println(stats) - */ - case: - } - } + // But in case you were curious: + // stats := transmute(^os.rtnl_link_stats)ifaddr.data + // fmt.println(stats) + // */ + // case: + // } + // } - if ifaddr.netmask != nil { - switch int(ifaddr.netmask.sa_family) { - case os.AF_INET, os.AF_INET6: - netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address) - case: - } - } + // if ifaddr.netmask != nil { + // switch int(ifaddr.netmask.sa_family) { + // case os.AF_INET, os.AF_INET6: + // netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address) + // case: + // } + // } - if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags { - switch int(ifaddr.broadcast_or_dest.sa_family) { - case os.AF_INET, os.AF_INET6: - broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address - append(&iface.multicast, broadcast) - case: - } - } + // if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags { + // switch int(ifaddr.broadcast_or_dest.sa_family) { + // case os.AF_INET, os.AF_INET6: + // broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address + // append(&iface.multicast, broadcast) + // case: + // } + // } - if address != nil { - lease := Lease{ - address = address, - netmask = netmask, - } - append(&iface.unicast, lease) - } + // if address != nil { + // lease := Lease{ + // address = address, + // netmask = netmask, + // } + // append(&iface.unicast, lease) + // } - /* - TODO: Refine this based on the type of adapter. - */ - state := Link_State{} + // /* + // TODO: Refine this based on the type of adapter. + // */ + // state := Link_State{} - if .UP in ifaddr.flags { - state |= {.Up} - } + // if .UP in ifaddr.flags { + // state |= {.Up} + // } - if .DORMANT in ifaddr.flags { - state |= {.Dormant} - } + // if .DORMANT in ifaddr.flags { + // state |= {.Dormant} + // } - if .LOOPBACK in ifaddr.flags { - state |= {.Loopback} - } - iface.link.state = state - } + // if .LOOPBACK in ifaddr.flags { + // state |= {.Loopback} + // } + // iface.link.state = state + // } - /* - Free the OS structures. - */ - os._freeifaddrs(head) + // /* + // Free the OS structures. + // */ + // os._freeifaddrs(head) - /* - Turn the map into a slice to return. - */ - _interfaces := make([dynamic]Network_Interface, 0, allocator) - for _, iface in ifaces { - append(&_interfaces, iface^) - free(iface) - } - return _interfaces[:], {} + // /* + // Turn the map into a slice to return. + // */ + // _interfaces := make([dynamic]Network_Interface, 0, allocator) + // for _, iface in ifaces { + // append(&_interfaces, iface^) + // free(iface) + // } + // return _interfaces[:], {} + return nil, {} } \ No newline at end of file diff --git a/core/net/socket.odin b/core/net/socket.odin index 8cdf7cceb..40fa6ab56 100644 --- a/core/net/socket.odin +++ b/core/net/socket.odin @@ -18,7 +18,7 @@ package net Jeroen van Rijn: Cross platform unification, code style, documentation */ -any_socket_to_socket :: proc(socket: Any_Socket) -> Socket { +any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket { switch s in socket { case TCP_Socket: return Socket(s) case UDP_Socket: return Socket(s) diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index b7141e8ba..590946dff 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -16,241 +16,294 @@ package net Tetralux: Initial implementation Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver Jeroen van Rijn: Cross platform unification, code style, documentation + flysand: Move dependency from core:os to core:sys/linux */ import "core:c" -import "core:os" import "core:time" +import "core:sys/linux" Socket_Option :: enum c.int { - Reuse_Address = c.int(os.SO_REUSEADDR), - Keep_Alive = c.int(os.SO_KEEPALIVE), - Out_Of_Bounds_Data_Inline = c.int(os.SO_OOBINLINE), - TCP_Nodelay = c.int(os.TCP_NODELAY), - Linger = c.int(os.SO_LINGER), - Receive_Buffer_Size = c.int(os.SO_RCVBUF), - Send_Buffer_Size = c.int(os.SO_SNDBUF), - Receive_Timeout = c.int(os.SO_RCVTIMEO_NEW), - Send_Timeout = c.int(os.SO_SNDTIMEO_NEW), + Reuse_Address = c.int(linux.Socket_Option.REUSEADDR), + Keep_Alive = c.int(linux.Socket_Option.KEEPALIVE), + Out_Of_Bounds_Data_Inline = c.int(linux.Socket_Option.OOBINLINE), + TCP_Nodelay = c.int(linux.Socket_TCP_Option.NODELAY), + Linger = c.int(linux.Socket_Option.LINGER), + Receive_Buffer_Size = c.int(linux.Socket_Option.RCVBUF), + Send_Buffer_Size = c.int(linux.Socket_Option.SNDBUF), + Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO_NEW), + Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO_NEW), } -@(private) -_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { - c_type, c_protocol, c_family: int +// Wrappers and unwrappers for system-native types +@(private="file") +_unwrap_os_socket :: proc "contextless" (sock: Any_Socket)->linux.Fd { + return linux.Fd(any_socket_to_socket(sock)) +} + +@(private="file") +_wrap_os_socket :: proc "contextless" (sock: linux.Fd, protocol: Socket_Protocol)->Any_Socket { + switch protocol { + case .TCP: return TCP_Socket(Socket(sock)) + case .UDP: return UDP_Socket(Socket(sock)) + case: + unreachable() + } +} + +@(private="file") +_unwrap_os_family :: proc "contextless" (family: Address_Family)->linux.Address_Family { switch family { - case .IP4: c_family = os.AF_INET - case .IP6: c_family = os.AF_INET6 - case: - unreachable() - } - - switch protocol { - case .TCP: c_type = os.SOCK_STREAM; c_protocol = os.IPPROTO_TCP - case .UDP: c_type = os.SOCK_DGRAM; c_protocol = os.IPPROTO_UDP - case: - unreachable() - } - - sock, ok := os.socket(c_family, c_type, c_protocol) - if ok != os.ERROR_NONE { - err = Create_Socket_Error(ok) - return - } - - switch protocol { - case .TCP: return TCP_Socket(sock), nil - case .UDP: return UDP_Socket(sock), nil + case .IP4: return .INET + case .IP6: return .INET6 case: unreachable() } } +@(private="file") +_unwrap_os_proto_socktype :: proc "contextless" (protocol: Socket_Protocol)->(linux.Protocol, linux.Socket_Type) { + switch protocol { + case .TCP: return .TCP, .STREAM + case .UDP: return .UDP, .DGRAM + case: + unreachable() + } +} + +@(private="file") +_unwrap_os_addr :: proc "contextless" (endpoint: Endpoint)->(linux.Sock_Addr_Any) { + switch address in endpoint.address { + case IP4_Address: + return { + ipv4 = { + sin_family = .INET, + sin_port = u16be(endpoint.port), + sin_addr = transmute([4]u8) endpoint.address.(IP4_Address), + }, + } + case IP6_Address: + return { + ipv6 = { + sin6_port = u16be(endpoint.port), + sin6_addr = transmute([16]u8) endpoint.address.(IP6_Address), + sin6_family = .INET6, + }, + } + case: + unreachable() + } +} + +@(private="file") +_wrap_os_addr :: proc "contextless" (addr: linux.Sock_Addr_Any)->(Endpoint) { + #partial switch addr.family { + case .INET: + return { + address = cast(IP4_Address) addr.sin_addr, + port = cast(int) addr.sin_port, + } + case .INET6: + return { + port = cast(int) addr.sin6_port, + address = transmute(IP6_Address) addr.sin6_addr, + } + case: + unreachable() + } +} + +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (Any_Socket, Network_Error) { + family := _unwrap_os_family(family) + proto, socktype := _unwrap_os_proto_socktype(protocol) + sock, errno := linux.socket(family, socktype, {}, proto) + if errno != .NONE { + return {}, Create_Socket_Error(errno) + } + return _wrap_os_socket(sock, protocol), nil +} + @(private) -_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (skt: TCP_Socket, err: Network_Error) { +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (tcp_sock: TCP_Socket, err: Network_Error) { + errno: linux.Errno if endpoint.port == 0 { return 0, .Port_Required } - - family := family_from_endpoint(endpoint) - sock := create_socket(family, .TCP) or_return - skt = sock.(TCP_Socket) - + // Create new TCP socket + os_sock: linux.Fd + os_sock, errno = linux.socket(_unwrap_os_family(family_from_endpoint(endpoint)), .STREAM, {}, .TCP) + if errno != .NONE { + // TODO(flysand): should return invalid file descriptor here casted as TCP_Socket + return {}, Create_Socket_Error(errno) + } // NOTE(tetra): This is so that if we crash while the socket is open, we can // bypass the cooldown period, and allow the next run of the program to // use the same address immediately. - _ = set_option(skt, .Reuse_Address, true) - - sockaddr := _endpoint_to_sockaddr(endpoint) - res := os.connect(os.Socket(skt), (^os.SOCKADDR)(&sockaddr), size_of(sockaddr)) - if res != os.ERROR_NONE { - err = Dial_Error(res) - return + reuse_addr: b32 = true + _ = linux.setsockopt(os_sock, linux.SOL_SOCKET, linux.Socket_Option.REUSEADDR, &reuse_addr) + addr := _unwrap_os_addr(endpoint) + errno = linux.connect(linux.Fd(tcp_sock), &addr) + if errno != .NONE { + return cast(TCP_Socket) os_sock, Dial_Error(errno) } - - if options.no_delay { - _ = _set_option(sock, .TCP_Nodelay, true) // NOTE(tetra): Not vital to succeed; error ignored - } - - return + // NOTE(tetra): Not vital to succeed; error ignored + no_delay: b32 = cast(b32) options.no_delay + _ = linux.setsockopt(os_sock, linux.SOL_TCP, linux.Socket_TCP_Option.NODELAY, &no_delay) + return cast(TCP_Socket) os_sock, nil } @(private) -_bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Network_Error) { - sockaddr := _endpoint_to_sockaddr(ep) - s := any_socket_to_socket(skt) - res := os.bind(os.Socket(s), (^os.SOCKADDR)(&sockaddr), size_of(sockaddr)) - if res != os.ERROR_NONE { - err = Bind_Error(res) +_bind :: proc(sock: Any_Socket, endpoint: Endpoint) -> (Network_Error) { + addr := _unwrap_os_addr(endpoint) + errno := linux.bind(_unwrap_os_socket(sock), &addr) + if errno != .NONE { + return Bind_Error(errno) } - return + return nil } @(private) -_listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_Socket, err: Network_Error) { +_listen_tcp :: proc(endpoint: Endpoint, backlog := 1000) -> (TCP_Socket, Network_Error) { + errno: linux.Errno assert(backlog > 0 && i32(backlog) < max(i32)) - - family := family_from_endpoint(interface_endpoint) - sock := create_socket(family, .TCP) or_return - skt = sock.(TCP_Socket) - + // Figure out the address family and address of the endpoint + ep_family := _unwrap_os_family(family_from_endpoint(endpoint)) + ep_address := _unwrap_os_addr(endpoint) + // Create TCP socket + os_sock: linux.Fd + os_sock, errno = linux.socket(ep_family, .STREAM, {}, .TCP) + if errno != .NONE { + // TODO(flysand): should return invalid file descriptor here casted as TCP_Socket + return {}, Create_Socket_Error(errno) + } // NOTE(tetra): This is so that if we crash while the socket is open, we can // bypass the cooldown period, and allow the next run of the program to // use the same address immediately. // // TODO(tetra, 2022-02-15): Confirm that this doesn't mean other processes can hijack the address! - set_option(sock, .Reuse_Address, true) or_return - - bind(sock, interface_endpoint) or_return - - res := os.listen(os.Socket(skt), backlog) - if res != os.ERROR_NONE { - err = Listen_Error(res) - return + do_reuse_addr: b32 = true + errno = linux.setsockopt(os_sock, linux.SOL_SOCKET, linux.Socket_Option.REUSEADDR, &do_reuse_addr) + if errno != .NONE { + return cast(TCP_Socket) os_sock, Listen_Error(errno) } - - return + // Bind the socket to endpoint address + errno = linux.bind(os_sock, &ep_address) + if errno != .NONE { + return cast(TCP_Socket) os_sock, Bind_Error(errno) + } + // Listen on bound socket + errno = linux.listen(os_sock, cast(i32) backlog) + if errno != .NONE { + return cast(TCP_Socket) os_sock, Listen_Error(errno) + } + return cast(TCP_Socket) os_sock, nil } @(private) -_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) { - sockaddr: os.SOCKADDR_STORAGE_LH - sockaddrlen := c.int(size_of(sockaddr)) - - client_sock, ok := os.accept(os.Socket(sock), cast(^os.SOCKADDR) &sockaddr, &sockaddrlen) - if ok != os.ERROR_NONE { - err = Accept_Error(ok) - return +_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (tcp_client: TCP_Socket, endpoint: Endpoint, err: Network_Error) { + addr: linux.Sock_Addr_Any + client_sock, errno := linux.accept(linux.Fd(sock), &addr) + if errno != .NONE { + return {}, {}, Accept_Error(errno) } - client = TCP_Socket(client_sock) - source = _sockaddr_storage_to_endpoint(&sockaddr) - if options.no_delay { - _ = _set_option(client, .TCP_Nodelay, true) // NOTE(tetra): Not vital to succeed; error ignored - } - return + // NOTE(tetra): Not vital to succeed; error ignored + val: b32 = cast(b32) options.no_delay + _ = linux.setsockopt(client_sock, linux.SOL_TCP, linux.Socket_TCP_Option.NODELAY, &val) + return TCP_Socket(client_sock), _wrap_os_addr(addr), nil } @(private) -_close :: proc(skt: Any_Socket) { - s := any_socket_to_socket(skt) - os.close(os.Handle(os.Socket(s))) +_close :: proc(sock: Any_Socket) { + linux.close(_unwrap_os_socket(sock)) } @(private) -_recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) { +_recv_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { if len(buf) <= 0 { - return + return 0, nil } - res, ok := os.recv(os.Socket(skt), buf, 0) - if ok != os.ERROR_NONE { - err = TCP_Recv_Error(ok) - return + bytes_read, errno := linux.recv(linux.Fd(tcp_sock), buf, {}) + if errno != .NONE { + return 0, TCP_Recv_Error(errno) } - return int(res), nil + return int(bytes_read), nil } @(private) -_recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) { +_recv_udp :: proc(udp_sock: UDP_Socket, buf: []byte) -> (int, Endpoint, Network_Error) { if len(buf) <= 0 { - return + // NOTE(flysand): It was returning no error, I didn't change anything + return 0, {}, {} } - - from: os.SOCKADDR_STORAGE_LH = --- - fromsize := c.int(size_of(from)) - // NOTE(tetra): On Linux, if the buffer is too small to fit the entire datagram payload, the rest is silently discarded, // and no error is returned. // However, if you pass MSG_TRUNC here, 'res' will be the size of the incoming message, rather than how much was read. // We can use this fact to detect this condition and return .Buffer_Too_Small. - res, ok := os.recvfrom(os.Socket(skt), buf, os.MSG_TRUNC, cast(^os.SOCKADDR) &from, &fromsize) - if ok != os.ERROR_NONE { - err = UDP_Recv_Error(ok) - return + from_addr: linux.Sock_Addr_Any + bytes_read, errno := linux.recvfrom(linux.Fd(udp_sock), buf, {.TRUNC}, &from_addr) + if errno != .NONE { + return 0, {}, UDP_Recv_Error(errno) } - - bytes_read = int(res) - remote_endpoint = _sockaddr_storage_to_endpoint(&from) - if bytes_read > len(buf) { // NOTE(tetra): The buffer has been filled, with a partial message. - bytes_read = len(buf) - err = .Buffer_Too_Small + return len(buf), {}, .Buffer_Too_Small } - - return + return bytes_read, _wrap_os_addr(from_addr), nil } @(private) -_send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) { - for bytes_written < len(buf) { - limit := min(int(max(i32)), len(buf) - bytes_written) - remaining := buf[bytes_written:][:limit] - res, ok := os.send(os.Socket(skt), remaining, 0) - if ok != os.ERROR_NONE { - err = TCP_Send_Error(ok) - return +_send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { + total_written := 0 + for total_written < len(buf) { + limit := min(int(max(i32)), len(buf) - total_written) + remaining := buf[total_written:][:limit] + res, errno := linux.send(linux.Fd(tcp_sock), remaining, {}) + if errno != .NONE { + return total_written, TCP_Send_Error(errno) } - bytes_written += int(res) + total_written += int(res) } - return + return total_written, nil } @(private) -_send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) { - toaddr := _endpoint_to_sockaddr(to) - res, os_err := os.sendto(os.Socket(skt), buf, 0, cast(^os.SOCKADDR) &toaddr, size_of(toaddr)) - if os_err != os.ERROR_NONE { - err = UDP_Send_Error(os_err) - return +_send_udp :: proc(udp_sock: UDP_Socket, buf: []byte, to: Endpoint) -> (int, Network_Error) { + to_addr := _unwrap_os_addr(to) + bytes_written, errno := linux.sendto(linux.Fd(udp_sock), buf, {}, &to_addr) + if errno != .NONE { + return bytes_written, UDP_Send_Error(errno) } - bytes_written = int(res) - return + return int(bytes_written), nil } @(private) -_shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { - s := any_socket_to_socket(skt) - res := os.shutdown(os.Socket(s), int(manner)) - if res != os.ERROR_NONE { - return Shutdown_Error(res) +_shutdown :: proc(sock: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { + os_sock := _unwrap_os_socket(sock) + errno := linux.shutdown(os_sock, cast(linux.Shutdown_How) manner) + if errno != .NONE { + return Shutdown_Error(errno) } - return + return nil } +// TODO(flysand): Figure out what we want to do with this on core:sys/ level. @(private) -_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { - level := os.SOL_SOCKET if option != .TCP_Nodelay else os.IPPROTO_TCP - +_set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { + level: int + if option == .TCP_Nodelay { + level = int(linux.SOL_TCP) + } else { + level = int(linux.SOL_SOCKET) + } + os_sock := _unwrap_os_socket(sock) // NOTE(tetra, 2022-02-15): On Linux, you cannot merely give a single byte for a bool; // it _has_ to be a b32. - // I haven't tested if you can give more than that. + // I haven't tested if you can give more than that. <-- (flysand) probably not, posix explicitly specifies an int bool_value: b32 int_value: i32 - timeval_value: os.Timeval - - ptr: rawptr - len: os.socklen_t - + timeval_value: linux.Time_Val + errno: linux.Errno switch option { case .Reuse_Address, @@ -258,7 +311,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca .Out_Of_Bounds_Data_Inline, .TCP_Nodelay: // TODO: verify whether these are options or not on Linux - // .Broadcast, + // .Broadcast, <-- yes // .Conditional_Accept, // .Dont_Linger: switch x in value { @@ -274,8 +327,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca case: panic("set_option() value must be a boolean here", loc) } - ptr = &bool_value - len = size_of(bool_value) + errno = linux.setsockopt(os_sock, level, int(option), &bool_value) case .Linger, .Send_Timeout, @@ -283,125 +335,49 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca t, ok := value.(time.Duration) if !ok do panic("set_option() value must be a time.Duration here", loc) - micros := i64(time.duration_microseconds(t)) - timeval_value.microseconds = int(micros % 1e6) - timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6 - - ptr = &timeval_value - len = size_of(timeval_value) + micros := cast(i64) (time.duration_microseconds(t)) + timeval_value.microseconds = cast(int) (micros % 1e6) + timeval_value.seconds = cast(int) ((micros - i64(timeval_value.microseconds)) / 1e6) + errno = linux.setsockopt(os_sock, level, int(option), &timeval_value) case .Receive_Buffer_Size, .Send_Buffer_Size: // TODO: check for out of range values and return .Value_Out_Of_Range? switch i in value { - case i8, u8: i2 := i; int_value = os.socklen_t((^u8)(&i2)^) - case i16, u16: i2 := i; int_value = os.socklen_t((^u16)(&i2)^) - case i32, u32: i2 := i; int_value = os.socklen_t((^u32)(&i2)^) - case i64, u64: i2 := i; int_value = os.socklen_t((^u64)(&i2)^) - case i128, u128: i2 := i; int_value = os.socklen_t((^u128)(&i2)^) - case int, uint: i2 := i; int_value = os.socklen_t((^uint)(&i2)^) + case i8, u8: i2 := i; int_value = i32((^u8)(&i2)^) + case i16, u16: i2 := i; int_value = i32((^u16)(&i2)^) + case i32, u32: i2 := i; int_value = i32((^u32)(&i2)^) + case i64, u64: i2 := i; int_value = i32((^u64)(&i2)^) + case i128, u128: i2 := i; int_value = i32((^u128)(&i2)^) + case int, uint: i2 := i; int_value = i32((^uint)(&i2)^) case: panic("set_option() value must be an integer here", loc) } - ptr = &int_value - len = size_of(int_value) + errno = linux.setsockopt(os_sock, level, int(option), &int_value) } - - skt := any_socket_to_socket(s) - res := os.setsockopt(os.Socket(skt), int(level), int(option), ptr, len) - if res != os.ERROR_NONE { - return Socket_Option_Error(res) + if errno != .NONE { + return Socket_Option_Error(errno) } - return nil } @(private) -_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { - socket := any_socket_to_socket(socket) - - flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0) - if getfl_err != os.ERROR_NONE { - return Set_Blocking_Error(getfl_err) +_set_blocking :: proc(sock: Any_Socket, should_block: bool) -> (err: Network_Error) { + errno: linux.Errno + flags: linux.Open_Flags + os_sock := _unwrap_os_socket(sock) + flags, errno = linux.fcntl(os_sock, linux.F_GETFL) + if errno != .NONE { + return Set_Blocking_Error(errno) } - if should_block { - flags &= ~int(os.O_NONBLOCK) + flags &= ~{.NONBLOCK} } else { - flags |= int(os.O_NONBLOCK) + flags |= {.NONBLOCK} } - - _, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags) - if setfl_err != os.ERROR_NONE { - return Set_Blocking_Error(setfl_err) + errno = linux.fcntl(os_sock, linux.F_SETFL, flags) + if errno != .NONE { + return Set_Blocking_Error(errno) } - return nil } - -@(private) -_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH) { - switch a in ep.address { - case IP4_Address: - (^os.sockaddr_in)(&sockaddr)^ = os.sockaddr_in { - sin_port = u16be(ep.port), - sin_addr = transmute(os.in_addr) a, - sin_family = u16(os.AF_INET), - } - return - case IP6_Address: - (^os.sockaddr_in6)(&sockaddr)^ = os.sockaddr_in6 { - sin6_port = u16be(ep.port), - sin6_addr = transmute(os.in6_addr) a, - sin6_family = u16(os.AF_INET6), - } - return - } - unreachable() -} - -@(private) -_sockaddr_storage_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endpoint) { - switch native_addr.ss_family { - case u16(os.AF_INET): - addr := cast(^os.sockaddr_in) native_addr - port := int(addr.sin_port) - ep = Endpoint { - address = IP4_Address(transmute([4]byte) addr.sin_addr), - port = port, - } - case u16(os.AF_INET6): - addr := cast(^os.sockaddr_in6) native_addr - port := int(addr.sin6_port) - ep = Endpoint { - address = IP6_Address(transmute([8]u16be) addr.sin6_addr), - port = port, - } - case: - panic("native_addr is neither IP4 or IP6 address") - } - return -} - -@(private) -_sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint) { - switch native_addr.sa_family { - case u16(os.AF_INET): - addr := cast(^os.sockaddr_in) native_addr - port := int(addr.sin_port) - ep = Endpoint { - address = IP4_Address(transmute([4]byte) addr.sin_addr), - port = port, - } - case u16(os.AF_INET6): - addr := cast(^os.sockaddr_in6) native_addr - port := int(addr.sin6_port) - ep = Endpoint { - address = IP6_Address(transmute([8]u16be) addr.sin6_addr), - port = port, - } - case: - panic("native_addr is neither IP4 or IP6 address") - } - return -} diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 51a14ab44..aabf42574 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -8,7 +8,18 @@ import "core:strings" import "core:c" import "core:strconv" import "core:intrinsics" -import "core:sys/unix" + +// NOTE(flysand): For compatibility we'll make core:os package +// depend on the old (scheduled for removal) linux package. +// Seeing that there are plans for os2, I'm imagining that *that* +// package should inherit the new sys functionality. +// The reasons for these are as follows: +// 1. It's very hard to update this package without breaking *a lot* of code. +// 2. os2 is not stable anyways, so we can break compatibility all we want +// It might be weird to bring up compatibility when Odin in it's nature isn't +// all that about compatibility. But we don't want to push experimental changes +// and have people's code break while it's still work in progress. +import unix "core:sys/unix" Handle :: distinct i32 Pid :: distinct i32 diff --git a/core/sync/futex_linux.odin b/core/sync/futex_linux.odin index 947d61cdf..fe57c12ed 100644 --- a/core/sync/futex_linux.odin +++ b/core/sync/futex_linux.odin @@ -2,95 +2,60 @@ //+build linux package sync -import "core:c" import "core:time" -import "core:intrinsics" -import "core:sys/unix" +import "core:sys/linux" -FUTEX_WAIT :: 0 -FUTEX_WAKE :: 1 -FUTEX_PRIVATE_FLAG :: 128 - -FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) -FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) - -ESUCCESS :: 0 -EINTR :: -4 -EAGAIN :: -11 -EFAULT :: -14 -EINVAL :: -22 -ETIMEDOUT :: -110 - -get_errno :: proc "contextless" (r: int) -> int { - if -4096 < r && r < 0 { - return r - } - return 0 -} - -internal_futex :: proc "contextless" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int { - code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0)) - return get_errno(code) -} - - -_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool { - err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil) - switch err { - case ESUCCESS, EINTR, EAGAIN, EINVAL: - // okay - case ETIMEDOUT: +_futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool { + errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAIT, {.PRIVATE}, expected) + if errno == .ETIMEDOUT { return false - case EFAULT: - fallthrough + } + #partial switch errno { + case .NONE, .EINTR, .EAGAIN: + return true case: + // TODO(flysand): More descriptive panic messages based on the vlaue of `errno` _panic("futex_wait failure") } - return true } -_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool { +_futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, duration: time.Duration) -> bool { if duration <= 0 { return false } - - timespec_t :: struct { - tv_sec: c.long, - tv_nsec: c.long, - } - - err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, ×pec_t{ - tv_sec = (c.long)(duration/1e9), - tv_nsec = (c.long)(duration%1e9), + errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAIT, {.PRIVATE}, expected, &linux.Time_Spec{ + time_sec = cast(uint)(duration/1e9), + time_nsec = cast(uint)(duration%1e9), }) - switch err { - case ESUCCESS, EINTR, EAGAIN, EINVAL: - // okay - case ETIMEDOUT: + if errno == .ETIMEDOUT { return false - case EFAULT: - fallthrough + } + #partial switch errno { + case .NONE, .EINTR, .EAGAIN: + return true case: _panic("futex_wait_with_timeout failure") } - return true } - -_futex_signal :: proc "contextless" (f: ^Futex) { - err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil) - switch err { - case ESUCCESS, EINVAL, EFAULT: - // okay +_futex_signal :: proc "contextless" (futex: ^Futex) { + _, errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAKE, {.PRIVATE}, 1) + #partial switch errno { + case .NONE: + return case: _panic("futex_wake_single failure") } } -_futex_broadcast :: proc "contextless" (f: ^Futex) { - err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil) - switch err { - case ESUCCESS, EINVAL, EFAULT: - // okay + +_futex_broadcast :: proc "contextless" (futex: ^Futex) { + // NOTE(flysand): This code was kinda funny and I don't want to remove it, but here I will + // record history of what has been in here before + // FUTEX_WAKE_PRIVATE | FUTEX_WAKE + _, errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAKE, {.PRIVATE}, max(i32)) + #partial switch errno { + case .NONE: + return case: _panic("_futex_wake_all failure") } diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin index 1e75891df..aa7a8b4b2 100644 --- a/core/sync/primitives_linux.odin +++ b/core/sync/primitives_linux.odin @@ -2,8 +2,8 @@ //+private package sync -import "core:sys/unix" +import "core:sys/linux" _current_thread_id :: proc "contextless" () -> int { - return unix.sys_gettid() + return cast(int) linux.gettid() } diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin index e9cc1dbc9..14961c2a8 100644 --- a/core/sys/info/platform_linux.odin +++ b/core/sys/info/platform_linux.odin @@ -1,40 +1,34 @@ // +build linux package sysinfo -import "core:c" -import sys "core:sys/unix" import "core:intrinsics" import "core:runtime" -import "core:os" import "core:strings" import "core:strconv" +import "core:sys/linux" + @(private) version_string_buf: [1024]u8 @(init, private) init_os_version :: proc () { os_version.platform = .Linux - // Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` - fd, err := os.open("/etc/os-release", os.O_RDONLY, 0) - if err != 0 { - return + fd, errno := linux.open("/etc/os-release", {.RDONLY}, {}) + assert(errno == .NONE, "Failed to read /etc/os-release") + defer { + errno := linux.close(fd) + assert(errno == .NONE, "Failed to close the file descriptor") } - defer os.close(fd) - os_release_buf: [2048]u8 - n, read_err := os.read(fd, os_release_buf[:]) - if read_err != 0 { - return - } + n, read_errno := linux.read(fd, os_release_buf[:]) + assert(read_errno == .NONE, "Failed to read data from /etc/os-release") release := string(os_release_buf[:n]) - + // Search the line in the file until we find "PRETTY_NAME=" NEEDLE :: "PRETTY_NAME=\"" pretty_start := strings.index(release, NEEDLE) - b := strings.builder_from_bytes(version_string_buf[:]) - if pretty_start > 0 { for r, i in release[pretty_start + len(NEEDLE):] { if r == '"' { @@ -46,94 +40,48 @@ init_os_version :: proc () { } } } - - NEW_UTS_LEN :: 64 - UTS_Name :: struct { - sys_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`, - node_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`, - release: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`, - version: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`, - machine: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`, - domain_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`, - } - uts: UTS_Name - // Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname - if intrinsics.syscall(sys.SYS_uname, uintptr(&uts)) != 0 { - return - } - + uts: linux.UTS_Name + uname_errno := linux.uname(&uts) + assert(uname_errno == .NONE, "This should never happen!") + // Append the system name (typically "Linux") and kernel release (looks like 6.5.2-arch1-1) strings.write_string(&b, ", ") - strings.write_string(&b, string(cstring(&uts.sys_name[0]))) + strings.write_string(&b, string(cstring(&uts.sysname[0]))) strings.write_rune(&b, ' ') - l := strings.builder_len(b) strings.write_string(&b, string(cstring(&uts.release[0]))) - - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - // Parse kernel version, as substrings of the version info in `version_string_buf` + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator) if len(version_bits) > 1 { os_version.version = version_bits[1] } - // Parse major, minor, patch from release info triplet := strings.split(version_bits[0], ".", context.temp_allocator) if len(triplet) == 3 { major, major_ok := strconv.parse_int(triplet[0]) minor, minor_ok := strconv.parse_int(triplet[1]) patch, patch_ok := strconv.parse_int(triplet[2]) - if major_ok && minor_ok && patch_ok { os_version.major = major os_version.minor = minor os_version.patch = patch } } - // Finish the string os_version.as_string = strings.to_string(b) } -Sys_Info :: struct { - uptime: c.long, // Seconds since boot - loads: [3]c.long, // 1, 5, 15 minute load averages - totalram: c.ulong, // Total usable main memory size - freeram: c.ulong, // Available memory size - sharedram: c.ulong, // Amount of shared memory - bufferram: c.ulong, // Memory used by buffers - totalswap: c.ulong, // Total swap space size - freeswap: c.ulong, // Swap space still available - procs: c.ushort, // Number of current processes - totalhigh: c.ulong, // Total high memory size - freehigh: c.ulong, // Available high memory size - mem_unit: c.int, // Memory unit size in bytes - _padding: [20 - (2 * size_of(c.long)) - size_of(c.int)]u8, -} - -get_sysinfo :: proc "c" () -> (res: Sys_Info, ok: bool) { - si: Sys_Info - err := intrinsics.syscall(sys.SYS_sysinfo, uintptr(rawptr(&si))) - if err != 0 { - // Unable to retrieve sysinfo - return {}, false - } - return si, true -} - @(init) init_ram :: proc() { // Retrieve RAM info using `sysinfo` - si, ok := get_sysinfo() - if !ok { - return - } - + sys_info: linux.Sys_Info + errno := linux.sysinfo(&sys_info) + assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") ram = RAM{ - total_ram = int(si.totalram) * int(si.mem_unit), - free_ram = int(si.freeram) * int(si.mem_unit), - total_swap = int(si.totalswap) * int(si.mem_unit), - free_swap = int(si.freeswap) * int(si.mem_unit), + total_ram = int(sys_info.totalram) * int(sys_info.mem_unit), + free_ram = int(sys_info.freeram) * int(sys_info.mem_unit), + total_swap = int(sys_info.totalswap) * int(sys_info.mem_unit), + free_swap = int(sys_info.freeswap) * int(sys_info.mem_unit), } } \ No newline at end of file diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin new file mode 100644 index 000000000..b6b22dfdb --- /dev/null +++ b/core/sys/linux/bits.odin @@ -0,0 +1,1400 @@ +package linux + + +/// Represents an error returned by most of syscalls +Errno :: enum i32 { + NONE = 0, + // Errno-base + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EAGAIN = 11, + ENOMEM = 12, + EACCES = 13, + EFAULT = 14, + ENOTBLK = 15, + EBUSY = 16, + EEXIST = 17, + EXDEV = 18, + ENODEV = 19, + ENOTDIR = 20, + EISDIR = 21, + EINVAL = 22, + ENFILE = 23, + EMFILE = 24, + ENOTTY = 25, + ETXTBSY = 26, + EFBIG = 27, + ENOSPC = 28, + ESPIPE = 29, + EROFS = 30, + EMLINK = 31, + EPIPE = 32, + EDOM = 33, + ERANGE = 34, + // Linux + EDEADLK = 35, + ENAMETOOLONG = 36, + ENOLCK = 37, + ENOSYS = 38, + ENOTEMPTY = 39, + ELOOP = 40, + ENOMSG = 42, + EIDRM = 43, + ECHRNG = 44, + EL2NSYNC = 45, + EL3HLT = 46, + EL3RST = 47, + ELNRNG = 48, + EUNATCH = 49, + ENOCSI = 50, + EL2HLT = 51, + EBADE = 52, + EBADR = 53, + EXFULL = 54, + ENOANO = 55, + EBADRQC = 56, + EBADSLT = 57, + EBFONT = 59, + ENOSTR = 60, + ENODATA = 61, + ETIME = 62, + ENOSR = 63, + ENONET = 64, + ENOPKG = 65, + EREMOTE = 66, + ENOLINK = 67, + EADV = 68, + ESRMNT = 69, + ECOMM = 70, + EPROTO = 71, + EMULTIHOP = 72, + EDOTDOT = 73, + EBADMSG = 74, + EOVERFLOW = 75, + ENOTUNIQ = 76, + EBADFD = 77, + EREMCHG = 78, + ELIBACC = 79, + ELIBBAD = 80, + ELIBSCN = 81, + ELIBMAX = 82, + ELIBEXEC = 83, + EILSEQ = 84, + ERESTART = 85, + ESTRPIPE = 86, + EUSERS = 87, + ENOTSOCK = 88, + EDESTADDRREQ = 89, + EMSGSIZE = 90, + EPROTOTYPE = 91, + ENOPROTOOPT = 92, + EPROTONOSUPPORT = 93, + ESOCKTNOSUPPORT = 94, + EOPNOTSUPP = 95, + EPFNOSUPPORT = 96, + EAFNOSUPPORT = 97, + EADDRINUSE = 98, + EADDRNOTAVAIL = 99, + ENETDOWN = 100, + ENETUNREACH = 101, + ENETRESET = 102, + ECONNABORTED = 103, + ECONNRESET = 104, + ENOBUFS = 105, + EISCONN = 106, + ENOTCONN = 107, + ESHUTDOWN = 108, + ETOOMANYREFS = 109, + ETIMEDOUT = 110, + ECONNREFUSED = 111, + EHOSTDOWN = 112, + EHOSTUNREACH = 113, + EALREADY = 114, + EINPROGRESS = 115, + ESTALE = 116, + EUCLEAN = 117, + ENOTNAM = 118, + ENAVAIL = 119, + EISNAM = 120, + EREMOTEIO = 121, + EDQUOT = 122, + ENOMEDIUM = 123, + EMEDIUMTYPE = 124, + ECANCELED = 125, + ENOKEY = 126, + EKEYEXPIRED = 127, + EKEYREVOKED = 128, + EKEYREJECTED = 129, + EOWNERDEAD = 130, + ENOTRECOVERABLE = 131, + ERFKILL = 132, + EHWPOISON = 133, + // Errno aliases + EWOULDBLOCK = EAGAIN, + EDEADLOCK = EDEADLK, +} + + +/// Bits for Open_Flags +Open_Flags_Bits :: enum { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREAT = 6, + EXCL = 7, + NOCTTY = 8, + TRUNC = 9, + APPEND = 10, + NONBLOCK = 11, + DSYNC = 12, + ASYNC = 13, + DIRECT = 14, + DIRECTORY = 16, + NOFOLLOW = 17, + NOATIME = 18, + CLOEXEC = 19, + PATH = 21, +} + +/// Bits for FD_Flags bitset +FD_Flags_Bits :: enum { + SYMLINK_NOFOLLOW = 8, + REMOVEDIR = 9, + EACCESS = 9, + SYMLINK_FOLLOW = 10, + NO_AUTOMOUNT = 11, + EMPTY_PATH = 12, + STATX_FORCE_SYNC = 13, + STATX_DONT_SYNC = 14, + RECURSIVE = 15, +} + +/// The bits for the Mode bitset. +Mode_Bits :: enum { + IXOTH = 0, // 0o0000001 + IWOTH = 1, // 0o0000002 + IROTH = 2, // 0o0000004 + IXGRP = 3, // 0o0000010 + IWGRP = 4, // 0o0000020 + IRGRP = 5, // 0o0000040 + IXUSR = 6, // 0o0000100 + IWUSR = 7, // 0o0000200 + IRUSR = 8, // 0o0000400 + ISVTX = 9, // 0o0001000 + ISGID = 10, // 0o0002000 + ISUID = 11, // 0o0004000 + IFFIFO = 12, // 0o0010000 + IFCHR = 13, // 0o0020000 + IFDIR = 14, // 0o0040000 + IFREG = 15, // 0o0100000 +} + +/// The bits used by the Statx_Mask bitset +Statx_Mask_Bits :: enum { + TYPE = 0, + MODE = 1, + NLINK = 2, + UID = 3, + GID = 4, + ATIME = 5, + MTIME = 6, + CTIME = 7, + INO = 8, + SIZE = 9, + BLOCKS = 10, + BTIME = 11, + MNT_ID = 12, + DIOALIGN = 13, +} + +/// Bits found in Statx_Attr bitset +/// You should not use these directly +Statx_Attr_Bits :: enum { + COMPRESSED = 2, // 0x00000004 + IMMUTABLE = 4, // 0x00000010 + APPEND = 5, // 0x00000020 + NODUMP = 6, // 0x00000040 + ENCRYPTED = 11, // 0x00000800 + AUTOMOUNT = 12, // 0x00001000 + MOUNT_ROOT = 13, // 0x00002000 + VERITY = 20, // 0x00100000 + DAX = 21, // 0x00200000 +} + +/// Magic bits for filesystems returned by Stat_FS +FS_Magic :: enum u32 { + ADFS_SUPER_MAGIC = 0xadf5, + AFFS_SUPER_MAGIC = 0xadff, + AFS_SUPER_MAGIC = 0x5346414f, + ANON_INODE_FS_MAGIC = 0x09041934, + AUTOFS_SUPER_MAGIC = 0x0187, + BDEVFS_MAGIC = 0x62646576, + BEFS_SUPER_MAGIC = 0x42465331, + BFS_MAGIC = 0x1badface, + BINFMTFS_MAGIC = 0x42494e4d, + BPF_FS_MAGIC = 0xcafe4a11, + BTRFS_SUPER_MAGIC = 0x9123683e, + BTRFS_TEST_MAGIC = 0x73727279, + CGROUP_SUPER_MAGIC = 0x27e0eb, + CGROUP2_SUPER_MAGIC = 0x63677270, + CIFS_MAGIC_NUMBER = 0xff534d42, + CODA_SUPER_MAGIC = 0x73757245, + COH_SUPER_MAGIC = 0x012ff7b7, + CRAMFS_MAGIC = 0x28cd3d45, + DEBUGFS_MAGIC = 0x64626720, + DEVFS_SUPER_MAGIC = 0x1373, + DEVPTS_SUPER_MAGIC = 0x1cd1, + ECRYPTFS_SUPER_MAGIC = 0xf15f, + EFIVARFS_MAGIC = 0xde5e81e4, + EFS_SUPER_MAGIC = 0x00414a53, + EXT_SUPER_MAGIC = 0x137d, + EXT2_OLD_SUPER_MAGIC = 0xef51, + EXT2_SUPER_MAGIC = 0xef53, + EXT3_SUPER_MAGIC = 0xef53, + EXT4_SUPER_MAGIC = 0xef53, + F2FS_SUPER_MAGIC = 0xf2f52010, + FUSE_SUPER_MAGIC = 0x65735546, + FUTEXFS_SUPER_MAGIC = 0xbad1dea, + HFS_SUPER_MAGIC = 0x4244, + HOSTFS_SUPER_MAGIC = 0x00c0ffee, + HPFS_SUPER_MAGIC = 0xf995e849, + HUGETLBFS_MAGIC = 0x958458f6, + ISOFS_SUPER_MAGIC = 0x9660, + JFFS2_SUPER_MAGIC = 0x72b6, + JFS_SUPER_MAGIC = 0x3153464a, + MINIX_SUPER_MAGIC = 0x137f, + MINIX_SUPER_MAGIC2 = 0x138f, + MINIX2_SUPER_MAGIC = 0x2468, + MINIX2_SUPER_MAGIC2 = 0x2478, + MINIX3_SUPER_MAGIC = 0x4d5a, + MQUEUE_MAGIC = 0x19800202, + MSDOS_SUPER_MAGIC = 0x4d44, + MTD_INODE_FS_MAGIC = 0x11307854, + NCP_SUPER_MAGIC = 0x564c, + NFS_SUPER_MAGIC = 0x6969, + NILFS_SUPER_MAGIC = 0x3434, + NSFS_MAGIC = 0x6e736673, + NTFS_SB_MAGIC = 0x5346544e, + OCFS2_SUPER_MAGIC = 0x7461636f, + OPENPROM_SUPER_MAGIC = 0x9fa1, + OVERLAYFS_SUPER_MAGIC = 0x794c7630, + PIPEFS_MAGIC = 0x50495045, + PROC_SUPER_MAGIC = 0x9fa0, + PSTOREFS_MAGIC = 0x6165676c, + QNX4_SUPER_MAGIC = 0x002f, + QNX6_SUPER_MAGIC = 0x68191122, + RAMFS_MAGIC = 0x858458f6, + REISERFS_SUPER_MAGIC = 0x52654973, + ROMFS_MAGIC = 0x7275, + SECURITYFS_MAGIC = 0x73636673, + SELINUX_MAGIC = 0xf97cff8c, + SMACK_MAGIC = 0x43415d53, + SMB_SUPER_MAGIC = 0x517b, + SMB2_MAGIC_NUMBER = 0xfe534d42, + SOCKFS_MAGIC = 0x534f434b, + SQUASHFS_MAGIC = 0x73717368, + SYSFS_MAGIC = 0x62656572, + SYSV2_SUPER_MAGIC = 0x012ff7b6, + SYSV4_SUPER_MAGIC = 0x012ff7b5, + TMPFS_MAGIC = 0x01021994, + TRACEFS_MAGIC = 0x74726163, + UDF_SUPER_MAGIC = 0x15013346, + UFS_MAGIC = 0x00011954, + USBDEVICE_SUPER_MAGIC = 0x9fa2, + V9FS_MAGIC = 0x01021997, + VXFS_SUPER_MAGIC = 0xa501fcf5, + XENFS_SUPER_MAGIC = 0xabba1974, + XENIX_SUPER_MAGIC = 0x012ff7b4, + XFS_SUPER_MAGIC = 0x58465342, + _XIAFS_SUPER_MAGIC = 0x012fd16d, +} + +/// Bits for FS_Flags bitset +FS_Flags_Bits :: enum { + RDONLY = 0, + NOSUID = 1, + NODEV = 2, + NOEXEC = 3, + SYNCHRONOUS = 4, + VALID = 5, + MANDLOCK = 6, + NOATIME = 10, + NODIRATIME = 11, + RELATIME = 12, + NOSYMFOLLOW = 13, +} + +Seek_Whence :: enum i16 { + SET = 0, + CUR = 1, + END = 2, + DATA = 3, + HOLE = 4, +} + +/// Bits for Close_Range_Flags +Close_Range_Flags_Bits :: enum { + CLOEXEC = 2, + UNSHARE = 1, +} + +/// Bits for Rename_Flags +Rename_Flags_Bits :: enum { + EXCHANGE = 1, + NOREPLACE = 0, + WHITEOUT = 2, +} + +/// Type of the file in a directory entry +Dirent_Type :: enum u8 { + UNKNOWN = 0, + FIFO = 1, + CHR = 2, + DIR = 4, + BLK = 6, + REG = 8, + LNK = 10, + SOCK = 12, + WHT = 14, +} + +/// Type of a lock for fcntl.2 +FLock_Type :: enum i16 { + RDLCK = 0, + WRLCK = 1, + UNLCK = 2, +} + +/// Bits for FD_Notifications +FD_Notifications_Bits :: enum { + ACCESS = 0, + MODIFY = 1, + CREATE = 2, + DELETE = 3, + RENAME = 4, + ATTRIB = 5, + MULTISHOT = 31, +} + +/// Bits for seal +Seal_Bits :: enum { + SEAL = 0, + SHRINK = 1, + GROW = 2, + WRITE = 3, + FUTURE_WRITE = 4, +} + +RW_Hint :: enum u64 { + WRITE_LIFE_NOT_SET = 0, + WRITE_LIFE_NONE = 1, + WRITE_LIFE_SHORT = 2, + WRITE_LIFE_MEDIUM = 3, + WRITE_LIFE_LONG = 4, + WRITE_LIFE_EXTREME = 5, +} + +FD_Lease :: enum { + RDLCK = 0, + WRLCK = 1, + UNLCK = 2, +} + +/// Kind of owner for FD_Owner +F_Owner_Type :: enum i32 { + OWNER_TID = 0, + OWNER_PID = 1, + OWNER_PGRP = 2, +} + +/// Command for fcntl.2 +FCntl_Command :: enum { + DUPFD = 0, + GETFD = 1, + SETFD = 2, + GETFL = 3, + SETFL = 4, + GETLK = 5, + SETLK = 6, + SETLKW = 7, + SETOWN = 8, + GETOWN = 9, + SETSIG = 10, + GETSIG = 11, + SETOWN_EX = 15, + GETOWN_EX = 16, + // OFD_GETLK = 36, + // OFD_SETLK = 37, + // OFD_SETLKW = 38, + SETLEASE = 1024, + GETLEASE = 1025, + NOTIFY = 1026, + DUPFD_CLOEXEC = 1030, + SETPIPE_SZ = 1031, + GETPIPE_SZ = 1032, + ADD_SEALS = 1033, + GET_SEALS = 1034, + GET_RW_HINT = 1035, + SET_RW_HINT = 1036, + GET_FILE_RW_HINT = 1037, + SET_FILE_RW_HINT = 1038, + // F_OK = 0, +} + +Fd_Poll_Events_Bits :: enum { + IN = 0, + PRI = 1, + OUT = 2, + ERR = 3, + HUP = 4, + NVAL = 5, + RDNORM = 6, + RDBAND = 7, + WRNORM = 8, + WRBAND = 9, + MSG = 10, + REMOVE = 12, + RDHUP = 13, +} + +/// Bits for Mem_Protection bitfield +Mem_Protection_Bits :: enum{ + READ = 0, + WRITE = 1, + EXEC = 2, + SEM = 3, + // platform-specific section start + ARM64_BTI = 4, + ARM64_MTE = 5, + // platform-specific section end + GROWSDOWN = 24, + GROWSUP = 25, +} + +/// Bits for Map_Flags +Map_Flags_Bits :: enum { + SHARED = 0, + PRIVATE = 1, + SHARED_VALIDATE = 2, + FIXED = 4, + ANONYMOUS = 5, + // platform-dependent section start + X86_32BIT = 6, + X86_ABOVE4G = 7, + // platform-dependent section end + GROWSDOWN = 8, + DENYWRITE = 11, + EXECUTABLE = 12, + LOCKED = 13, + NORESERVE = 14, + POPULATE = 15, + NONBLOCK = 16, + STACK = 17, + HUGETLB = 18, + SYNC = 19, + FIXED_NOREPLACE = 20, + UNINITIALIZED = 26, +} + +/// Bits for MLock_Flags +MLock_Flags_Bits :: enum { + ONFAULT = 0, +} + +/// Bits for MSync_Flags +MSync_Flags_Bits :: enum { + ASYNC = 0, + INVALIDATE = 1, + SYNC = 2, +} + +/// Argument for madvice.2 +MAdvice :: enum { + NORMAL = 0, + RANDOM = 1, + SEQUENTIAL = 2, + WILLNEED = 3, + DONTNEED = 4, + FREE = 8, + REMOVE = 9, + DONTFORK = 10, + DOFORK = 11, + MERGEABLE = 12, + UNMERGEABLE = 13, + HUGEPAGE = 14, + NOHUGEPAGE = 15, + DONTDUMP = 16, + DODUMP = 17, + WIPEONFORK = 18, + KEEPONFORK = 19, + COLD = 20, + PAGEOUT = 21, + POPULATE_READ = 22, + POPULATE_WRITE = 23, + DONTNEED_LOCKED = 24, + COLLAPSE = 25, + HWPOISON = 100, + SOFT_OFFLINE = 101, +} + +/// Bits for PKey_Access_Rights +PKey_Access_Bits :: enum { + DISABLE_ACCESS = 0, + DISABLE_WRITE = 2, +} + +/// Bits for MRemap_Flags +MRemap_Flags_Bits :: enum { + MAYMOVE = 0, + FIXED = 1, + DONTUNMAP = 2, +} + +/// Bits for Get_Random_Flags +Get_Random_Flags_Bits :: enum { + RANDOM = 0, + NONBLOCK = 1, + INSECURE = 2, +} + +/// Bits for Perf_Flags +Perf_Flags_Bits :: enum { + FD_NO_GROUP = 0, + FD_OUTPUT = 1, + PID_CGROUP = 2, + FD_CLOEXEC = 3, +} + +/// Union tag for Perf_Event_Attr struct +Perf_Event_Type :: enum u32 { + HARDWARE = 0, + SOFTWARE = 1, + TRACEPOINT = 2, + HW_CACHE = 3, + RAW = 4, + BREAKPOINT = 5, +} + +Perf_Event_Flags_Bits :: enum u64 { + Disabled = 0, + Inherit = 1, + Pinned = 2, + Exclusive = 3, + Exclude_User = 4, + Exclude_Kernel = 5, + Exclude_HV = 6, + Exclude_Idle = 7, + Mmap = 8, + Comm = 9, + Freq = 10, + Inherit_Stat = 11, + Enable_On_Exec = 12, + Task = 13, + Watermark = 14, + Precise_IP_0 = 15, + Precise_IP_1 = 16, + Mmap_Data = 17, + Sample_Id_All = 18, + Exclude_Host = 19, + Exclude_Guest = 20, + Exclude_Callchain_Kernel = 21, + Exclude_Callchain_User = 22, + Mmap2 = 23, + Comm_Exec = 24, + Use_Clockid = 25, + Context_Switch = 26, + Write_Backward = 27, + Namespaces = 28, + KSymbol = 29, + BPF_Event = 30, + Aux_Output = 31, + CGroup = 32, + Text_Poke = 33, + Build_Id = 34, + Inherit_Thread = 35, + Remove_On_Exec = 36, + Sigtrap = 37, +} + +Perf_Cap_Flags_Bits :: enum u64 { + Bit0 = 0, + Bit0_Is_Deprecated = 1, + User_Rdpmc = 2, + User_Time = 3, + User_Time_Zero = 4, + User_Time_Short = 5, +} + +/// Specifies the type of the hardware event that you want to get info about +Perf_Hardware_Id :: enum u64 { + CPU_CYCLES = 0, + INSTRUCTIONS = 1, + CACHE_REFERENCES = 2, + CACHE_MISSES = 3, + BRANCH_INSTRUCTIONS = 4, + BRANCH_MISSES = 5, + BUS_CYCLES = 6, + STALLED_CYCLES_FRONTEND = 7, + STALLED_CYCLES_BACKEND = 8, + REF_CPU_CYCLES = 9, +} + +/// Specifies the cache for the particular cache event that you want to get info about +Perf_Hardware_Cache_Id :: enum u64 { + L1D = 0, + L1I = 1, + LL = 2, + DTLB = 3, + ITLB = 4, + BPU = 5, + NODE = 6, +} + +/// Specifies the cache op that you want to get info about +Perf_Hardware_Cache_Op_Id :: enum u64 { + READ = 0, + WRITE = 1, + PREFETCH = 2, +} + +/// Specifies the cache operation result that you want to get info about +Perf_Hardware_Cache_Result_Id :: enum u64 { + ACCESS = 0, + MISS = 1, +} + +/// Specifies the particular software event that you want to get info about +Perf_Software_Id :: enum u64 { + CPU_CLOCK = 0, + TASK_CLOCK = 1, + PAGE_FAULTS = 2, + CONTEXT_SWITCHES = 3, + CPU_MIGRATIONS = 4, + PAGE_FAULTS_MIN = 5, + PAGE_FAULTS_MAJ = 6, + ALIGNMENT_FAULTS = 7, + EMULATION_FAULTS = 8, + DUMMY = 9, + BPF_OUTPUT = 10, + CGROUP_SWITCHES = 11, + +} + +/// Specifies which values to include in the sample +Perf_Event_Sample_Type_Bits :: enum { + IP = 0, + TID = 1, + TIME = 2, + ADDR = 3, + READ = 4, + CALLCHAIN = 5, + ID = 6, + CPU = 7, + PERIOD = 8, + STREAM_ID = 9, + RAW = 10, + BRANCH_STACK = 11, + REGS_USER = 12, + STACK_USER = 13, + WEIGHT = 14, + DATA_SRC = 15, + IDENTIFIER = 16, + TRANSACTION = 17, + REGS_INTR = 18, + PHYS_ADDR = 19, + AUX = 20, + CGROUP = 21, + DATA_PAGE_SIZE = 22, + CODE_PAGE_SIZE = 23, + WEIGHT_STRUCT = 24, +} + +/// Describes field sets to include in mmaped page +Perf_Read_Format :: enum { + TOTAL_TIME_ENABLED = 0, + TOTAL_TIME_RUNNING = 1, + ID = 2, + GROUP = 3, + LOST = 4, +} + +/// Chooses the breakpoint type +Hardware_Breakpoint_Type :: enum u32 { + EMPTY = 0, + R = 1, + W = 2, + X = 4, + RW = R | W, + INVALID = RW | X, +} + +/// Bits for Branch_Sample_Type +Branch_Sample_Type_Bits :: enum { + USER = 0, + KERNEL = 1, + HV = 2, + ANY = 3, + ANY_CALL = 4, + ANY_RETURN = 5, + IND_CALL = 6, + ABORT_TX = 7, + IN_TX = 8, + NO_TX = 9, + COND = 10, + CALL_STACK = 11, + IND_JUMP = 12, + CALL = 13, + NO_FLAGS = 14, + NO_CYCLES = 15, + TYPE_SAVE = 16, + HW_INDEX = 17, + PRIV_SAVE = 18, +} + +/// Represent the type of Id +Id_Type :: enum uint { + ALL = 0, + PID = 1, + PGID = 2, + PIDFD = 3, +} + +/// Options for wait syscalls +Wait_Option :: enum { + WNOHANG = 0, + WUNTRACED = 1, + WSTOPPED = 1, + WEXITED = 2, + WCONTINUED = 3, + WNOWAIT = 24, + // // For processes created using clone + __WNOTHREAD = 29, + __WALL = 30, + __WCLONE = 31, +} + +/// Bits for flags for pidfd +Pid_FD_Flags_Bits :: enum { + NONBLOCK = 11, +} + +/// Priority for process, process group, user +Priority_Which :: enum i32 { + PROCESS = 0, + PGRP = 1, + USER = 2, +} + +Signal :: enum i32 { + // POSIX-defined signals + SIGINT = 2, // Interactive attention signal. + SIGILL = 4, // Illegal instruction. + SIGABRT = 6, // Abnormal termination. + SIGFPE = 8, // Erroneous arithmetic operation. + SIGSEGV = 11, // Invalid access to storage. + SIGTERM = 15, // Termination request. + // Other POSIX signals + SIGHUP = 1, // Hangup. + SIGQUIT = 3, // Quit. + SIGTRAP = 5, // Trace/breakpoint trap. + SIGKILL = 9, // Killed. + SIGPIPE = 13, // Broken pipe. + SIGALRM = 14, // Alarm clock. + // Adjustments needed for most linux systems + SIGSTKFLT = 16, // Stack fault (obsolete). + SIGPWR = 30, // Power failure imminent. + // Historical signals specified by POSIX. + SIGBUS = 7, // Bus error. + SIGSYS = 31, // Bad system call. + // New(er) POSIX signals (1003.1-2008, 1003.1-2013). + SIGURG = 23, // Urgent data is available at a socket. + SIGSTOP = 19, // Stop, unblockable. + SIGTSTP = 20, // Keyboard stop. + SIGCONT = 18, // Continue. + SIGCHLD = 17, // Child terminated or stopped. + SIGTTIN = 21, // Background read from control terminal. + SIGTTOU = 22, // Background write to control terminal. + SIGPOLL = 29, // Pollable event occurred (System V). + SIGXFSZ = 25, // File size limit exceeded. + SIGXCPU = 24, // CPU time limit exceeded. + SIGVTALRM = 26, // Virtual timer expired. + SIGPROF = 27, // Profiling timer expired. + SIGUSR1 = 10, // User-defined signal 1. + SIGUSR2 = 12, // User-defined signal 2. + // Nonstandard signals found in all modern POSIX systems (including both BSD and Linux). + SIGWINCH = 28, // Window size change (4.3 BSD, Sun). + // Archaic names for compatibility. + SIGIO = SIGPOLL, // I/O now possible (4.2 BSD). + SIGIOT = SIGABRT, // IOT instruction, abort() on a PDP-11. + SIGCLD = SIGCHLD, // Old System V name +} + +Sig_Mask_Kind :: enum i32 { + SIG_BLOCK = 0, + SIG_UNBLOCK = 1, + SIG_SETMASK = 2, +} + +Sig_Stack_Flag :: enum i32 { + DISABLE = 0, + ONSTACK = 1, + AUTODISARM = 31, +} + +/// Type of socket to create +/// For TCP you want to use SOCK_STREAM +/// For UDP you want to use SOCK_DGRAM +/// Also see Protocol +Socket_Type :: enum { + STREAM = 1, + DGRAM = 2, + RAW = 3, + RDM = 4, + SEQPACKET = 5, + DCCP = 6, + PACKET = 10, +} + +/// Bits for Socket_FD_Flags +Socket_FD_Flags_Bits :: enum { + NONBLOCK = 14, + CLOEXEC = 25, +} + +/// Protocol family +Protocol_Family :: enum u16 { + UNSPEC = 0, + LOCAL = 1, + UNIX = LOCAL, + FILE = LOCAL, + INET = 2, + AX25 = 3, + IPX = 4, + APPLETALK = 5, + NETROM = 6, + BRIDGE = 7, + ATMPVC = 8, + X25 = 9, + INET6 = 10, + ROSE = 11, + DECnet = 12, + NETBEUI = 13, + SECURITY = 14, + KEY = 15, + NETLINK = 16, + ROUTE = NETLINK, + PACKET = 17, + ASH = 18, + ECONET = 19, + ATMSVC = 20, + RDS = 21, + SNA = 22, + IRDA = 23, + PPPOX = 24, + WANPIPE = 25, + LLC = 26, + IB = 27, + MPLS = 28, + CAN = 29, + TIPC = 30, + BLUETOOTH = 31, + IUCV = 32, + RXRPC = 33, + ISDN = 34, + PHONET = 35, + IEEE802154 = 36, + CAIF = 37, + ALG = 38, + NFC = 39, + VSOCK = 40, + KCM = 41, + QIPCRTR = 42, + SMC = 43, + XDP = 44, + MCTP = 45, +} + +/// The protocol number according to IANA protocol number list +/// Full list of protocol numbers: +/// https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml +/// Supported by the OS protocols can be queried by reading: +/// /etc/protocols +Protocol :: enum { + HOPOPT = 0, + ICMP = 1, + IGMP = 2, + GGP = 3, + IPv4 = 4, + ST = 5, + TCP = 6, + CBT = 7, + EGP = 8, + IGP = 9, + BBN_RCC_MON = 10, + NVP_II = 11, + PUP = 12, + EMCON = 14, + XNET = 15, + CHAOS = 16, + UDP = 17, + MUX = 18, + DCN_MEAS = 19, + HMP = 20, + PRM = 21, + XNS_IDP = 22, + TRUNK_1 = 23, + TRUNK_2 = 24, + LEAF_1 = 25, + LEAF_2 = 26, + RDP = 27, + IRTP = 28, + ISO_TP4 = 29, + NETBLT = 30, + MFE_NSP = 31, + MERIT_INP = 32, + DCCP = 33, + THREE_PC = 34, + IDPR = 35, + XTP = 36, + DDP = 37, + IDPR_CMTP = 38, + TP_PlusPlus = 39, + IL = 40, + IPv6 = 41, + SDRP = 42, + IPv6_Route = 43, + IPv6_Frag = 44, + IDRP = 45, + RSVP = 46, + GRE = 47, + DSR = 48, + BNA = 49, + ESP = 50, + AH = 51, + I_NLSP = 52, + NARP = 54, + MOBILE = 55, + TLSP = 56, + SKIP = 57, + IPv6_ICMP = 58, + IPv6_NoNxt = 59, + IPv6_Opts = 60, + CFTP = 62, + SAT_EXPAK = 64, + KRYPTOLAN = 65, + RVD = 66, + IPPC = 67, + SAT_MON = 69, + VISA = 70, + IPCV = 71, + CPNX = 72, + CPHB = 73, + WSN = 74, + PVP = 75, + BR_SAT_MON = 76, + SUN_ND = 77, + WB_MON = 78, + WB_EXPAK = 79, + ISO_IP = 80, + VMTP = 81, + SECURE_VMTP = 82, + VINES = 83, + IPTM = 84, + NSFNET_IGP = 85, + DGP = 86, + TCF = 87, + EIGRP = 88, + OSPFIGP = 89, + Sprite_RPC = 90, + LARP = 91, + MTP = 92, + AX_25 = 93, + IPIP = 94, + SCC_SP = 96, + ETHERIP = 97, + ENCAP = 98, + GMTP = 100, + IFMP = 101, + PNNI = 102, + PIM = 103, + ARIS = 104, + SCPS = 105, + QNX = 106, + A_N = 107, + IPComp = 108, + SNP = 109, + Compaq_Peer = 110, + IPX_in_IP = 111, + VRRP = 112, + PGM = 113, + L2TP = 115, + DDX = 116, + IATP = 117, + STP = 118, + SRP = 119, + UTI = 120, + SMP = 121, + PTP = 123, + FIRE = 125, + CRTP = 126, + CRUDP = 127, + SSCOPMCE = 128, + IPLT = 129, + SPS = 130, + PIPE = 131, + SCTP = 132, + FC = 133, + RSVP_E2E_IGNORE = 134, + UDPLite = 136, + MPLS_in_IP = 137, + manet = 138, + HIP = 139, + Shim6 = 140, + WESP = 141, + ROHC = 142, + Ethernet = 143, + AGGFRAG = 144, + NSH = 145, + Reserved = 255, +} + +/// API Level for get/setsockopt.2 +Socket_API_Level :: enum { + // Comes from + SOCKET = 1, + // Copy-pasted from protocol numbers + TCP = 6, + UDP = 17, + // Comes from + RAW = 255, + DECNET = 261, + X25 = 262, + PACKET = 263, + ATM = 264, + AAL = 265, + IRDA = 266, + NETBEUI = 267, + LLC = 268, + DCCP = 269, + NETLINK = 270, + TIPC = 271, + RXRPC = 272, + PPPOL2TP = 273, + BLUETOOTH = 274, + PNPIPE = 275, + RDS = 276, + IUCV = 277, + CAIF = 278, + ALG = 279, + NFC = 280, + KCM = 281, + TLS = 282, + XDP = 283, + MPTCP = 284, + MCTP = 285, + SMC = 286, +} + +/// If Socket_API_Level == .SOCKET, these are the options +/// you can specify in get/setsockopt.2 +Socket_Option :: enum { + DEBUG = 1, + REUSEADDR = 2, + TYPE = 3, + ERROR = 4, + DONTROUTE = 5, + BROADCAST = 6, + SNDBUF = 7, + RCVBUF = 8, + SNDBUFFORCE = 32, + RCVBUFFORCE = 33, + KEEPALIVE = 9, + OOBINLINE = 10, + NO_CHECK = 11, + PRIORITY = 12, + LINGER = 13, + BSDCOMPAT = 14, + REUSEPORT = 15, + PASSCRED = 16, + PEERCRED = 17, + RCVLOWAT = 18, + SNDLOWAT = 19, + RCVTIMEO_OLD = 20, + SNDTIMEO_OLD = 21, + SECURITY_AUTHENTICATION = 22, + SECURITY_ENCRYPTION_TRANSPORT = 23, + SECURITY_ENCRYPTION_NETWORK = 24, + BINDTODEVICE = 25, + ATTACH_FILTER = 26, + DETACH_FILTER = 27, + GET_FILTER = ATTACH_FILTER, + PEERNAME = 28, + ACCEPTCONN = 30, + PEERSEC = 31, + PASSSEC = 34, + MARK = 36, + PROTOCOL = 38, + DOMAIN = 39, + RXQ_OVFL = 40, + WIFI_STATUS = 41, + PEEK_OFF = 42, + NOFCS = 43, + LOCK_FILTER = 44, + SELECT_ERR_QUEUE = 45, + BUSY_POLL = 46, + MAX_PACING_RATE = 47, + BPF_EXTENSIONS = 48, + INCOMING_CPU = 49, + ATTACH_BPF = 50, + DETACH_BPF = DETACH_FILTER, + ATTACH_REUSEPORT_CBPF = 51, + ATTACH_REUSEPORT_EBPF = 52, + CNX_ADVICE = 53, + TIMESTAMPING_OPT_STATS = 54, + MEMINFO = 55, + INCOMING_NAPI_ID = 56, + COOKIE = 57, + TIMESTAMPING_PKTINFO = 58, + PEERGROUPS = 59, + ZEROCOPY = 60, + TXTIME = 61, + BINDTOIFINDEX = 62, + TIMESTAMP_OLD = 29, + TIMESTAMPNS_OLD = 35, + TIMESTAMPING_OLD = 37, + TIMESTAMP_NEW = 63, + TIMESTAMPNS_NEW = 64, + TIMESTAMPING_NEW = 65, + RCVTIMEO_NEW = 66, + SNDTIMEO_NEW = 67, + DETACH_REUSEPORT_BPF = 68, + PREFER_BUSY_POLL = 69, + BUSY_POLL_BUDGET = 70, + NETNS_COOKIE = 71, + BUF_LOCK = 72, + RESERVE_MEM = 73, + TXREHASH = 74, + RCVMARK = 75, + // Hardcoded 64-bit Time. It's time to move on. + TIMESTAMP = TIMESTAMP_NEW, + TIMESTAMPNS = TIMESTAMPNS_NEW, + TIMESTAMPING = TIMESTAMPING_NEW, + RCVTIMEO = RCVTIMEO_NEW, + SNDTIMEO = SNDTIMEO_NEW, +} + +Socket_UDP_Option :: enum { + CORK = 1, + ENCAP = 100, + NO_CHECK6_TX = 101, + NO_CHECK6_RX = 102, + SEGMENT = 103, + GRO = 104, +} + +UPD_Encapsulation :: enum { + ENCAP_ESPINUDP_NON_IKE = 1, + ENCAP_ESPINUDP = 2, + ENCAP_L2TPINUDP = 3, + ENCAP_GTP0 = 4, + ENCAP_GTP1U = 5, +} + +Socket_TCP_Option :: enum { + NODELAY = 1, + MAXSEG = 2, + CORK = 3, + KEEPIDLE = 4, + KEEPINTVL = 5, + KEEPCNT = 6, + SYNCNT = 7, + LINGER2 = 8, + DEFER_ACCEPT = 9, + WINDOW_CLAMP = 10, + INFO = 11, + QUICKACK = 12, + CONGESTION = 13, + MD5SIG = 14, + COOKIE_TRANSACTIONS = 15, + THIN_LINEAR_TIMEOUTS = 16, + THIN_DUPACK = 17, + USER_TIMEOUT = 18, + REPAIR = 19, + REPAIR_QUEUE = 20, + QUEUE_SEQ = 21, + REPAIR_OPTIONS = 22, + FASTOPEN = 23, + TIMESTAMP = 24, + NOTSENT_LOWAT = 25, + CC_INFO = 26, + SAVE_SYN = 27, + SAVED_SYN = 28, + REPAIR_WINDOW = 29, + FASTOPEN_CONNECT = 30, + ULP = 31, + MD5SIG_EXT = 32, + FASTOPEN_KEY = 33, + FASTOPEN_NO_COOKIE = 34, + ZEROCOPY_RECEIVE = 35, + INQ = 36, + CM_INQ = INQ, + TX_DELAY = 37, +} + +/// Bits for Socket_Msg +Socket_Msg_Bits :: enum { + OOB = 0, + PEEK = 1, + DONTROUTE = 2, + TRYHARD = DONTROUTE, + CTRUNC = 3, + PROXY = 4, + TRUNC = 5, + DONTWAIT = 6, + EOR = 7, + WAITALL = 8, + FIN = 9, + SYN = 10, + CONFIRM = 11, + RST = 12, + ERRQUEUE = 13, + NOSIGNAL = 14, + MORE = 15, + WAITFORONE = 16, + BATCH = 18, + ZEROCOPY = 22, + FASTOPEN = 29, + CMSG_CLOEXEC = 30, +} + +/// Argument to shutdown.2 +Shutdown_How :: enum i32 { + RD = 0, + WR = 1, + RDWR = 2, +} + +/// Second argument to futex.2 syscall +Futex_Op :: enum u32 { + WAIT = 0, + WAKE = 1, + FD = 2, + REQUEUE = 3, + CMP_REQUEUE = 4, + WAKE_OP = 5, + LOCK_PI = 6, + UNLOCK_PI = 7, + TRYLOCK_PI = 8, + WAIT_BITSET = 9, + WAKE_BITSET = 10, + WAIT_REQUEUE_PI = 11, + CMP_REQUEUE_PI = 12, + LOCK_PI2 = 13, +} + +/// Bits for Futex_Flags +Futex_Flags_Bits :: enum { + PRIVATE = 7, + REALTIME = 8, +} + +/// Kind of operation on futex, see FUTEX_WAKE_OP +Futex_Arg_Op :: enum { + SET = 0, /* uaddr2 = oparg; */ + ADD = 1, /* uaddr2 += oparg; */ + OR = 2, /* uaddr2 |= oparg; */ + ANDN = 3, /* uaddr2 &= ~oparg; */ + XOR = 4, /* uaddr2 ^= oparg; */ + PO2_SET = 0, /* uaddr2 = 1< cmparg) wake */ + GE = 5, /* if (oldval >= cmparg) wake */ +} + +/// The kind of resource limits +RLimit_Kind :: enum i32 { + CPU = 0, + FSIZE = 1, + DATA = 2, + STACK = 3, + CORE = 4, + RSS = 5, + NOFILE = 7, + AS = 9, + NPROC = 6, + MEMLOCK = 8, + LOCKS = 10, + SIGPENDING = 11, + MSGQUEUE = 12, + NICE = 13, + RTPRIO = 14, + RTTIME = 15, + NLIMITS = 16, +} + +/// Represents the user of resources +RUsage_Who :: enum i32 { + CHILDREN = -1, + SELF = 0, + THREAD = 1, + LWP = THREAD, +} + +/// Bits for Personality_Flags +UNAME26 :: 17 +ADDR_NO_RANDOMIZE :: 18 +FDPIC_FUNCPTRS :: 19 +MMAP_PAGE_ZERO :: 20 +ADDR_COMPAT_LAYOUT :: 21 +READ_IMPLIES_EXEC :: 22 +ADDR_LIMIT_32BIT :: 23 +SHORT_INODE :: 24 +WHOLE_SECONDS :: 25 +STICKY_TIMEOUTS :: 26 +ADDR_LIMIT_3GB :: 27 + +/// Personality type +/// These go into the bottom 8 bits of the personality value +PER_LINUX :: 0x0000 +PER_LINUX_32BIT :: 0x0000 | ADDR_LIMIT_32BIT +PER_LINUX_FDPIC :: 0x0000 | FDPIC_FUNCPTRS +PER_SVR4 :: 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO +PER_SVR3 :: 0x0002 | STICKY_TIMEOUTS | SHORT_INODE +PER_SCOSVR3 :: 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE +PER_OSR5 :: 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS +PER_WYSEV386 :: 0x0004 | STICKY_TIMEOUTS | SHORT_INODE +PER_ISCR4 :: 0x0005 | STICKY_TIMEOUTS +PER_BSD :: 0x0006 +PER_SUNOS :: 0x0006 | STICKY_TIMEOUTS +PER_XENIX :: 0x0007 | STICKY_TIMEOUTS | SHORT_INODE +PER_LINUX32 :: 0x0008 +PER_LINUX32_3GB :: 0x0008 | ADDR_LIMIT_3GB +PER_IRIX32 :: 0x0009 | STICKY_TIMEOUTS +PER_IRIXN32 :: 0x000a | STICKY_TIMEOUTS +PER_IRIX64 :: 0x000b | STICKY_TIMEOUTS +PER_RISCOS :: 0x000c +PER_SOLARIS :: 0x000d | STICKY_TIMEOUTS +PER_UW7 :: 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO +PER_OSF4 :: 0x000f +PER_HPUX :: 0x0010 +PER_MASK :: 0x00ff + diff --git a/core/sys/linux/constants.odin b/core/sys/linux/constants.odin new file mode 100644 index 000000000..f826a556d --- /dev/null +++ b/core/sys/linux/constants.odin @@ -0,0 +1,199 @@ + +package linux + +/// Special file descriptor to pass to `*at` functions to specify +/// that relative paths are relative to current directory +AT_FDCWD :: Fd(-100) + +/// Special value to put into timespec for utimensat() to set timestamp to the current time +UTIME_NOW :: uint((1 << 30) - 1) + +/// Special value to put into the timespec for utimensat() to leave the corresponding field of the timestamp unchanged +UTIME_OMIT :: uint((1 << 30) - 2) + +/// For wait4: Pass this pid to wait for any process +WAIT_ANY :: Pid(-1) + +/// For wait4: Pass this pid to wait for any process in current process group +WAIT_MYPGRP :: Pid(0) + +/// Maximum priority (aka nice value) for the process +PRIO_MAX :: 20 + +/// Minimum priority (aka nice value) for the process +PRIO_MIN :: -20 + +SIGRTMIN :: Signal(32) +SIGRTMAX :: Signal(64) + +S_IFMT :: Mode{.IFREG, .IFDIR, .IFCHR, .IFFIFO} +S_IFSOCK :: Mode{.IFREG, .IFDIR} +S_IFLNK :: Mode{.IFREG, .IFCHR} +S_IFBLK :: Mode{.IFDIR, .IFCHR} +S_IFFIFO :: Mode{.IFFIFO} +S_IFCHR :: Mode{.IFCHR} +S_IFDIR :: Mode{.IFDIR} +S_IFREG :: Mode{.IFREG} + +/// Checks the Mode bits to see if the file is a named pipe (FIFO) +S_ISFIFO :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFFIFO == (m & S_IFMT))} + +/// Check the Mode bits to see if the file is a character device +S_ISCHR :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFCHR == (m & S_IFMT))} + +/// Check the Mode bits to see if the file is a directory +S_ISDIR :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFDIR == (m & S_IFMT))} + +/// Check the Mode bits to see if the file is a register +S_ISREG :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFREG == (m & S_IFMT))} + +/// Check the Mode bits to see if the file is a socket +S_ISSOCK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFSOCK == (m & S_IFMT))} + +/// Check the Mode bits to see if the file is a symlink +S_ISLNK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFLNK == (m & S_IFMT))} + +/// Check the Mode bits to see if the file is a block device +S_ISBLK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFBLK == (m & S_IFMT))} + +/// For access.2 syscall family: instruct to check if the file exists +F_OK :: Mode{} + +/// For access.2 syscall family: instruct to check if the file is executable +X_OK :: Mode{.IXOTH} + +/// For access.2 syscall family: instruct to check if the file is writeable +W_OK :: Mode{.IWOTH} + +/// For access.2 syscall family: instruct to check if the file is readable +R_OK :: Mode{.IROTH} + +/// The stats you get by calling `stat` +STATX_BASIC_STATS :: Statx_Mask { + .TYPE, + .MODE, + .NLINK, + .UID, + .GID, + .ATIME, + .MTIME, + .CTIME, + .INO, + .SIZE, + .BLOCKS, +} + + +FCntl_Command_DUPFD :: distinct FCntl_Command +FCntl_Command_GETFD :: distinct FCntl_Command +FCntl_Command_SETFD :: distinct FCntl_Command +FCntl_Command_GETFL :: distinct FCntl_Command +FCntl_Command_SETFL :: distinct FCntl_Command +FCntl_Command_GETLK :: distinct FCntl_Command +FCntl_Command_SETLK :: distinct FCntl_Command +FCntl_Command_SETLKW :: distinct FCntl_Command +FCntl_Command_DUPFD_CLOEXEC :: distinct FCntl_Command +FCntl_Command_SETOWN :: distinct FCntl_Command +FCntl_Command_GETOWN :: distinct FCntl_Command +FCntl_Command_SETSIG :: distinct FCntl_Command +FCntl_Command_GETSIG :: distinct FCntl_Command +FCntl_Command_SETOWN_EX :: distinct FCntl_Command +FCntl_Command_GETOWN_EX :: distinct FCntl_Command +FCntl_Command_SETLEASE :: distinct FCntl_Command +FCntl_Command_GETLEASE :: distinct FCntl_Command +FCntl_Command_NOTIFY :: distinct FCntl_Command +FCntl_Command_SETPIPE_SZ :: distinct FCntl_Command +FCntl_Command_GETPIPE_SZ :: distinct FCntl_Command +FCntl_Command_ADD_SEALS :: distinct FCntl_Command +FCntl_Command_GET_SEALS :: distinct FCntl_Command +FCntl_Command_GET_RW_HINT :: distinct FCntl_Command +FCntl_Command_SET_RW_HINT :: distinct FCntl_Command +FCntl_Command_GET_FILE_RW_HINT :: distinct FCntl_Command +FCntl_Command_SET_FILE_RW_HINT :: distinct FCntl_Command +F_DUPFD :: FCntl_Command_DUPFD(.DUPFD) +F_GETFD :: FCntl_Command_GETFD(.GETFD) +F_SETFD :: FCntl_Command_SETFD(.SETFD) +F_GETFL :: FCntl_Command_GETFL(.GETFL) +F_SETFL :: FCntl_Command_SETFL(.SETFL) +// F_GETLK64 :: FCntl_Command_GETLK64(.GETLK64) +// F_SETLK64 :: FCntl_Command_SETLK64(.SETLK64) +// F_SETLKW64 :: FCntl_Command_SETLKW64(.SETLKW64) +F_GETLK :: FCntl_Command_GETLK(.GETLK) +F_SETLK :: FCntl_Command_SETLK(.SETLK) +F_SETLKW :: FCntl_Command_SETLKW(.SETLKW) +F_DUPFD_CLOEXEC :: FCntl_Command_DUPFD_CLOEXEC(.DUPFD_CLOEXEC) +F_SETOWN :: FCntl_Command_SETOWN(.SETOWN) +F_GETOWN :: FCntl_Command_GETOWN(.GETOWN) +F_SETSIG :: FCntl_Command_SETSIG(.SETSIG) +F_GETSIG :: FCntl_Command_GETSIG(.GETSIG) +F_SETOWN_EX :: FCntl_Command_SETOWN_EX(.SETOWN_EX) +F_GETOWN_EX :: FCntl_Command_GETOWN_EX(.GETOWN_EX) +F_SETLEASE :: FCntl_Command_SETLEASE(.SETLEASE) +F_GETLEASE :: FCntl_Command_GETLEASE(.GETLEASE) +F_NOTIFY :: FCntl_Command_NOTIFY(.NOTIFY) +F_SETPIPE_SZ :: FCntl_Command_SETPIPE_SZ(.SETPIPE_SZ) +F_GETPIPE_SZ :: FCntl_Command_GETPIPE_SZ(.GETPIPE_SZ) +F_ADD_SEALS :: FCntl_Command_ADD_SEALS(.ADD_SEALS) +F_GET_SEALS :: FCntl_Command_GET_SEALS(.GET_SEALS) +F_GET_RW_HINT :: FCntl_Command_GET_RW_HINT(.GET_RW_HINT) +F_SET_RW_HINT :: FCntl_Command_SET_RW_HINT(.SET_RW_HINT) +F_GET_FILE_RW_HINT :: FCntl_Command_GET_FILE_RW_HINT(.GET_FILE_RW_HINT) +F_SET_FILE_RW_HINT :: FCntl_Command_SET_FILE_RW_HINT(.SET_FILE_RW_HINT) + +Socket_API_Level_Sock :: distinct Socket_API_Level +Socket_API_Level_TCP :: distinct Socket_API_Level +Socket_API_Level_UDP :: distinct Socket_API_Level +Socket_API_Level_Raw :: distinct Socket_API_Level + +SOL_SOCKET :: Socket_API_Level_Sock(.SOCKET) +SOL_TCP :: Socket_API_Level_TCP(.TCP) +SOL_UDP :: Socket_API_Level_UDP(.UDP) +SOL_RAW :: Socket_API_Level_Raw(.RAW) + +Futex_Wait_Type :: distinct Futex_Op +Futex_Wake_Type :: distinct Futex_Op +Futex_Fd_Type :: distinct Futex_Op +Futex_Requeue_Type :: distinct Futex_Op +Futex_Cmp_Requeue_Type :: distinct Futex_Op +Futex_Wake_Op_Type :: distinct Futex_Op +Futex_Lock_Pi_Type :: distinct Futex_Op +Futex_Unlock_Pi_Type :: distinct Futex_Op +Futex_Trylock_Pi_Type :: distinct Futex_Op +Futex_Wait_Bitset_Type :: distinct Futex_Op +Futex_Wake_Bitset_Type :: distinct Futex_Op +Futex_Wait_requeue_Pi_Type :: distinct Futex_Op +Futex_Cmp_requeue_Pi_Type :: distinct Futex_Op +Futex_Lock_Pi2_Type :: distinct Futex_Op + +/// Wait on futex wakeup signal +FUTEX_WAIT :: Futex_Wait_Type(.WAIT) + +/// Wake up other processes waiting on the futex +FUTEX_WAKE :: Futex_Wake_Type(.WAKE) + +/// Not implemented. Basically, since +FUTEX_FD :: Futex_Fd_Type(.FD) + +/// Requeue waiters from one futex to another +FUTEX_REQUEUE :: Futex_Requeue_Type(.REQUEUE) + +/// Requeue waiters from one futex to another if the value at mutex matches +FUTEX_CMP_REQUEUE :: Futex_Cmp_Requeue_Type(.CMP_REQUEUE) + +/// See man pages, I'm not describing it here +FUTEX_WAKE_OP :: Futex_Wake_Op_Type(.WAKE_OP) + +/// Wait on a futex, but the value is a bitset +FUTEX_WAIT_BITSET :: Futex_Wait_Bitset_Type(.WAIT_BITSET) + +/// Wait on a futex, but the value is a bitset +FUTEX_WAKE_BITSET :: Futex_Wake_Bitset_Type(.WAKE_BITSET) + +// TODO(flysand): Priority inversion futexes +FUTEX_LOCK_PI :: Futex_Lock_Pi_Type(.LOCK_PI) +FUTEX_UNLOCK_PI :: Futex_Unlock_Pi_Type(.UNLOCK_PI) +FUTEX_TRYLOCK_PI :: Futex_Trylock_Pi_Type(.TRYLOCK_PI) +FUTEX_WAIT_REQUEUE_PI :: Futex_Wait_requeue_Pi_Type(.WAIT_REQUEUE_PI) +FUTEX_CMP_REQUEUE_PI :: Futex_Cmp_requeue_Pi_Type(.CMP_REQUEUE_PI) +FUTEX_LOCK_PI2 :: Futex_Lock_Pi2_Type(.LOCK_PI2) + diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin new file mode 100644 index 000000000..8fe4de6d2 --- /dev/null +++ b/core/sys/linux/helpers.odin @@ -0,0 +1,150 @@ +//+build linux +package linux + +import "core:intrinsics" + +// Note(flysand): In the case of syscall let's get rid of extra +// casting. First of all, let these syscalls return int, because +// we'll need to check for Errno anyway. Second of all +// most parameters are going to be trivially-castable to +// uintptr, so we'll have that. + +@(private) +syscall0 :: #force_inline proc "contextless" (nr: uintptr) -> int { + return cast(int) intrinsics.syscall(nr) +} + +@(private) +syscall1 :: #force_inline proc "contextless" (nr: uintptr, p1: $T) -> int +where + size_of(p1) <= size_of(uintptr) +{ + return cast(int) intrinsics.syscall(nr, cast(uintptr) p1) +} + +@(private) +syscall2 :: #force_inline proc "contextless" (nr: uintptr,p1: $T1, p2: $T2) -> int +where + size_of(p1) <= size_of(uintptr) && + size_of(p2) <= size_of(uintptr) +{ + return cast(int) intrinsics.syscall(nr, + cast(uintptr) p1, cast(uintptr) p2) +} + +@(private) +syscall3 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3) -> int +where + size_of(p1) <= size_of(uintptr) && + size_of(p2) <= size_of(uintptr) && + size_of(p3) <= size_of(uintptr) +{ + return cast(int) intrinsics.syscall(nr, + cast(uintptr) p1, + cast(uintptr) p2, + cast(uintptr) p3) +} + +@(private) +syscall4 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4) -> int +where + size_of(p1) <= size_of(uintptr) && + size_of(p2) <= size_of(uintptr) && + size_of(p3) <= size_of(uintptr) && + size_of(p4) <= size_of(uintptr) +{ + return cast(int) intrinsics.syscall(nr, + cast(uintptr) p1, + cast(uintptr) p2, + cast(uintptr) p3, + cast(uintptr) p4) +} + +@(private) +syscall5 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4, p5: $T5) -> int +where + size_of(p1) <= size_of(uintptr) && + size_of(p2) <= size_of(uintptr) && + size_of(p3) <= size_of(uintptr) && + size_of(p4) <= size_of(uintptr) && + size_of(p5) <= size_of(uintptr) +{ + return cast(int) intrinsics.syscall(nr, + cast(uintptr) p1, + cast(uintptr) p2, + cast(uintptr) p3, + cast(uintptr) p4, + cast(uintptr) p5) +} + +@(private) +syscall6 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4, p5: $T5, p6: $T6) -> int +where + size_of(p1) <= size_of(uintptr) && + size_of(p2) <= size_of(uintptr) && + size_of(p3) <= size_of(uintptr) && + size_of(p4) <= size_of(uintptr) && + size_of(p5) <= size_of(uintptr) && + size_of(p6) <= size_of(uintptr) +{ + return cast(int) intrinsics.syscall(nr, + cast(uintptr) p1, + cast(uintptr) p2, + cast(uintptr) p3, + cast(uintptr) p4, + cast(uintptr) p5, + cast(uintptr) p6) +} + +syscall :: proc {syscall0, syscall1, syscall2, syscall3, syscall4, syscall5, syscall6} + +// Note(bumbread): This should shrug off a few lines from every syscall. +// Since not any type can be trivially casted to another type, we take two arguments: +// the final type to cast to, and the type to transmute to before casting. +// One transmute + one cast should allow us to get to any type we might want +// to return from a syscall wrapper. +@(private) +errno_unwrap3 :: #force_inline proc "contextless" (ret: $P, $T: typeid, $U: typeid) -> (T, Errno) +where + intrinsics.type_is_ordered_numeric(P) +{ + if ret < 0 { + default_value: T + return default_value, Errno(-ret) + } else { + return cast(T) transmute(U) ret, Errno(.NONE) + } +} + +@(private) +errno_unwrap2 :: #force_inline proc "contextless" (ret: $P, $T: typeid) -> (T, Errno) { + if ret < 0 { + default_value: T + return default_value, Errno(-ret) + } else { + return cast(T) ret, Errno(.NONE) + } +} + +@(private) +errno_unwrap :: proc {errno_unwrap2, errno_unwrap3} + +// Note(flysand): 32-bit architectures sometimes take in a 64-bit argument in a +// register pair. This function should help me avoid typing the same code a few times.. +when size_of(int) == 4 { + // xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer + @(private) + compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) { + no_sign := uint(a) + hi = uint(no_sign >> 32) + lo = uint(no_sign & 0xffff_ffff) + return + } +} else { + // ... and on 64-bit architectures it's just a long + @(private) + compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (uint) { + return uint(a) + } +} + diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin new file mode 100644 index 000000000..fa7b7186a --- /dev/null +++ b/core/sys/linux/sys.odin @@ -0,0 +1,2038 @@ +//+build linux +package linux + +import "core:intrinsics" + + +/// Read data from file into the buffer +/// Returns the number of bytes successfully read, which may be less than the size +/// of the buffer even if the termination is successfull +/// +/// Available since Linux 1.0 +/// Before Linux 3.14, this operation is not atomic (i.e. not thread safe). +read :: proc "contextless" (fd: Fd, buf: []$T) -> (int, Errno) { + ret := syscall(SYS_read, fd, raw_data(buf), len(buf) * size_of(T)) + return errno_unwrap(ret, int) +} + +/// Write the data from a buffer into the file +/// Returns the number of bytes successfully written, which may be less than the size +/// of the buffer, even if the termination is successfull +/// When using direct I/O, error doesn't mean the write has failed. Partial data may +/// have been written. +/// If .Eintr is returned, the write operation has failed due to interrupt. You'll probably +/// need to restart this syscall +/// +/// Available since Linux 1.0 +/// Before Linux 3.14 this operation is not atomic (i.e. not thread safe) +write :: proc "contextless" (fd: Fd, buf: []$T) -> (int, Errno) { + ret := syscall(SYS_write, fd, raw_data(buf), len(buf)*size_of(T)) + return errno_unwrap(ret, int) +} + +/// Open file, get the file descriptor +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +open :: proc "contextless" (name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_openat, AT_FDCWD, transmute(uintptr) name, transmute(u32) mode) + return errno_unwrap(ret, Fd) + } else { + ret := syscall(SYS_open, transmute(uintptr) name, transmute(u32) mode) + return errno_unwrap(ret, Fd) + } +} + +/// Close the file +/// Available since Linux 1.0 +close :: proc "contextless" (fd: Fd) -> (Errno) { + ret := syscall(SYS_close, fd) + return Errno(-ret) +} + +/// Get file status +/// +/// Returns information about the file in struct pointed to by `stat` parameter. +/// +/// Available since Linux 1.0 +/// For 32-bit systems a different syscall is used that became available since 2.4 +/// Not available on arm64 +stat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) { + when size_of(int) == 8 { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat) + return Errno(-ret) + } else { + ret := syscall(SYS_stat, cast(rawptr) filename, stat) + return Errno(-ret) + } + } else { + ret := syscall(SYS_stat64, cast(rawptr) filename, stat) + return Errno(-ret) + } +} + +/// Get file status from file descriptor +/// +/// Returns information about the file in struct pointed to by `stat` parameter. +/// +/// Available since Linux 1.0 +/// For 32-bit systems a different syscall is used that became available since 2.4 +fstat :: proc "contextless" (fd: Fd, stat: ^Stat) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_fstat, stat) + return Errno(-ret) + } else { + ret := syscall(SYS_fstat64, stat) + return Errno(-ret) + } +} + +/// Get information about the file that's potentially a symbolic link +/// The information is returned in a struct pointed to by `stat` parameter. +/// The difference with stat, fstat is that if the file is a symbolic link, +/// stat and fstat will dereference the link. lstat doesn't dereference symlinks +/// +/// Available since Linux 1.0 +/// For 32-bit systems a different syscall is used that became available since 2.4 +/// Not available on arm64 +lstat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) { + when size_of(int) == 8 { + when ODIN_ARCH == .arm64 { + return fstatat(AT_FDCWD, filename, stat, {.SYMLINK_NOFOLLOW}) + } else { + ret := syscall(SYS_lstat, cast(rawptr) filename, stat) + return Errno(-ret) + } + } else { + ret := syscall(SYS_lstat64, cast(rawptr) filename, stat) + return Errno(-ret) + } +} + +/// Wait on event on a file descriptor +/// Available since Linux 2.2 +poll :: proc "contextless" (fds: []Poll_Fd, timeout: i32) -> (i32, Errno) { + when ODIN_ARCH == .arm64 { + seconds := cast(uint) timeout / 1000 + nanoseconds := cast(uint) (timeout % 1000) * 1_000_000 + timeout_spec := Time_Spec{seconds, nanoseconds} + ret := syscall(SYS_ppoll, raw_data(fds), len(fds), &timeout_spec, 0, 0) + return errno_unwrap(ret, i32) + } else { + ret := syscall(SYS_poll, raw_data(fds), len(fds), timeout) + return errno_unwrap(ret, i32) + } +} + + +/// Seek the file stream to specified offset +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 1.2 +lseek :: proc "contextless" (fd: Fd, off: i64, whence: Seek_Whence) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_lseek, fd, off, whence) + return Errno(-ret) + } else { + ret := syscall(SYS__llseek, fd, compat64_arg_pair(off), whence) + return Errno(-ret) + } +} + +/// Map files into memory +/// Available since Linux 1.0 +/// On 32-bit platforms since Linux 1.0 +mmap :: proc "contextless" (addr: uintptr, size: uint, prot: Mem_Protection, flags: Map_Flags, fd: Fd = Fd(-1), offset: i64 = 0) -> (rawptr, Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_mmap, addr, size, transmute(i32) prot, transmute(i32) flags, fd, offset) + return errno_unwrap(ret, rawptr, uintptr) + } else { + ret := syscall(SYS_mmap2, addr, size, transmute(i32) prot, transmute(i32) flags, fd, cast(uintptr)(offset/4096)) + return errno_unwrap(ret, rawptr, uintptr) + } +} + +/// Protect memory region +mprotect :: proc "contextless" (addr: rawptr, size: uint, prot: Mem_Protection) -> (Errno) { + ret := syscall(SYS_mprotect, addr, size, transmute(i32) prot) + return Errno(-ret) +} + +/// Unmap memory +/// Available since Linux 1.0 +munmap :: proc "contextless" (addr: rawptr, size: uint) -> (Errno) { + ret := syscall(SYS_mmap, addr, size) + return Errno(-ret) +} + +// TODO(flysand): brk + +/// Alter an action taken by a process +rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action, old_sigaction: ^Sig_Action) -> Errno { + ret := syscall(SYS_rt_sigaction, sig, sigaction, old_sigaction, size_of(Sig_Set)) + return Errno(-ret) +} + +/// Examime and alter blocked signals +/// Available since Linux 2.2 +rt_sigprocmask :: proc "contextless" (mask_kind: Sig_Mask_Kind, new_set: ^Sig_Set, old_set: ^Sig_Set) -> Errno { + ret := syscall(SYS_rt_sigprocmask, mask_kind, new_set, old_set, size_of(Sig_Set)) + return Errno(-ret) +} + +// TODO(flysand): rt_sigreturn + +// TODO(flysand): ioctl + +/// Read the file at a specified offset +/// Note, it is not an error to return less bytes than requested +/// Available since Linux 2.2 +pread :: proc "contextless" (fd: Fd, buf: []$T, offset: i64) -> (int, Errno) { + ret := syscall(SYS_pread64, fd, raw_data(buf), compat64_arg_pair(len(buf)*size_of(T))) + return errno_unwrap(ret, int) +} + +/// Read the file at a specified offset +/// Note, it is not an error to return less bytes than requested +/// Available since Linux 2.2 +pwrite :: proc "contextless" (fd: Fd, buf: []$T, offset: i64) -> (int, Errno) { + ret := syscall(SYS_pwrite64, fd, raw_data(buf), compat64_arg_pair(len(buf)*size_of(T))) + return errno_unwrap(ret, int) +} + +// TODO(flysand): readv + +// TODO(flysand): writev + +/// Check user permissions for a file +/// If Mode is F_OK, checks whether the file exists +/// Similarly, X_OK, W_OK, R_OK check if the file is executable, writeable, readable respectively +/// Available since Linux 1.0 +/// For ARM64 available since Linux 2.6.16 +access :: proc "contextless" (name: cstring, mode: Mode = F_OK) -> (bool, Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_faccessat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode) + return errno_unwrap(ret, bool) + } else { + ret := syscall(SYS_access, cast(rawptr) name, transmute(u32) mode) + return errno_unwrap(ret, bool) + } +} + +/// Create a pipe +/// Available since Linux 2.6.27 +pipe2 :: proc "contextless" (pipes: ^[2]Fd, flags: Open_Flags) -> (Errno) { + ret := syscall(SYS_pipe2, pipes, transmute(u32) flags) + return Errno(-ret) +} + +// TODO(flysand): select + +// TODO(flysand): sched_yield + +// TODO(flysand): add docs here +mremap :: proc "contextless" (old_addr: rawptr, old_size: uint, new_size: uint, flags: MRemap_Flags, new_addr: uintptr = 0) -> (rawptr, Errno) { + if .FIXED in flags { + ret := syscall(SYS_mremap, old_addr, old_size, new_size, transmute(i32) flags, new_addr) + return errno_unwrap(ret, rawptr, rawptr) + } else { + ret := syscall(SYS_mremap, old_addr, old_size, new_size, transmute(i32) flags) + return errno_unwrap(ret, rawptr, rawptr) + } +} + +/// Sync file with memory map +/// Available since Linux 2.0 +msync :: proc "contextless" (addr: rawptr, size: uint, flags: MSync_Flags) -> (Errno) { + ret := syscall(SYS_msync, addr, size, transmute(i32) flags) + return Errno(-ret) +} + +// TODO(flysand): mincore + +/// Give advice about use of memory +/// Available since Linux 2.4 +madvise :: proc "contextless" (addr: rawptr, size: uint, advice: MAdvice) -> (Errno) { + ret := syscall(SYS_madvise, addr, size, advice) + return Errno(-ret) +} + +// TODO(flysand): shmget + +// TODO(flysand): shmat + +// TODO(flysand): shmctl + +/// Allocate a new file descriptor that refers to the same file as the one provided +/// Available since Linux 1.0 +dup :: proc "contextless" (fd: Fd) -> (Fd, Errno) { + ret := syscall(SYS_dup, fd) + return errno_unwrap(ret, Fd) +} + +/// Adjust an existing file descriptor to point to the same file as `old` +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.27 +dup2 :: proc "contextless" (old: Fd, new: Fd) -> (Fd, Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_dup3, old, new, 0) + return errno_unwrap(ret, Fd) + } else { + ret := syscall(SYS_dup2, old, new) + return errno_unwrap(ret, Fd) + } +} + +// TODO(flysand): pause + +// TODO(flysand): nanosleep + +// TODO(flysand): getitimer + +// TODO(flysand): alarm + +// TODO(flysand): setitimer + +/// Returns the thread group ID of the current process +/// Note that it doesn't return the pid, despite it's name. +/// Available since Linux 1.0 +getpid :: proc "contextless" () -> Pid { + return cast(Pid) syscall(SYS_getpid) +} + +// TODO(flysand): sendfile + +/// Create a socket file descriptor +/// Available since Linux 2.0 +socket :: proc "contextless" (domain: Address_Family, socktype: Socket_Type, sockflags: Socket_FD_Flags, protocol: Protocol) -> (Fd, Errno) { + sock_type_flags: int = cast(int) socktype | transmute(int) sockflags + ret := syscall(SYS_socket, domain, sock_type_flags, protocol) + return errno_unwrap(ret, Fd) +} + +/// Connect the socket to the address +/// Available since Linux 2.0 +connect :: proc "contextless" (sock: Fd, addr: ^$T) -> (Errno) +where + T == Sock_Addr_In || + T == Sock_Addr_In6 || + T == Sock_Addr_Any +{ + ret := syscall(SYS_connect, sock, addr, size_of(T)) + return Errno(-ret) +} + +/// Accept a pending connection or block until new connection appears +/// Depends on Sock_FD_Flags of the `sock` parameter. +/// Available since Linux 2.0 +accept :: proc "contextless" (sock: Fd, addr: ^$T, sockflags: Socket_FD_Flags = {}) -> (Fd, Errno) +where + T == Sock_Addr_In || + T == Sock_Addr_In6 || + T == Sock_Addr_Any +{ + ret := syscall(SYS_accept4, sock, addr, size_of(T), transmute(int) sockflags) + return errno_unwrap(ret, Fd) +} + +// TODO(flysand): Rewrite recvfrom and sendto to use default parameters +recvfrom :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg, addr: ^$T) -> (int, Errno) +where + T == Sock_Addr_In || + T == Sock_Addr_In6 || + T == Sock_Addr_Any +{ + ret := syscall(SYS_recvfrom, sock, raw_data(buf), len(buf), transmute(i32) flags, addr, size_of(T)) + return errno_unwrap(ret, int) +} + +@private +recv_noaddr :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg) -> (int, Errno) { + ret := syscall(SYS_recvfrom, sock, raw_data(buf), len(buf), transmute(i32) flags, cast(rawptr) nil, cast(uintptr) 0) + return errno_unwrap(ret, int) +} + +sendto :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg, addr: ^$T) -> (int, Errno) +where + T == Sock_Addr_In || + T == Sock_Addr_In6 || + T == Sock_Addr_Any +{ + ret := syscall(SYS_sendto, sock, raw_data(buf), len(buf), transmute(i32) flags, addr, size_of(T)) + return errno_unwrap(ret, int) +} + +@private +send_noaddr :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg) -> (int, Errno) { + ret := syscall(SYS_sendto, sock, raw_data(buf), len(buf), transmute(i32) flags, cast(rawptr) nil, cast(uintptr) 0) + return errno_unwrap(ret, int) +} + +/// Receive a message from a socket +/// Available since Linux 2.0 +recv :: proc {recvfrom, recv_noaddr} + +/// Send a message through a socket +/// Available since Linux 2.0 +send :: proc {sendto, send_noaddr} + +// TODO(flysand): sendmsg + +// TODO(flysand): recvmsg + +shutdown :: proc "contextless" (sock: Fd, how: Shutdown_How) -> (Errno) { + ret := syscall(SYS_shutdown, sock, how) + return Errno(-ret) +} + +/// Bind a socket to the given local address +/// Available since Linux 2.0 +bind :: proc "contextless" (sock: Fd, addr: ^$T) -> (Errno) +where + T == Sock_Addr_In || + T == Sock_Addr_In6 || + T == Sock_Addr_Any +{ + ret := syscall(SYS_bind, sock, addr, size_of(T)) + return Errno(-ret) +} + +/// Marks the socket as a socket that listen to connections using accept.2 +/// Available since Linux 2.0 +listen :: proc "contextless" (sock: Fd, queue_len: i32) -> (Errno) { + ret := syscall(SYS_listen, sock, queue_len) + return Errno(-ret) +} + +// TODO(flysand): getsockname + +// TODO(flysand): getpeername + +// TODO(flysand): socketpair + +// TODO(flysand): the parameters are the same, maybe there's a way to make it into a single proc, sacrificing type +// safety slightly +// TODO(flysand): add ability to specify slices +setsockopt_base :: proc "contextless" (sock: Fd, level: int, opt: int, val: $T) -> (Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + val_data := val + val_size := size_of(intrinsics.type_elem_type(T)) + ret := syscall(SYS_setsockopt, sock, level, opt, val_data, val_size) + return Errno(-ret) +} + +setsockopt_sock :: proc "contextless" (sock: Fd, level: Socket_API_Level_Sock, opt: Socket_Option, val: $T) -> (Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + return setsockopt_base(sock, cast(int) level, cast(int) opt, val) +} + +setsockopt_tcp :: proc "contextless" (sock: Fd, level: Socket_API_Level_TCP, opt: Socket_TCP_Option, val: $T) -> (Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + return setsockopt_base(sock, cast(int) level, cast(int) opt, val) +} + +setsockopt_udp :: proc "contextless" (sock: Fd, level: Socket_API_Level_UDP, opt: Socket_UDP_Option, val: $T) -> (Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + return setsockopt_base(sock, cast(int) level, cast(int) opt, val) +} + +/// Set socket option for a given socket API level +/// Available since Linux 2.0 +setsockopt :: proc { + setsockopt_sock, + setsockopt_tcp, + setsockopt_udp, + setsockopt_base, +} + +getsockopt_base :: proc "contextless" (sock: Fd, level: int, opt: Socket_Option, val: $T) -> (int, Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + val_data := val + val_size := size_of(T) + ret := syscall(SYS_getsockopt, sock, level, opt, val_data, cast(rawptr) &val_size) + return val_size, Errno(-ret) +} + +getsockopt_sock :: proc "contextless" (sock: Fd, level: Socket_API_Level_Sock, opt: Socket_Option, val: ^$T) -> (int, Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + return getsockopt_base(sock, cast(int) level, cast(int) opt, val) +} + +getsockopt_tcp :: proc "contextless" (sock: Fd, level: Socket_API_Level_TCP, opt: Socket_TCP_Option, val: ^$T) -> (int, Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + return getsockopt_base(sock, cast(int) level, cast(int) opt, val) +} + +getsockopt_udp :: proc "contextless" (sock: Fd, level: Socket_API_Level_UDP, opt: Socket_UDP_Option, val: ^$T) -> (int, Errno) +where + intrinsics.type_is_pointer(T) || + intrinsics.type_is_multi_pointer(T) +{ + return getsockopt_base(sock, cast(int) level, cast(int) opt, val) +} + +/// Get socket option for a given socket API level +/// Available since Linux 2.0 +getsockopt :: proc { + getsockopt_sock, + getsockopt_tcp, + getsockopt_udp, + getsockopt_base, +} + +// TODO(flysand): clone (probably not in this PR, maybe not ever) + +/// Creates a copy of the running process +/// Available since Linux 1.0 +fork :: proc "contextless" () -> (Pid, Errno) { + when ODIN_ARCH == .arm64 { + // Note(flysand): this syscall is not documented, but the bottom 8 bits of flags + // are for exit signal + ret := syscall(SYS_clone, Signal.SIGCHLD) + return errno_unwrap(ret, Pid) + } else { + ret := syscall(SYS_fork) + return errno_unwrap(ret, Pid) + } +} + +// TODO(flysand): vfork + +// TODO(flysand): execve + +/// Exit the thread with a given exit code +/// Available since Linux 1.0 +exit :: proc "contextless" (code: i32) -> ! { + syscall(SYS_exit, code) + unreachable() +} + +/// Wait for the process to change state +/// Available since Linux 1.0 +wait4 :: proc "contextless" (pid: Pid, status: ^u32, options: Wait_Options) -> (Pid, Errno) { + ret := syscall(SYS_wait4, pid, status, transmute(u32) options) + return errno_unwrap(ret, Pid) +} + +/// See wait4 +waitpid :: wait4 + +// TODO(flysand): kill + +/// Get system information +/// Available since Linux 1.0 +uname :: proc "contextless" (uts_name: ^UTS_Name) -> (Errno) { + ret := syscall(SYS_uname, uts_name) + return Errno(-ret) +} + +// TODO(flysand): semget + +// TODO(flysand): semop + +// TODO(flysand): semctl + +// TODO(flysand): shmdt + +// TODO(flysand): msgget + +// TODO(flysand): msgsnd + +// TODO(flysand): msgrcv + +// TODO(flysand): msgctl + +fcntl_dupfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_DUPFD, newfd: Fd) -> (Fd, Errno) { + ret := syscall(SYS_fcntl, fd, cmd, newfd) + return errno_unwrap(ret, Fd) +} + +fcntl_dupfd_cloexec :: proc "contextless" (fd: Fd, cmd: FCntl_Command_DUPFD_CLOEXEC, newfd: Fd) -> (Fd, Errno) { + ret := syscall(SYS_fcntl, fd, cmd, newfd) + return errno_unwrap(ret, Fd) +} + +fcntl_getfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETFD) -> (Fd, Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return errno_unwrap(ret, Fd) +} + +fcntl_setfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETFD, newfd: Fd) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, newfd) + return Errno(-ret) +} + +fcntl_getfl :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETFL) -> (Open_Flags, Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return errno_unwrap(u32(ret), Open_Flags, Open_Flags) +} + +fcntl_setfl :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETFL, flags: Open_Flags) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, transmute(u32) flags) + return Errno(-ret) +} + +fcntl_setlk :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETLK, lock: ^FLock) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_fcntl64, fd, cmd, lock) + return Errno(-ret) + } else { + ret := syscall(SYS_fcntl, fd, cmd, lock) + return Errno(-ret) + } +} + +fcntl_setlkw :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETLKW, lock: ^FLock) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_fcntl64, fd, cmd, lock) + return Errno(-ret) + } else { + ret := syscall(SYS_fcntl, fd, cmd, lock) + return Errno(-ret) + } +} + +fcntl_getlk :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETLK, lock: ^FLock) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_fcntl64, fd, cmd, lock) + return Errno(-ret) + } else { + ret := syscall(SYS_fcntl, fd, cmd, lock) + return Errno(-ret) + } +} + +fcntl_getown_ex :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETOWN_EX, owner: ^F_Owner) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, owner) + return Errno(-ret) +} + +fcntl_setown_ex :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETOWN_EX, owner: ^F_Owner) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, owner) + return Errno(-ret) +} + +fcntl_getsig :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETSIG) -> (Signal, Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return errno_unwrap(ret, Signal) +} + +fcntl_setsig :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETSIG, sig: Signal) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, sig) + return Errno(-ret) +} + +fcntl_setlease :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETLEASE, lease: FD_Lease) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, lease) + return Errno(-ret) +} + +fcntl_getlease :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETLEASE) -> (FD_Lease, Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return errno_unwrap(ret, FD_Lease) +} + +fcntl_notify :: proc "contextless" (fd: Fd, cmd: FCntl_Command_NOTIFY, notifications: FD_Notifications) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return Errno(-ret) +} + +fcntl_setpipe_sz :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETPIPE_SZ, sz: i32) -> (i32, Errno) { + ret := syscall(SYS_fcntl, fd, cmd, sz) + return errno_unwrap(ret, i32) +} + +fcntl_getpipe_sz :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETPIPE_SZ) -> (i32, Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return errno_unwrap(ret, i32) +} + +fcntl_add_seals :: proc "contextless" (fd: Fd, cmd: FCntl_Command_ADD_SEALS, seal: Seal) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, transmute(i32) seal) + return Errno(-ret) +} + +fcntl_get_seals :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GET_SEALS) -> (Seal, Errno) { + ret := syscall(SYS_fcntl, fd, cmd) + return errno_unwrap(i32(ret), Seal, Seal) +} + +fcntl_get_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GET_RW_HINT, hint: ^RW_Hint) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, hint) + return Errno(-ret) +} + +fcntl_set_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SET_RW_HINT, hint: ^RW_Hint) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, hint) + return Errno(-ret) +} + +fcntl_get_file_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GET_FILE_RW_HINT, hint: ^RW_Hint) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, hint) + return Errno(-ret) +} + +fcntl_set_file_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SET_FILE_RW_HINT, hint: ^RW_Hint) -> (Errno) { + ret := syscall(SYS_fcntl, fd, cmd, hint) + return Errno(-ret) +} + +fcntl :: proc { + fcntl_dupfd, + fcntl_dupfd_cloexec, + fcntl_getfd, + fcntl_setfd, + fcntl_getfl, + fcntl_setfl, + fcntl_setlk, + fcntl_setlkw, + fcntl_getlk, + fcntl_getown_ex, + fcntl_setown_ex, + fcntl_getsig, + fcntl_setsig, + fcntl_setlease, + fcntl_getlease, + fcntl_notify, + fcntl_setpipe_sz, + fcntl_getpipe_sz, + fcntl_add_seals, + fcntl_get_seals, + fcntl_get_rw_hint, + fcntl_set_rw_hint, + fcntl_get_file_rw_hint, + fcntl_set_file_rw_hint, +} + +// TODO(flysand): flock + +/// Sync state of the file with the storage device +fsync :: proc "contextless" (fd: Fd) -> (Errno) { + ret := syscall(SYS_fsync, fd) + return Errno(-ret) +} + +// TODO(flysand): fdatasync + +/// Truncate a file to specified length +/// On 32-bit architectures available since Linux 2.4 +truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length)) + return Errno(-ret) + } else { + ret := syscall(SYS_truncate, cast(rawptr) name, compat64_arg_pair(length)) + return Errno(-ret) + } +} + +/// Truncate a file specified by file descriptor to specified length +/// On 32-bit architectures available since 2.4 +ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length)) + return Errno(-ret) + } else { + ret := syscall(SYS_truncate, fd, compat64_arg_pair(length)) + return Errno(-ret) + } +} + +/// Retrieve the contents of the directory specified by dirfd +/// Returns the number of bytes written +/// Available since Linux 2.4 +getdents :: proc "contextless" (dirfd: Fd, buf: []u8) -> (int, Errno) { + ret := syscall(SYS_getdents64, dirfd, raw_data(buf), len(buf)) + return errno_unwrap(ret, int) +} + +/// Get current working directory +/// Available since Linux 1.0 +getcwd :: proc "contextless" (buf: []u8) -> (int, Errno) { + ret := syscall(SYS_getcwd, raw_data(buf), len(buf)) + return errno_unwrap(ret, int) +} + +/// Change working directory to the directory specified by path +/// Available since Linux 1.0 +chdir :: proc "contextless" (path: cstring) -> (Errno) { + ret := syscall(SYS_chdir, cast(rawptr) path) + return Errno(-ret) +} + +/// Change working directory to the directory specified by dirfd +/// Available since Linux 1.0 +fchdir :: proc "contextless" (fd: Fd) -> (Errno) { + ret := syscall(SYS_fchdir, fd) + return Errno(-ret) +} + +/// Rename (move) the file +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +rename :: proc "contextless" (old: cstring, new: cstring) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_renameat, AT_FDCWD, cast(rawptr) old, AT_FDCWD, cast(rawptr) new) + return Errno(-ret) + } else { + ret := syscall(SYS_rename, cast(rawptr) old, cast(rawptr) new) + return Errno(-ret) + } +} + +/// Creates a directory +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +mkdir :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_mkdirat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode) + return Errno(-ret) + } else { + ret := syscall(SYS_mkdir, cast(rawptr) name, transmute(u32) mode) + return Errno(-ret) + } +} + +/// Remove a directory specified by name +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +rmdir :: proc "contextless" (name: cstring) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_unlinkat, AT_FDCWD, cast(rawptr) name, transmute(i32) FD_Flags{.REMOVEDIR}) + return Errno(-ret) + } else { + ret := syscall(SYS_rmdir, cast(rawptr) name) + return Errno(-ret) + } +} + +// TODO(flysand): creat + +/// Create a hard link on a file +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath) + return Errno(-ret) + } else { + ret := syscall(SYS_link, cast(rawptr) target, cast(rawptr) linkpath) + return Errno(-ret) + } +} + +/// Delete a name, and possible a file it refers to +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +unlink :: proc "contextless" (name: cstring) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_unlinkat, AT_FDCWD, cast(rawptr) name, 0) + return Errno(-ret) + } else { + ret := syscall(SYS_unlink, cast(rawptr) name) + return Errno(-ret) + } +} + +/// Create a symbolic link +/// Available since Linux 1.0 +/// On arm64 available since Linux 2.6.16 +symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_symlinkat, AT_FDCWD, cast(rawptr) target, cast(rawptr) linkpath) + return Errno(-ret) + } else { + ret := syscall(SYS_symlink, cast(rawptr) target, cast(rawptr) linkpath) + return Errno(-ret) + } +} + +/// Read the value of a symbolic link +/// Available since Linux 1.0 +/// On arm64 available since Linux 2.6.16 +readlink :: proc "contextless" (name: cstring, buf: []u8) -> (int, Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_readlinkat, AT_FDCWD, cast(rawptr) name, raw_data(buf), len(buf)) + return errno_unwrap(ret, int) + } else { + ret := syscall(SYS_readlink, cast(rawptr) name, raw_data(buf), len(buf)) + return errno_unwrap(ret, int) + } +} + +/// Change file permissions +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +chmod :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_fchmodat, cast(rawptr) name, transmute(u32) mode, 0) + return Errno(-ret) + } else { + ret := syscall(SYS_chmod, cast(rawptr) name, transmute(u32) mode) + return Errno(-ret) + } +} + +/// Change file permissions through a file descriptor +/// Available since Linux 1.0 +fchmod :: proc "contextless" (fd: Fd, mode: Mode) -> (Errno) { + ret := syscall(SYS_fchmod, fd, transmute(u32) mode) + return Errno(-ret) +} + +/// Change ownership of a file +/// Available since Linux 2.2 +/// On 32-bit architectures available since Linux 2.4 +/// On ARM64 available since Linux 2.6.16 +chown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_chown32, cast(rawptr) name, uid, gid) + return Errno(-ret) + } else when ODIN_ARCH == .arm64 { + ret := syscall(SYS_fchownat, AT_FDCWD, cast(rawptr) name, uid, gid, 0) + return Errno(-ret) + } else { + ret := syscall(SYS_chown, cast(rawptr) name, uid, gid) + return Errno(-ret) + } +} + +/// Change ownership of a file by file descriptor +/// Available since Linux 1.0 +/// On 32-bit architecvtures available since Linux 2.4 +fchown :: proc "contextless" (fd: Fd, uid: Uid, gid: Gid) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_fchown32, fd, uid, gid) + return Errno(-ret) + } else { + ret := syscall(SYS_fchown, fd, uid, gid) + return Errno(-ret) + } +} + +/// Change ownership of a file. Unlike chown, if a file is a symlink dooesn't dereference it +/// Available since Linux 1.0 +/// On 32-bit architectures available since Linux 2.4 +/// On ARM64 available since Linux 2.6.16 +lchown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_lchown32, cast(rawptr) name, uid, gid) + return Errno(-ret) + } else when ODIN_ARCH == .arm64 { + ret := syscall(SYS_fchownat, AT_FDCWD, cast(rawptr) name, uid, gid, transmute(i32) FD_Flags{.SYMLINK_NOFOLLOW}) + return Errno(-ret) + } else { + ret := syscall(SYS_lchown, cast(rawptr) name, uid, gid) + return Errno(-ret) + } +} + +// TODO(flysand): umask + +// TODO(flysand): gettimeofday + +/// Get limits on resources +/// Available since Linux 1.0 +getrlimit :: proc "contextless" (kind: RLimit_Kind, resource: ^RLimit) -> (Errno) { + ret := syscall(SYS_getrlimit, kind, resource) + return Errno(-ret) +} + +/// Get resource usage +/// Available since Linux 1.0 +getrusage :: proc "contextless" (who: RUsage_Who, rusage: ^RUsage) -> (Errno) { + ret := syscall(SYS_getrusage, who, rusage) + return Errno(-ret) +} + +/// Get information about the system +sysinfo :: proc "contextless" (sysinfo: ^Sys_Info) -> (Errno) { + ret := syscall(SYS_sysinfo, sysinfo) + return Errno(-ret) +} + +/// Get current process times +/// Available since Linux 1.0 +times :: proc "contextless" (tms: ^Tms) -> (Errno) { + ret := syscall(SYS_times, cast(rawptr) tms) + return Errno(-ret) +} + +// TODO(flysand): ptrace + +/// Get real user ID +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +getuid :: proc "contextless" () -> Uid { + when size_of(int) == 8 { + return cast(Uid) syscall(SYS_getuid) + } else { + return cast(Uid) syscall(SYS_getuid32) + } +} + +// TODO(flysand): syslog + +/// Get real group ID +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +getgid :: proc "contextless" () -> Gid { + when size_of(int) == 8 { + return cast(Gid) syscall(SYS_getgid) + } else { + return cast(Gid) syscall(SYS_getgid32) + } +} + +/// Set effective user id +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +@(require_results) +setuid :: proc "contextless" (uid: Uid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_setuid, uid) + return Errno(-ret) + } else { + ret := syscall(SYS_setuid32, uid) + return Errno(-ret) + } +} + +/// Set effective group id +/// If the process is privileged also sets real group id +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +@(require_results) +setgid :: proc "contextless" (gid: Gid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_setgid, gid) + return Errno(-ret) + } else { + ret := syscall(SYS_setgid32, gid) + return Errno(-ret) + } +} + +/// Get effective user ID +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +geteuid :: proc "contextless" () -> Uid { + when size_of(int) == 8 { + return cast(Uid) syscall(SYS_geteuid) + } else { + return cast(Uid) syscall(SYS_geteuid32) + } +} + +/// Get effective group ID +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +getegid :: proc "contextless" () -> Gid { + when size_of(int) == 8 { + return cast(Gid) syscall(SYS_getegid) + } else { + return cast(Gid) syscall(SYS_getegid32) + } +} + +/// Set process group +/// Available since Linux 1.0 +setpgid :: proc "contextless" (pid: Pid, pgid: Pid) -> (Errno) { + ret := syscall(SYS_setpgid, pid, pgid) + return Errno(-ret) +} + +/// Get the parent process ID +/// Available since Linux 1.0 +getppid :: proc "contextless" () -> Pid { + return cast(Pid) syscall(SYS_getppid) +} + +/// Get process group +/// Available since Linux 1.0 +getpgrp :: proc "contextless" () -> (Pid, Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_getpgid, 0) + return errno_unwrap(ret, Pid) + } else { + ret := syscall(SYS_getpgrp) + return errno_unwrap(ret, Pid) + } +} + +/// Create a session and set the process group ID +/// Available since Linux 2.0 +setsid :: proc "contextless" () -> (Errno) { + ret := syscall(SYS_setsid) + return Errno(-ret) +} + +/// Set real and/or effective user id +/// If any of the arguments is -1, the corresponding id is not changed +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +@(require_results) +setreuid :: proc "contextless" (real: Uid, effective: Uid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_setreuid, real, effective) + return Errno(-ret) + } else { + ret := syscall(SYS_setreuid32, real, effective) + return Errno(-ret) + } +} + +/// Set real and/or effective group id +/// If any of the arguments is -1, the corresponding id is not changed +/// Available since Linux 1.0 +/// On 32-bit platforms available since Linux 2.4 +@(require_results) +setregid :: proc "contextless" (real: Gid, effective: Gid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_setregid, real, effective) + return Errno(-ret) + } else { + ret := syscall(SYS_setregid32, real, effective) + return Errno(-ret) + } +} + +// TODO(flysand): getgroups + +// TODO(flysand): setgroups + +/// Set real, effective and/or saved user id +/// If any of the arguments is -1, the corresponding id is not changed +/// Available since Linux 2.2 +/// On 32-bit platforms available since Linux 2.4 +@(require_results) +setresuid :: proc "contextless" (real: Uid, effective: Uid, saved: Uid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_setresuid, real, effective, saved) + return Errno(-ret) + } else { + ret := syscall(SYS_setresuid32, real, effective, saved) + return Errno(-ret) + } +} + +/// Get real, effective and saved user id +/// Available since Linux 2.2 +/// On 32-bit platforms available since Linux 2.4 +getresuid :: proc "contextless" (real: ^Uid, effective: ^Uid, saved: ^Uid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_getresuid, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved) + return Errno(-ret) + } else { + ret := syscall(SYS_getresuid32, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved) + return Errno(-ret) + } +} + +/// Set real, effective and/or saved group id +/// If any of the arguments is -1, the corresponding id is not changed +/// Available since Linux 2.2 +/// On 32-bit platforms available since Linux 2.4 +@(require_results) +setresgid :: proc "contextless" (real: Gid, effective: Gid, saved: Uid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_setresgid, real, effective, saved) + return Errno(-ret) + } else { + ret := syscall(SYS_setresgid32, real, effective, saved) + return Errno(-ret) + } +} + +/// Get real, effective and saved group id +/// Available since Linux 2.2 +/// On 32-bit platforms available since Linux 2.4 +getresgid :: proc "contextless" (real: ^Gid, effective: ^Gid, saved: ^Gid) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_getresgid, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved) + return Errno(-ret) + } else { + ret := syscall(SYS_getresgid32, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved) + return Errno(-ret) + } +} + +/// Get process group +/// Available since Linux 1.0 +getpgid :: proc "contextless" (pid: Pid) -> (Pid, Errno) { + ret := syscall(SYS_getpgid, pid) + return errno_unwrap(ret, Pid) +} + +// NOTE(flysand): setfsuid and setfsgid are deprecated + +/// Get session ID of the calling process +/// Available since Linux 2.0 +getsid :: proc "contextless" (pid: Pid) -> (Pid, Errno) { + ret := syscall(SYS_getsid, pid) + return errno_unwrap(ret, Pid) +} + +// TODO(flysand): capget + +// TODO(flysand): capset + +/// Examine pending signals +/// Available since Linux 2.2 +rt_sigpending :: proc "contextless" (sigs: ^Sig_Set) -> Errno { + ret := syscall(SYS_rt_sigpending, sigs, size_of(Sig_Set)) + return Errno(-ret) +} + +/// Synchronously wait for queued signals +/// Available since Linux 2.2 +rt_sigtimedwait :: proc "contextless" (sigs: ^Sig_Set, info: ^Sig_Info, time_sus: ^Time_Spec) -> (Signal, Errno) { + ret := syscall(SYS_rt_sigtimedwait, sigs, info, time_sus, size_of(Sig_Set)) + return errno_unwrap(ret, Signal) +} + +/// Send signal information to a process +/// Available since Linux 2.2 +rt_sigqueueinfo :: proc "contextless" (pid: Pid, sig: Signal, si: ^Sig_Info) -> (Errno) { + ret := syscall(SYS_rt_sigqueueinfo, pid, sig, si) + return Errno(-ret) +} + +/// Replace the signal mask for a value with the new mask until a signal is received +/// Available since Linux 2.2 +rt_sigsuspend :: proc "contextless" (sigset: ^Sig_Set) -> Errno { + ret := syscall(SYS_rt_sigsuspend, sigset, size_of(Sig_Set)) + return Errno(-ret) +} + +/// Set or get signal stack context +/// Available since Linux 2.2 +sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) -> (Errno) { + ret := syscall(SYS_sigaltstack, stack, old_stack) + return Errno(-ret) +} + +// TODO(flysand): utime + +/// Create a special or ordinary file +/// `mode` parameter contains both the the file mode and the type of the node to create +/// -> Add one of S_IFSOCK, S_IFBLK, S_IFFIFO, S_IFCHR to mode +/// Available since Linux 1.0 +/// On ARM64 available since Linux 2.6.16 +mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) { + when ODIN_ARCH == .arm64 { + ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev) + return Errno(-ret) + } else { + ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, dev) + return Errno(-ret) + } +} + +// TODO(flysand): uselib + +/// Set the process execution domain +/// Available since Linux 1.2 +personality :: proc "contextless" (personality: uint) -> (uint, Errno) { + ret := syscall(SYS_personality, personality) + return errno_unwrap(ret, uint) +} + +// TODO(flysand): ustat + +/// Query information about filesystem +/// +/// Available since Linux 1.0 +/// For 32-bit systems a different syscall is used that became available since 2.6 +statfs :: proc "contextless" (path: cstring, statfs: ^Stat_FS) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_statfs, transmute(uintptr) path, statfs) + return Errno(-ret) + } else { + ret := syscall(SYS_statfs64, cast(rawptr) path, size_of(Stat_FS), statfs) + return Errno(-ret) + } +} + +/// Query information about filesystem by file descriptor +/// +/// Available since Linux 1.0 +/// For 32-bit systems a different syscall is used that became available since 2.6 +fstatfs :: proc "contextless" (fd: Fd, statfs: ^Stat_FS) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_statfs, fd, statfs) + return Errno(-ret) + } else { + ret := syscall(SYS_statfs64, fd, size_of(Stat_FS), statfs) + return Errno(-ret) + } +} + +// TODO(flysand): sysfs + +/// Get priority on user, process group or process +/// Available since Linux 1.0 +getpriority :: proc "contextless" (which: Priority_Which, who: i32) -> (i32, Errno) { + ret := syscall(SYS_getpriority, which, who) + prio, err := errno_unwrap(ret, i32) + // NOTE(flysand): getpriority will return `20 - priority` to avoid returning + // negative priorities as errors + prio = 20 - prio + return prio, err +} + +/// Set priority on user, process group or process +/// Available since Linux 1.0 +setpriority :: proc "contextless" (which: Priority_Which, who: i32, prio: i32) -> (Errno) { + ret := syscall(SYS_setpriority, which, who, prio) + return Errno(-ret) +} + +// TODO(flysand): sched_setparam + +// TODO(flysand): sched_getparam + +// TODO(flysand): sched_setscheduler + +// TODO(flysand): sched_getscheduler + +// TODO(flysand): sched_get_priority_max + +// TODO(flysand): sched_get_priority_min + +// TODO(flysand): sched_rr_get_interval + +/// Lock and memory +/// Available since Linux 2.0 +/// If flags specified, available since Linux 4.4 +mlock :: proc "contextless" (addr: rawptr, size: uint, flags: MLock_Flags = {}) -> (Errno) { + // Pretty darn recent syscall, better call simpler version if we can + if flags > {} { + ret := syscall(SYS_mlock2, addr, size, transmute(i32) flags) + return Errno(-ret) + } else { + ret := syscall(SYS_mlock, addr, size) + return Errno(-ret) + } +} + +/// Unlock memory +/// Available since Linux 2.0 +munlock :: proc "contextless" (addr: rawptr, size: uint) -> (Errno) { + ret := syscall(SYS_munlock, addr, size) + return Errno(-ret) +} + +/// Lock all memory +mlockall :: proc "contextless" (flags: MLock_Flags = {}) -> (Errno) { + ret := syscall(SYS_mlockall, transmute(i32) flags) + return Errno(-ret) +} + +/// Unlock all memory +munlockall :: proc "contextless" () -> (Errno) { + ret := syscall(SYS_munlockall) + return Errno(-ret) +} + +// TODO(flysand): vhangup + +// TODO(flysand): modify_ldt + +// TODO(flysand): pivot_root + +// TODO(flysand): _sysctl + +// TODO(flysand): prctl + +// TODO(flysand): arch_prctl + +// TODO(flysand): adj_timex + +/// Set limits on resources +/// Available since Linux 1.0 +setrlimit :: proc "contextless" (kind: RLimit_Kind, resource: ^RLimit) -> (Errno) { + ret := syscall(SYS_setrlimit, kind, resource) + return Errno(-ret) +} + +// TODO(flysand): sync + +// TODO(flysand): acct + +// TODO(flysand): settimeofday + +// TODO(flysand): mount + +// TODO(flysand): umount2 + +// TODO(flysand): swapon + +// TODO(flysand): swapoff + +// TODO(flysand): reboot + +/// Set hostname +/// Note: to get the host name, use `uname` syscall +/// Available since Linux 1.0 +sethostname :: proc "contextless" (hostname: string) -> (Errno) { + ret := syscall(SYS_sethostname, raw_data(hostname), len(hostname)) + return Errno(-ret) +} + +/// Set domain name +/// Note: to get the domain name, use `uname` syscall +/// Available since Linux 2.2 +setdomainname :: proc "contextless" (name: string) -> (Errno) { + ret := syscall(SYS_setdomainname, raw_data(name), len(name)) + return Errno(-ret) +} + +// TODO(flysand): iopl + +// TODO(flysand): ioperm + +// TODO(flysand): create_module + +// TODO(flysand): init_module + +// TODO(flysand): delete_module + +// TODO(flysand): get_kernel_syms + +// TODO(flysand): query_module + +// TODO(flysand): quotactl + +// TODO(flysand): nfsservctl + +// TODO(flysand): getpmsg + +// TODO(flysand): putpmsg + +// TODO(flysand): afs_syscall + +// TODO(flysand): tuxcall + +// TODO(flysand): security + +/// Returns the thread ID of the current process +/// This is what the kernel calls "pid" +/// Let me insert a tiny rant here, this terminology is confusing: +/// sometimes pid refers to a thread, and other times it refers +/// to a thread group (process group?) +/// Anyway, this syscall is available since Linux 1.0 +gettid :: proc "contextless" () -> Pid { + return cast(Pid) syscall(SYS_gettid) +} + +// TODO(flysand): readahead + +// TODO(flysand): setxattr + +// TODO(flysand): lsetxattr + +// TODO(flysand): fsetxattr + +// TODO(flysand): getxattr + +// TODO(flysand): lgetxattr + +// TODO(flysand): fgetxattr + +// TODO(flysand): listxattr + +// TODO(flysand): llistxattr + +// TODO(flysand): flistxattr + +// TODO(flysand): removexattr + +// TODO(flysand): lremovexattr + +// TODO(flysand): fremovexattr + +// TODO(flysand): tkill + +// TODO(flysand): time + +/// Wait on a futex until it's signaled +futex_wait :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Type, flags: Futex_Flags, val: u32, timeout: ^Time_Spec = nil) -> (Errno) { + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, val, timeout) + return Errno(-ret) +} + +/// Wake up other threads on a futex +/// n_wakeup specifies the number of processes to wakeup. Specify max(i32) to wake up all processes waiting +futex_wake :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Type, flags: Futex_Flags, n_wakeup: i32) -> (int, Errno) { + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, n_wakeup) + return errno_unwrap(ret, int) +} + +// NOTE(flysand): futex_fd is racy, so not implemented + +/// Requeues processes waiting on futex `futex` to wait on futex `requeue_futex` +/// `requeue_threshold` specifies the maximum amount of waiters to wake up, the rest of the waiters will be requeued +/// `requeue_max` specifies the maximum amount of waiters that are required at `requeue_futex` +/// The operation blocks until the `requeue_max` requirement is satisfied +/// If the value of the mutex is not equal to `val`, fails with EAGAIN before any further checks +/// Returns the total number of waiters that have been woken up plus the number of waiters requeued +futex_cmp_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Cmp_Requeue_Type, flags: Futex_Flags, requeue_threshold: u32, + requeue_max: i32, requeue_futex: ^Futex, val: i32) -> (int, Errno) +{ + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, requeue_threshold, requeue_max, requeue_futex, val) + return errno_unwrap(ret, int) +} + +/// See `futex_cmp_requeue`, this function does the same thing but doesn't check the value of the futex +/// Returns the total number of waiters that have been woken up +futex_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Requeue_Type, flags: Futex_Flags, requeue_threshold: u32, + requeue_max: i32, requeue_futex: ^Futex) -> (int, Errno) +{ + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, requeue_threshold, requeue_max, requeue_futex) + return errno_unwrap(ret, int) +} + +/// Okay, for this one, see the man pages, the description for it is pretty long and very specific. It's sole +/// purpose is to allow implementing conditional values sync primitive, it seems like +futex_wake_op :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Op_Type, flags: Futex_Flags, wakeup: i32, + dst_wakeup, dst: ^Futex, futex_op: u32) -> (int, Errno) +{ + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, wakeup, dst_wakeup, dst, futex_op) + return errno_unwrap(ret, int) +} + +/// Same as wait, but mask specifies bits that must be equal for the mutex to wake up +futex_wait_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Bitset_Type, flags: Futex_Flags, val: u32, + timeout: ^Time_Spec, mask: u32) -> (int, Errno) +{ + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, val, timeout, 0, mask) + return errno_unwrap(ret, int) +} + +/// Wake up on bitset +futex_wake_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Bitset_Type, flags: Futex_Flags, n_wakeup: u32, mask: u32) -> (int, Errno) +{ + futex_flags := cast(u32) op + transmute(u32) flags + ret := syscall(SYS_futex, futex, futex_flags, n_wakeup, 0, 0, mask) + return errno_unwrap(ret, int) +} + +// TODO(flysand): Priority inheritance (PI) futicees + +futex :: proc { + futex_wait, + futex_wake, + futex_cmp_requeue, + futex_requeue, + futex_wake_op, + futex_wait_bitset, + futex_wake_bitset, +} + +// TODO(flysand): sched_setaffinity + +// TODO(flysand): sched_getaffinity + +// TODO(flysand): set_thread_area + +// TODO(flysand): io_setup + +// TODO(flysand): io_destroy + +// TODO(flysand): io_getevents + +// TODO(flysand): io_submit + +// TODO(flysand): io_cancel + +// TODO(flysand): get_thread_area + +// TODO(flysand): lookup_dcookie + +// TODO(flysand): epoll_create + +// TODO(flysand): epoll_ctl_old + +// TODO(flysand): epoll_wait_old + +// TODO(flysand): remap_file_pages + +/// Set the address of the futex that's gonna be waken when +/// current thread terminates +/// Available since Linux 2.6 +set_tid_address :: proc "contextless" (tidptr: ^u32) { + syscall(SYS_set_tid_address, tidptr) +} + +// TODO(flysand): restart_syscall + +// TODO(flysand): semtimedop + +// TODO(flysand): fadvise64 + +// TODO(flysand): timer_create + +// TODO(flysand): timer_settime + +// TODO(flysand): timer_gettime + +// TODO(flysand): timer_getoverrun + +// TODO(flysand): timer_delete + +// TODO(flysand): clock_settime + +// TODO(flysand): clock_gettime + +// TODO(flysand): clock_getres + +// TODO(flysand): clock_nanosleep + +/// Exit the thread group +/// Available since Linux 2.6 +exit_group :: proc "contextless" (code: i32) -> ! { + syscall(SYS_exit_group, code) + unreachable() +} + +// TODO(flysand): epoll_wait + +// TODO(flysand): epoll_ctl + +// TODO(flysand): tgkill + +// TODO(flysand): utimes + +// TODO(flysand): vserver + +// TODO(flysand): mbind + +// TODO(flysand): set_mempolicy + +// TODO(flysand): get_mempolicy + +// TODO(flysand): mq_open + +// TODO(flysand): mq_unlink + +// TODO(flysand): mq_timedsend + +// TODO(flysand): mq_timedreceive + +// TODO(flysand): mq_notify + +// TODO(flysand): mq_getsetattr + +// TODO(flysand): kexec_load + + +/// Wait on process, process group or pid file descriptor +/// Available since Linux 2.6.10 +waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, options: Wait_Options) -> (Errno) { + ret := syscall(SYS_waitid, id_type, id, sig_info, transmute(i32) options) + return Errno(-ret) +} + +// TODO(flysand): add_key + +// TODO(flysand): request_key + +// TODO(flysand): keyctl + +// TODO(flysand): ioprio_set + +// TODO(flysand): ioprio_get + +// TODO(flysand): inotify_init + +// TODO(flysand): inotify_add_watch + +// TODO(flysand): inotify_rm_watch + +// TODO(flysand): migrate_pages + +/// Open file at the specified file descriptor +/// Available since Linux 2.6.16 +openat :: proc "contextless" (fd: Fd, name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) { + ret := syscall(SYS_openat, fd, AT_FDCWD, transmute(uintptr) name, transmute(u32) mode) + return errno_unwrap(ret, Fd) +} + +/// Create a directory relative to specified dirfd +/// Available since Linux 2.6.16 +mkdirat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode) -> (Errno) { + ret := syscall(SYS_mkdirat, dirfd, cast(rawptr) name, transmute(u32) mode) + return Errno(-ret) +} + +/// Create a special or ordinary file wrt given directory specified by dirfd +/// Available since Linux 2.6.16 +mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) { + ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, dev) + return Errno(-ret) +} + +/// Change the ownership of the file specified relative to directory +/// Available since Linux 2.6.16 +fchownat :: proc "contextless" (dirfd: Fd, name: cstring, uid: Uid, gid: Gid) -> (Errno) { + ret := syscall(SYS_fchownat, dirfd, cast(rawptr) name, uid, gid) + return Errno(-ret) +} + +// TODO(flysand): futimesat + +/// Get information about a file at a specific directory +/// Available since Linux 2.6.16 +fstatat :: proc "contextless" (dirfd: Fd, name: cstring, stat: ^Stat, flags: FD_Flags) -> (Errno) { + when size_of(int) == 4 { + ret := syscall(SYS_fstatat64, dirfd, cast(rawptr) name, stat, transmute(i32) flags) + return Errno(-ret) + } else when ODIN_ARCH == .amd64 { + ret := syscall(SYS_newfstatat, dirfd, cast(rawptr) name, stat, transmute(i32) flags) + return Errno(-ret) + } else { + ret := syscall(SYS_fstatat, dirfd, cast(rawptr) name, stat, transmute(i32) flags) + return Errno(-ret) + } +} + +/// Remove a directory entry relative to a directory file descriptor +/// Available since Linux 2.6.16 +unlinkat :: proc "contextless" (dirfd: Fd, name: cstring, flags: FD_Flags) -> (Errno) { + ret := syscall(SYS_unlinkat, dirfd, cast(rawptr) name, transmute(i32) flags) + return Errno(-ret) +} + +/// Rename the file with names relative to the specified dirfd's +/// Available since Linux 2.6.16 +renameat :: proc "contextless" (oldfd: Fd, old: cstring, newfd: Fd, new: cstring) -> (Errno) { + ret := syscall(SYS_renameat, oldfd, cast(rawptr) old, newfd, cast(rawptr) new) + return Errno(-ret) +} + +/// Creates a hard link on a file relative to specified dirfd +/// Available since Linux 2.6.16 +linkat :: proc "contextless" (target_dirfd: Fd, oldpath: cstring, link_dirfd: Fd, link: cstring, flags: FD_Flags) -> (Errno) { + ret := syscall(SYS_linkat, target_dirfd, cast(rawptr) oldpath, link_dirfd, cast(rawptr) link, transmute(i32) flags) + return Errno(-ret) +} + +/// Create a symbolic link at specified dirfd +/// Available since Linux 2.6.16 +symlinkat :: proc "contextless" (dirfd: Fd, target: cstring, linkpath: cstring) -> (Errno) { + ret := syscall(SYS_symlinkat, dirfd, cast(rawptr) target, cast(rawptr) linkpath) + return Errno(-ret) +} + +/// Read the value of a symbolic link at given dirfd +/// Available since Linux 2.6.16 +readlinkat :: proc "contextless" (dirfd: Fd, name: cstring, buf: []u8) -> (int, Errno) { + ret := syscall(SYS_readlinkat, dirfd, cast(rawptr) name, raw_data(buf), len(buf)) + return errno_unwrap(ret, int) +} + +/// Change the file mode at a specified file descriptor +/// Available since Linux 2.6.16 +fchmodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, flags: FD_Flags) -> (Errno) { + ret := syscall(SYS_fchmodat, cast(rawptr) name, transmute(u32) mode, transmute(i32) flags) + return Errno(-ret) +} + +/// Checks the user permissions for a file at specified dirfd +/// Available since Linux 2.6.16 +faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> (bool, Errno) { + ret := syscall(SYS_faccessat, dirfd, cast(rawptr) name, transmute(u32) mode) + return errno_unwrap(ret, bool) +} + +// TODO(flysand): pselect6 + +/// Wait for events on a file descriptor +/// Available since Linux 2.6.16 +ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (Errno) { + when size_of(int) == 8 { + ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) + return Errno(-ret) + } else { + ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set)) + return Errno(-ret) + } +} + +// TODO(flysand): unshare + +// TODO(flysand): set_robust_list + +// TODO(flysand): get_robust_list + +// TODO(flysand): splice + +// TODO(flysand): tee + +// TODO(flysand): sync_file_range + +// TODO(flysand): vmsplice + +// TODO(flysand): move_pages + +/// Change file timestamps with nanosecond precision +/// Available since Linux 2.6.22 +utimensat :: proc "contextless" (dirfd: Fd, name: cstring, timespec: ^Time_Spec, flags: FD_Flags) -> (Errno) { + ret := syscall(SYS_utimensat, dirfd, cast(rawptr) name, timespec, transmute(i32) flags) + return Errno(-ret) +} + +// TODO(flysand): epoll_pwait + +// TODO(flysand): signalfd + +// TODO(flysand): timerfd_create + +// TODO(flysand): eventfd + +// TODO(flysand): fallocate + +// TODO(flysand): timerfd_settime + +// TODO(flysand): timerfd_gettime + +// TODO(flysand): accept4 + +// TODO(flysand): signalfd4 + +// TODO(flysand): eventfd2 + +// TODO(flysand): epoll_create1 + +/// Adjust an existing file descriptor to point to the same file as `old` +/// In addition to dup2 allows to pass O_CLOEXEC flag +/// Available since Linux 2.6.27 +dup3 :: proc "contextless" (old: Fd, new: Fd, flags: Open_Flags) -> (Fd, Errno) { + ret := syscall(SYS_dup3, old, new, transmute(i32) flags) + return errno_unwrap(ret, Fd) +} + +// TODO(flysand): inotify_init1 + +// TODO(flysand): preadv + +// TODO(flysand): pwritev + + +/// Send signal information to a thread +/// Available since Linux 2.2 +rt_tgsigqueueinfo :: proc "contextless" (tgid: Pid, pid: Pid, sig: Signal, si: ^Sig_Info) -> (Errno) { + ret := syscall(SYS_rt_tgsigqueueinfo, tgid, pid, sig, si) + return Errno(-ret) +} + +/// Set up performance monitoring +/// Available since Linux 2.6.31 +perf_event_open :: proc "contextless" (attr: ^Perf_Event_Attr, pid: Pid, cpu: int, group_fd: Fd, flags: Perf_Flags = {}) -> (Fd, Errno) { + ret := syscall(SYS_perf_event_open, attr, pid, cpu, group_fd, transmute(uint) flags) + return errno_unwrap(ret, Fd) +} + +// TODO(flysand): recvmmsg + +// TODO(flysand): fanotify_init + +// TODO(flysand): fanotify_mark + +// TODO(flysand): prlimit64 + +// TODO(flysand): name_to_handle_at + +// TODO(flysand): open_by_handle_at + +// TODO(flysand): clock_adjtime + +// TODO(flysand): syncfs + +// TODO(flysand): sendmmsg + +// TODO(flysand): setns + +// TODO(flysand): getcpu + +// TODO(flysand): process_vm_readv + +// TODO(flysand): process_vm_writev + +// TODO(flysand): kcmp + +// TODO(flysand): finit_module + +// TODO(flysand): sched_setattr + +// TODO(flysand): sched_getattr + +/// Rename the file with names relative to the specified dirfd's with other options +/// Available since Linux 3.15 +renameat2 :: proc "contextless" (oldfd: Fd, old: cstring, newfd: Fd, new: cstring, flags: Rename_Flags) -> (Errno) { + ret := syscall(SYS_renameat2, oldfd, cast(rawptr) old, newfd, cast(rawptr) new, transmute(u32) flags) + return Errno(-ret) +} + +// TODO(flysand): seccomp + +getrandom :: proc "contextless" (buf: []u8, flags: Get_Random_Flags) -> (int, Errno) { + ret := syscall(SYS_getrandom, raw_data(buf), len(buf), transmute(i32) flags) + return errno_unwrap(ret, int) +} + +// TODO(flysand): memfd_create + +// TODO(flysand): kexec_file_load + +// TODO(flysand): bpf + +// TODO(flysand): execveat + +// TODO(flysand): userfaultfd + +// TODO(flysand): membarrier + +// TODO(flysand): mlock2 + +// TODO(flysand): copy_file_range + +// TODO(flysand): preadv2 + +// TODO(flysand): pwritev2 + +// TODO(flysand): pkey_mprotect + +// TODO(flysand): pkey_alloc + +// TODO(flysand): pkey_free + +/// Query extended information about the file +/// +/// The file can be specified as: +/// absolute pathname: `dir` parameter is ignored +/// relatvie pathname: `dir` parameter specifies the base directory's fd +/// file descriptor: `AT_EMPTY_PATH` is passed in flags, pathname is empty, `dir` specifies the file descriptor +/// +/// Available since Linux 4.11 +statx :: proc "contextless" (dir: Fd, pathname: cstring, flags: FD_Flags, mask: Statx_Mask, statx: ^Statx) -> (Errno) { + ret := syscall(SYS_statx, dir, transmute(uintptr) pathname, transmute(i32) flags, transmute(u32) mask, statx) + return Errno(-ret) +} + +// TODO(flysand): io_pgetevents + +// TODO(flysand): rseq + +// TODO(flysand): pidfd_send_signal + +// TODO(flysand): io_uring_setup + +// TODO(flysand): io_uring_enter + +// TODO(flysand): io_uring_register + +// TODO(flysand): open_tree + +// TODO(flysand): move_mount + +// TODO(flysand): fsopen + +// TODO(flysand): fsconfig + +// TODO(flysand): fsmount + +// TODO(flysand): fspick + +/// Creates a new PID file descriptor +/// The process identified by `pid` must be a pid group leader +/// The returned `pidfd` has `CLOEXEC` semantics +/// Available since Linux 5.3 +pidfd_open :: proc "contextless" (pid: Pid, flags: Pid_FD_Flags) -> (Pid_FD, Errno) { + ret := syscall(SYS_pidfd_open, pid, transmute(i32) flags) + return errno_unwrap(ret, Pid_FD) +} + +// TODO(flysand): clone3 (probably not this PR) + +/// Close the range of files as an atomic operation +/// The range of file descriptors is inclusive, and may contain invalid file descriptors +/// Available since Linux 5.9 +close_range :: proc "contextless" (lo: Fd, hi: Fd, flags: Close_Range_Flags) -> (Errno) { + ret := syscall(SYS_close_range, lo, hi, transmute(u32) flags) + return Errno(-ret) +} + +// TODO(flysand): openat2 + +/// Get a file descriptor from another process +/// `fd` refers to a file descriptor number to get +/// `flags` must be zero +/// Available since Linux 5.3 +pidfd_getfd :: proc "contextless" (pidfd: Pid_FD, fd: Fd, flags: i32 = 0) -> (Fd, Errno) { + ret := syscall(SYS_pidfd_getfd, pidfd, fd, flags) + return errno_unwrap(ret, Fd) +} + +/// Checks the user permissions for a file at specified dirfd (with flags) +/// Available since Linux 5.8 +faccessat2 :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK, flags: FD_Flags = FD_Flags{}) -> (bool, Errno) { + ret := syscall(SYS_faccessat2, dirfd, cast(rawptr) name, transmute(u32) mode, transmute(i32) flags) + return errno_unwrap(ret, bool) +} + +// TODO(flysand): process_madvise + +// TODO(flysand): epoll_pwait2 + +// TODO(flysand): mount_setattr + +// TODO(flysand): quotactl_fd + +// TODO(flysand): landlock_create_ruleset + +// TODO(flysand): landlock_add_rule + +// TODO(flysand): landlock_restrict_self + +// TODO(flysand): memfd_secret + +// TODO(flysand): process_mrelease + +// TODO(flysand): futex_waitv + +// TODO(flysand): set_mempolicy_home_node + +// TODO(flysand): cachestat + +// TODO(flysand): fchmodat2 + +// TODO(flysand): map_shadow_stack diff --git a/core/sys/linux/syscall_amd64.odin b/core/sys/linux/syscall_amd64.odin new file mode 100644 index 000000000..ee4e16280 --- /dev/null +++ b/core/sys/linux/syscall_amd64.odin @@ -0,0 +1,373 @@ +//+build amd64 +package linux + +// AMD64 uses the new way to define syscalls, i.e. one that +// is different from the other architectures. Instead of using +// a .tbl file, they define constants to tell which syscalls they +// want and then include a generic unistd.h file. + +SYS_read :: uintptr(0) +SYS_write :: uintptr(1) +SYS_open :: uintptr(2) +SYS_close :: uintptr(3) +SYS_stat :: uintptr(4) +SYS_fstat :: uintptr(5) +SYS_lstat :: uintptr(6) +SYS_poll :: uintptr(7) +SYS_lseek :: uintptr(8) +SYS_mmap :: uintptr(9) +SYS_mprotect :: uintptr(10) +SYS_munmap :: uintptr(11) +SYS_brk :: uintptr(12) +SYS_rt_sigaction :: uintptr(13) +SYS_rt_sigprocmask :: uintptr(14) +SYS_rt_sigreturn :: uintptr(15) +SYS_ioctl :: uintptr(16) +SYS_pread64 :: uintptr(17) +SYS_pwrite64 :: uintptr(18) +SYS_readv :: uintptr(19) +SYS_writev :: uintptr(20) +SYS_access :: uintptr(21) +SYS_pipe :: uintptr(22) +SYS_select :: uintptr(23) +SYS_sched_yield :: uintptr(24) +SYS_mremap :: uintptr(25) +SYS_msync :: uintptr(26) +SYS_mincore :: uintptr(27) +SYS_madvise :: uintptr(28) +SYS_shmget :: uintptr(29) +SYS_shmat :: uintptr(30) +SYS_shmctl :: uintptr(31) +SYS_dup :: uintptr(32) +SYS_dup2 :: uintptr(33) +SYS_pause :: uintptr(34) +SYS_nanosleep :: uintptr(35) +SYS_getitimer :: uintptr(36) +SYS_alarm :: uintptr(37) +SYS_setitimer :: uintptr(38) +SYS_getpid :: uintptr(39) +SYS_sendfile :: uintptr(40) +SYS_socket :: uintptr(41) +SYS_connect :: uintptr(42) +SYS_accept :: uintptr(43) +SYS_sendto :: uintptr(44) +SYS_recvfrom :: uintptr(45) +SYS_sendmsg :: uintptr(46) +SYS_recvmsg :: uintptr(47) +SYS_shutdown :: uintptr(48) +SYS_bind :: uintptr(49) +SYS_listen :: uintptr(50) +SYS_getsockname :: uintptr(51) +SYS_getpeername :: uintptr(52) +SYS_socketpair :: uintptr(53) +SYS_setsockopt :: uintptr(54) +SYS_getsockopt :: uintptr(55) +SYS_clone :: uintptr(56) +SYS_fork :: uintptr(57) +SYS_vfork :: uintptr(58) +SYS_execve :: uintptr(59) +SYS_exit :: uintptr(60) +SYS_wait4 :: uintptr(61) +SYS_kill :: uintptr(62) +SYS_uname :: uintptr(63) +SYS_semget :: uintptr(64) +SYS_semop :: uintptr(65) +SYS_semctl :: uintptr(66) +SYS_shmdt :: uintptr(67) +SYS_msgget :: uintptr(68) +SYS_msgsnd :: uintptr(69) +SYS_msgrcv :: uintptr(70) +SYS_msgctl :: uintptr(71) +SYS_fcntl :: uintptr(72) +SYS_flock :: uintptr(73) +SYS_fsync :: uintptr(74) +SYS_fdatasync :: uintptr(75) +SYS_truncate :: uintptr(76) +SYS_ftruncate :: uintptr(77) +SYS_getdents :: uintptr(78) +SYS_getcwd :: uintptr(79) +SYS_chdir :: uintptr(80) +SYS_fchdir :: uintptr(81) +SYS_rename :: uintptr(82) +SYS_mkdir :: uintptr(83) +SYS_rmdir :: uintptr(84) +SYS_creat :: uintptr(85) +SYS_link :: uintptr(86) +SYS_unlink :: uintptr(87) +SYS_symlink :: uintptr(88) +SYS_readlink :: uintptr(89) +SYS_chmod :: uintptr(90) +SYS_fchmod :: uintptr(91) +SYS_chown :: uintptr(92) +SYS_fchown :: uintptr(93) +SYS_lchown :: uintptr(94) +SYS_umask :: uintptr(95) +SYS_gettimeofday :: uintptr(96) +SYS_getrlimit :: uintptr(97) +SYS_getrusage :: uintptr(98) +SYS_sysinfo :: uintptr(99) +SYS_times :: uintptr(100) +SYS_ptrace :: uintptr(101) +SYS_getuid :: uintptr(102) +SYS_syslog :: uintptr(103) +SYS_getgid :: uintptr(104) +SYS_setuid :: uintptr(105) +SYS_setgid :: uintptr(106) +SYS_geteuid :: uintptr(107) +SYS_getegid :: uintptr(108) +SYS_setpgid :: uintptr(109) +SYS_getppid :: uintptr(110) +SYS_getpgrp :: uintptr(111) +SYS_setsid :: uintptr(112) +SYS_setreuid :: uintptr(113) +SYS_setregid :: uintptr(114) +SYS_getgroups :: uintptr(115) +SYS_setgroups :: uintptr(116) +SYS_setresuid :: uintptr(117) +SYS_getresuid :: uintptr(118) +SYS_setresgid :: uintptr(119) +SYS_getresgid :: uintptr(120) +SYS_getpgid :: uintptr(121) +SYS_setfsuid :: uintptr(122) +SYS_setfsgid :: uintptr(123) +SYS_getsid :: uintptr(124) +SYS_capget :: uintptr(125) +SYS_capset :: uintptr(126) +SYS_rt_sigpending :: uintptr(127) +SYS_rt_sigtimedwait :: uintptr(128) +SYS_rt_sigqueueinfo :: uintptr(129) +SYS_rt_sigsuspend :: uintptr(130) +SYS_sigaltstack :: uintptr(131) +SYS_utime :: uintptr(132) +SYS_mknod :: uintptr(133) +SYS_uselib :: uintptr(134) +SYS_personality :: uintptr(135) +SYS_ustat :: uintptr(136) +SYS_statfs :: uintptr(137) +SYS_fstatfs :: uintptr(138) +SYS_sysfs :: uintptr(139) +SYS_getpriority :: uintptr(140) +SYS_setpriority :: uintptr(141) +SYS_sched_setparam :: uintptr(142) +SYS_sched_getparam :: uintptr(143) +SYS_sched_setscheduler :: uintptr(144) +SYS_sched_getscheduler :: uintptr(145) +SYS_sched_get_priority_max :: uintptr(146) +SYS_sched_get_priority_min :: uintptr(147) +SYS_sched_rr_get_interval :: uintptr(148) +SYS_mlock :: uintptr(149) +SYS_munlock :: uintptr(150) +SYS_mlockall :: uintptr(151) +SYS_munlockall :: uintptr(152) +SYS_vhangup :: uintptr(153) +SYS_modify_ldt :: uintptr(154) +SYS_pivot_root :: uintptr(155) +SYS__sysctl :: uintptr(156) +SYS_prctl :: uintptr(157) +SYS_arch_prctl :: uintptr(158) +SYS_adjtimex :: uintptr(159) +SYS_setrlimit :: uintptr(160) +SYS_chroot :: uintptr(161) +SYS_sync :: uintptr(162) +SYS_acct :: uintptr(163) +SYS_settimeofday :: uintptr(164) +SYS_mount :: uintptr(165) +SYS_umount2 :: uintptr(166) +SYS_swapon :: uintptr(167) +SYS_swapoff :: uintptr(168) +SYS_reboot :: uintptr(169) +SYS_sethostname :: uintptr(170) +SYS_setdomainname :: uintptr(171) +SYS_iopl :: uintptr(172) +SYS_ioperm :: uintptr(173) +SYS_create_module :: uintptr(174) +SYS_init_module :: uintptr(175) +SYS_delete_module :: uintptr(176) +SYS_get_kernel_syms :: uintptr(177) +SYS_query_module :: uintptr(178) +SYS_quotactl :: uintptr(179) +SYS_nfsservctl :: uintptr(180) +SYS_getpmsg :: uintptr(181) +SYS_putpmsg :: uintptr(182) +SYS_afs_syscall :: uintptr(183) +SYS_tuxcall :: uintptr(184) +SYS_security :: uintptr(185) +SYS_gettid :: uintptr(186) +SYS_readahead :: uintptr(187) +SYS_setxattr :: uintptr(188) +SYS_lsetxattr :: uintptr(189) +SYS_fsetxattr :: uintptr(190) +SYS_getxattr :: uintptr(191) +SYS_lgetxattr :: uintptr(192) +SYS_fgetxattr :: uintptr(193) +SYS_listxattr :: uintptr(194) +SYS_llistxattr :: uintptr(195) +SYS_flistxattr :: uintptr(196) +SYS_removexattr :: uintptr(197) +SYS_lremovexattr :: uintptr(198) +SYS_fremovexattr :: uintptr(199) +SYS_tkill :: uintptr(200) +SYS_time :: uintptr(201) +SYS_futex :: uintptr(202) +SYS_sched_setaffinity :: uintptr(203) +SYS_sched_getaffinity :: uintptr(204) +SYS_set_thread_area :: uintptr(205) +SYS_io_setup :: uintptr(206) +SYS_io_destroy :: uintptr(207) +SYS_io_getevents :: uintptr(208) +SYS_io_submit :: uintptr(209) +SYS_io_cancel :: uintptr(210) +SYS_get_thread_area :: uintptr(211) +SYS_lookup_dcookie :: uintptr(212) +SYS_epoll_create :: uintptr(213) +SYS_epoll_ctl_old :: uintptr(214) +SYS_epoll_wait_old :: uintptr(215) +SYS_remap_file_pages :: uintptr(216) +SYS_getdents64 :: uintptr(217) +SYS_set_tid_address :: uintptr(218) +SYS_restart_syscall :: uintptr(219) +SYS_semtimedop :: uintptr(220) +SYS_fadvise64 :: uintptr(221) +SYS_timer_create :: uintptr(222) +SYS_timer_settime :: uintptr(223) +SYS_timer_gettime :: uintptr(224) +SYS_timer_getoverrun :: uintptr(225) +SYS_timer_delete :: uintptr(226) +SYS_clock_settime :: uintptr(227) +SYS_clock_gettime :: uintptr(228) +SYS_clock_getres :: uintptr(229) +SYS_clock_nanosleep :: uintptr(230) +SYS_exit_group :: uintptr(231) +SYS_epoll_wait :: uintptr(232) +SYS_epoll_ctl :: uintptr(233) +SYS_tgkill :: uintptr(234) +SYS_utimes :: uintptr(235) +SYS_vserver :: uintptr(236) +SYS_mbind :: uintptr(237) +SYS_set_mempolicy :: uintptr(238) +SYS_get_mempolicy :: uintptr(239) +SYS_mq_open :: uintptr(240) +SYS_mq_unlink :: uintptr(241) +SYS_mq_timedsend :: uintptr(242) +SYS_mq_timedreceive :: uintptr(243) +SYS_mq_notify :: uintptr(244) +SYS_mq_getsetattr :: uintptr(245) +SYS_kexec_load :: uintptr(246) +SYS_waitid :: uintptr(247) +SYS_add_key :: uintptr(248) +SYS_request_key :: uintptr(249) +SYS_keyctl :: uintptr(250) +SYS_ioprio_set :: uintptr(251) +SYS_ioprio_get :: uintptr(252) +SYS_inotify_init :: uintptr(253) +SYS_inotify_add_watch :: uintptr(254) +SYS_inotify_rm_watch :: uintptr(255) +SYS_migrate_pages :: uintptr(256) +SYS_openat :: uintptr(257) +SYS_mkdirat :: uintptr(258) +SYS_mknodat :: uintptr(259) +SYS_fchownat :: uintptr(260) +SYS_futimesat :: uintptr(261) +SYS_newfstatat :: uintptr(262) +SYS_unlinkat :: uintptr(263) +SYS_renameat :: uintptr(264) +SYS_linkat :: uintptr(265) +SYS_symlinkat :: uintptr(266) +SYS_readlinkat :: uintptr(267) +SYS_fchmodat :: uintptr(268) +SYS_faccessat :: uintptr(269) +SYS_pselect6 :: uintptr(270) +SYS_ppoll :: uintptr(271) +SYS_unshare :: uintptr(272) +SYS_set_robust_list :: uintptr(273) +SYS_get_robust_list :: uintptr(274) +SYS_splice :: uintptr(275) +SYS_tee :: uintptr(276) +SYS_sync_file_range :: uintptr(277) +SYS_vmsplice :: uintptr(278) +SYS_move_pages :: uintptr(279) +SYS_utimensat :: uintptr(280) +SYS_epoll_pwait :: uintptr(281) +SYS_signalfd :: uintptr(282) +SYS_timerfd_create :: uintptr(283) +SYS_eventfd :: uintptr(284) +SYS_fallocate :: uintptr(285) +SYS_timerfd_settime :: uintptr(286) +SYS_timerfd_gettime :: uintptr(287) +SYS_accept4 :: uintptr(288) +SYS_signalfd4 :: uintptr(289) +SYS_eventfd2 :: uintptr(290) +SYS_epoll_create1 :: uintptr(291) +SYS_dup3 :: uintptr(292) +SYS_pipe2 :: uintptr(293) +SYS_inotify_init1 :: uintptr(294) +SYS_preadv :: uintptr(295) +SYS_pwritev :: uintptr(296) +SYS_rt_tgsigqueueinfo :: uintptr(297) +SYS_perf_event_open :: uintptr(298) +SYS_recvmmsg :: uintptr(299) +SYS_fanotify_init :: uintptr(300) +SYS_fanotify_mark :: uintptr(301) +SYS_prlimit64 :: uintptr(302) +SYS_name_to_handle_at :: uintptr(303) +SYS_open_by_handle_at :: uintptr(304) +SYS_clock_adjtime :: uintptr(305) +SYS_syncfs :: uintptr(306) +SYS_sendmmsg :: uintptr(307) +SYS_setns :: uintptr(308) +SYS_getcpu :: uintptr(309) +SYS_process_vm_readv :: uintptr(310) +SYS_process_vm_writev :: uintptr(311) +SYS_kcmp :: uintptr(312) +SYS_finit_module :: uintptr(313) +SYS_sched_setattr :: uintptr(314) +SYS_sched_getattr :: uintptr(315) +SYS_renameat2 :: uintptr(316) +SYS_seccomp :: uintptr(317) +SYS_getrandom :: uintptr(318) +SYS_memfd_create :: uintptr(319) +SYS_kexec_file_load :: uintptr(320) +SYS_bpf :: uintptr(321) +SYS_execveat :: uintptr(322) +SYS_userfaultfd :: uintptr(323) +SYS_membarrier :: uintptr(324) +SYS_mlock2 :: uintptr(325) +SYS_copy_file_range :: uintptr(326) +SYS_preadv2 :: uintptr(327) +SYS_pwritev2 :: uintptr(328) +SYS_pkey_mprotect :: uintptr(329) +SYS_pkey_alloc :: uintptr(330) +SYS_pkey_free :: uintptr(331) +SYS_statx :: uintptr(332) +SYS_io_pgetevents :: uintptr(333) +SYS_rseq :: uintptr(334) +SYS_pidfd_send_signal :: uintptr(424) +SYS_io_uring_setup :: uintptr(425) +SYS_io_uring_enter :: uintptr(426) +SYS_io_uring_register :: uintptr(427) +SYS_open_tree :: uintptr(428) +SYS_move_mount :: uintptr(429) +SYS_fsopen :: uintptr(430) +SYS_fsconfig :: uintptr(431) +SYS_fsmount :: uintptr(432) +SYS_fspick :: uintptr(433) +SYS_pidfd_open :: uintptr(434) +SYS_clone3 :: uintptr(435) +SYS_close_range :: uintptr(436) +SYS_openat2 :: uintptr(437) +SYS_pidfd_getfd :: uintptr(438) +SYS_faccessat2 :: uintptr(439) +SYS_process_madvise :: uintptr(440) +SYS_epoll_pwait2 :: uintptr(441) +SYS_mount_setattr :: uintptr(442) +SYS_quotactl_fd :: uintptr(443) +SYS_landlock_create_ruleset :: uintptr(444) +SYS_landlock_add_rule :: uintptr(445) +SYS_landlock_restrict_self :: uintptr(446) +SYS_memfd_secret :: uintptr(447) +SYS_process_mrelease :: uintptr(448) +SYS_futex_waitv :: uintptr(449) +SYS_set_mempolicy_home_node :: uintptr(450) +SYS_cachestat :: uintptr(451) +SYS_fchmodat2 :: uintptr(452) +SYS_map_shadow_stack :: uintptr(453) diff --git a/core/sys/linux/syscall_arm32.odin b/core/sys/linux/syscall_arm32.odin new file mode 100644 index 000000000..74640a1a3 --- /dev/null +++ b/core/sys/linux/syscall_arm32.odin @@ -0,0 +1,470 @@ +//+build arm32 +package linux + +// This file was taken and transformed from +// /arch/arm/tools/syscall.tbl +// in linux headers. OABI and EABI syscalls +// are included. + +// TODO(bumbread, 2023-10-13): I'm not sure whether I have used +// the right syscall table. ARM64 stuff seems to be also compatible +// with ARM32, I'm not sure whether ARM32 also uses the new way of +// defining the syscall table, and this one is just for compatibility..? + +// This syscall is not meant to be used by userspace +SYS_restart_syscall :: uintptr(0) + +SYS_exit :: uintptr(1) +SYS_fork :: uintptr(2) +SYS_read :: uintptr(3) +SYS_write :: uintptr(4) +SYS_open :: uintptr(5) +SYS_close :: uintptr(6) +// 7 was sys_waitpid +SYS_creat :: uintptr(8) +SYS_link :: uintptr(9) +SYS_unlink :: uintptr(10) +SYS_execve :: uintptr(11) +SYS_chdir :: uintptr(12) +SYS_time :: uintptr(13) +SYS_mknod :: uintptr(14) +SYS_chmod :: uintptr(15) +SYS_lchown :: uintptr(16) +// 17 was sys_break +// 18 was sys_stat +SYS_lseek :: uintptr(19) +SYS_getpid :: uintptr(20) +SYS_mount :: uintptr(21) +SYS_umount :: uintptr(22) +SYS_setuid :: uintptr(23) +SYS_getuid :: uintptr(24) +SYS_stime :: uintptr(25) +SYS_ptrace :: uintptr(26) +SYS_alarm :: uintptr(27) +// 28 was sys_fstat +SYS_pause :: uintptr(29) +SYS_utime :: uintptr(30) +// 31 was sys_stty +// 32 was sys_gtty +SYS_access :: uintptr(33) +SYS_nice :: uintptr(34) +// 35 was sys_ftime +SYS_sync :: uintptr(36) +SYS_kill :: uintptr(37) +SYS_rename :: uintptr(38) +SYS_mkdir :: uintptr(39) +SYS_rmdir :: uintptr(40) +SYS_dup :: uintptr(41) +SYS_pipe :: uintptr(42) +SYS_times :: uintptr(43) +// 44 was sys_prof +SYS_brk :: uintptr(45) +SYS_setgid :: uintptr(46) +SYS_getgid :: uintptr(47) +// 48 was sys_signal +SYS_geteuid :: uintptr(49) +SYS_getegid :: uintptr(50) +SYS_acct :: uintptr(51) +SYS_umount2 :: uintptr(52) +// 53 was sys_lock +SYS_ioctl :: uintptr(54) +SYS_fcntl :: uintptr(55) +// 56 was sys_mpx +SYS_setpgid :: uintptr(57) +// 58 was sys_ulimit +// 59 was sys_olduname +SYS_umask :: uintptr(60) +SYS_chroot :: uintptr(61) +SYS_ustat :: uintptr(62) +SYS_dup2 :: uintptr(63) +SYS_getppid :: uintptr(64) +SYS_getpgrp :: uintptr(65) +SYS_setsid :: uintptr(66) +SYS_sigaction :: uintptr(67) +// 68 was sys_sgetmask +// 69 was sys_ssetmask +SYS_setreuid :: uintptr(70) +SYS_setregid :: uintptr(71) +SYS_sigsuspend :: uintptr(72) +SYS_sigpending :: uintptr(73) +SYS_sethostname :: uintptr(74) +SYS_setrlimit :: uintptr(75) +// Back compat 2GB limited rlimit +SYS_getrlimit :: uintptr(76) +SYS_getrusage :: uintptr(77) +SYS_gettimeofday :: uintptr(78) +SYS_settimeofday :: uintptr(79) +SYS_getgroups :: uintptr(80) +SYS_setgroups :: uintptr(81) +SYS_select :: uintptr(82) +SYS_symlink :: uintptr(83) +// 84 was sys_lstat +SYS_readlink :: uintptr(85) +SYS_uselib :: uintptr(86) +SYS_swapon :: uintptr(87) +SYS_reboot :: uintptr(88) +SYS_readdir :: uintptr(89) +SYS_mmap :: uintptr(90) +SYS_munmap :: uintptr(91) +SYS_truncate :: uintptr(92) +SYS_ftruncate :: uintptr(93) +SYS_fchmod :: uintptr(94) +SYS_fchown :: uintptr(95) +SYS_getpriority :: uintptr(96) +SYS_setpriority :: uintptr(97) +// 98 was sys_profil +SYS_statfs :: uintptr(99) +SYS_fstatfs :: uintptr(100) +// 101 was sys_ioperm +SYS_socketcall :: uintptr(102) +SYS_syslog :: uintptr(103) +SYS_setitimer :: uintptr(104) +SYS_getitimer :: uintptr(105) +SYS_stat :: uintptr(106) +SYS_lstat :: uintptr(107) +SYS_fstat :: uintptr(108) +// 109 was sys_uname +// 110 was sys_iopl +SYS_vhangup :: uintptr(111) +// 112 was sys_idle +// syscall to call a syscall! +SYS_syscall :: uintptr(113) +SYS_wait4 :: uintptr(114) +SYS_swapoff :: uintptr(115) +SYS_sysinfo :: uintptr(116) +SYS_ipc :: uintptr(117) +SYS_fsync :: uintptr(118) +SYS_sigreturn :: uintptr(119) +SYS_clone :: uintptr(120) +SYS_setdomainname :: uintptr(121) +SYS_uname :: uintptr(122) +// 123 was sys_modify_ldt +SYS_adjtimex :: uintptr(124) +SYS_mprotect :: uintptr(125) +SYS_sigprocmask :: uintptr(126) +// 127 was sys_create_module +SYS_init_module :: uintptr(128) +SYS_delete_module :: uintptr(129) +// 130 was sys_get_kernel_syms +SYS_quotactl :: uintptr(131) +SYS_getpgid :: uintptr(132) +SYS_fchdir :: uintptr(133) +SYS_bdflush :: uintptr(134) +SYS_sysfs :: uintptr(135) +SYS_personality :: uintptr(136) +// 137 was sys_afs_syscall +SYS_setfsuid :: uintptr(138) +SYS_setfsgid :: uintptr(139) +SYS__llseek :: uintptr(140) +SYS_getdents :: uintptr(141) +SYS__newselect :: uintptr(142) +SYS_flock :: uintptr(143) +SYS_msync :: uintptr(144) +SYS_readv :: uintptr(145) +SYS_writev :: uintptr(146) +SYS_getsid :: uintptr(147) +SYS_fdatasync :: uintptr(148) +SYS__sysctl :: uintptr(149) +SYS_mlock :: uintptr(150) +SYS_munlock :: uintptr(151) +SYS_mlockall :: uintptr(152) +SYS_munlockall :: uintptr(153) +SYS_sched_setparam :: uintptr(154) +SYS_sched_getparam :: uintptr(155) +SYS_sched_setscheduler :: uintptr(156) +SYS_sched_getscheduler :: uintptr(157) +SYS_sched_yield :: uintptr(158) +SYS_sched_get_priority_max :: uintptr(159) +SYS_sched_get_priority_min :: uintptr(160) +SYS_sched_rr_get_interval :: uintptr(161) +SYS_nanosleep :: uintptr(162) +SYS_mremap :: uintptr(163) +SYS_setresuid :: uintptr(164) +SYS_getresuid :: uintptr(165) +// 166 was sys_vm86 +// 167 was sys_query_module +SYS_poll :: uintptr(168) +SYS_nfsservctl :: uintptr(169) +SYS_setresgid :: uintptr(170) +SYS_getresgid :: uintptr(171) +SYS_prctl :: uintptr(172) +SYS_rt_sigreturn :: uintptr(173) +SYS_rt_sigaction :: uintptr(174) +SYS_rt_sigprocmask :: uintptr(175) +SYS_rt_sigpending :: uintptr(176) +SYS_rt_sigtimedwait :: uintptr(177) +SYS_rt_sigqueueinfo :: uintptr(178) +SYS_rt_sigsuspend :: uintptr(179) +SYS_pread64 :: uintptr(180) +SYS_pwrite64 :: uintptr(181) +SYS_chown :: uintptr(182) +SYS_getcwd :: uintptr(183) +SYS_capget :: uintptr(184) +SYS_capset :: uintptr(185) +SYS_sigaltstack :: uintptr(186) +SYS_sendfile :: uintptr(187) +// 188 reserved +// 189 reserved +SYS_vfork :: uintptr(190) +// SuS compliant getrlimit +SYS_ugetrlimit :: uintptr(191) +SYS_mmap2 :: uintptr(192) +SYS_truncate64 :: uintptr(193) +SYS_ftruncate64 :: uintptr(194) +SYS_stat64 :: uintptr(195) +SYS_lstat64 :: uintptr(196) +SYS_fstat64 :: uintptr(197) +SYS_lchown32 :: uintptr(198) +SYS_getuid32 :: uintptr(199) +SYS_getgid32 :: uintptr(200) +SYS_geteuid32 :: uintptr(201) +SYS_getegid32 :: uintptr(202) +SYS_setreuid32 :: uintptr(203) +SYS_setregid32 :: uintptr(204) +SYS_getgroups32 :: uintptr(205) +SYS_setgroups32 :: uintptr(206) +SYS_fchown32 :: uintptr(207) +SYS_setresuid32 :: uintptr(208) +SYS_getresuid32 :: uintptr(209) +SYS_setresgid32 :: uintptr(210) +SYS_getresgid32 :: uintptr(211) +SYS_chown32 :: uintptr(212) +SYS_setuid32 :: uintptr(213) +SYS_setgid32 :: uintptr(214) +SYS_setfsuid32 :: uintptr(215) +SYS_setfsgid32 :: uintptr(216) +SYS_getdents64 :: uintptr(217) +SYS_pivot_root :: uintptr(218) +SYS_mincore :: uintptr(219) +SYS_madvise :: uintptr(220) +SYS_fcntl64 :: uintptr(221) +// 222 for tux +// 223 is unused +SYS_gettid :: uintptr(224) +SYS_readahead :: uintptr(225) +SYS_setxattr :: uintptr(226) +SYS_lsetxattr :: uintptr(227) +SYS_fsetxattr :: uintptr(228) +SYS_getxattr :: uintptr(229) +SYS_lgetxattr :: uintptr(230) +SYS_fgetxattr :: uintptr(231) +SYS_listxattr :: uintptr(232) +SYS_llistxattr :: uintptr(233) +SYS_flistxattr :: uintptr(234) +SYS_removexattr :: uintptr(235) +SYS_lremovexattr :: uintptr(236) +SYS_fremovexattr :: uintptr(237) +SYS_tkill :: uintptr(238) +SYS_sendfile64 :: uintptr(239) +SYS_futex :: uintptr(240) +SYS_sched_setaffinity :: uintptr(241) +SYS_sched_getaffinity :: uintptr(242) +SYS_io_setup :: uintptr(243) +SYS_io_destroy :: uintptr(244) +SYS_io_getevents :: uintptr(245) +SYS_io_submit :: uintptr(246) +SYS_io_cancel :: uintptr(247) +SYS_exit_group :: uintptr(248) +SYS_lookup_dcookie :: uintptr(249) +SYS_epoll_create :: uintptr(250) +SYS_epoll_ctl :: uintptr(251) +SYS_epoll_wait :: uintptr(252) +SYS_remap_file_pages :: uintptr(253) +// 254 for set_thread_area +// 255 for get_thread_area +SYS_set_tid_address :: uintptr(256) +SYS_timer_create :: uintptr(257) +SYS_timer_settime :: uintptr(258) +SYS_timer_gettime :: uintptr(259) +SYS_timer_getoverrun :: uintptr(260) +SYS_timer_delete :: uintptr(261) +SYS_clock_settime :: uintptr(262) +SYS_clock_gettime :: uintptr(263) +SYS_clock_getres :: uintptr(264) +SYS_clock_nanosleep :: uintptr(265) +SYS_statfs64 :: uintptr(266) +SYS_fstatfs64 :: uintptr(267) +SYS_tgkill :: uintptr(268) +SYS_utimes :: uintptr(269) +SYS_arm_fadvise64_64 :: uintptr(270) +SYS_pciconfig_iobase :: uintptr(271) +SYS_pciconfig_read :: uintptr(272) +SYS_pciconfig_write :: uintptr(273) +SYS_mq_open :: uintptr(274) +SYS_mq_unlink :: uintptr(275) +SYS_mq_timedsend :: uintptr(276) +SYS_mq_timedreceive :: uintptr(277) +SYS_mq_notify :: uintptr(278) +SYS_mq_getsetattr :: uintptr(279) +SYS_waitid :: uintptr(280) +SYS_socket :: uintptr(281) +SYS_bind :: uintptr(282) +SYS_connect :: uintptr(283) +SYS_listen :: uintptr(284) +SYS_accept :: uintptr(285) +SYS_getsockname :: uintptr(286) +SYS_getpeername :: uintptr(287) +SYS_socketpair :: uintptr(288) +SYS_send :: uintptr(289) +SYS_sendto :: uintptr(290) +SYS_recv :: uintptr(291) +SYS_recvfrom :: uintptr(292) +SYS_shutdown :: uintptr(293) +SYS_setsockopt :: uintptr(294) +SYS_getsockopt :: uintptr(295) +SYS_sendmsg :: uintptr(296) +SYS_recvmsg :: uintptr(297) +SYS_semop :: uintptr(298) +SYS_semget :: uintptr(299) +SYS_semctl :: uintptr(300) +SYS_msgsnd :: uintptr(301) +SYS_msgrcv :: uintptr(302) +SYS_msgget :: uintptr(303) +SYS_msgctl :: uintptr(304) +SYS_shmat :: uintptr(305) +SYS_shmdt :: uintptr(306) +SYS_shmget :: uintptr(307) +SYS_shmctl :: uintptr(308) +SYS_add_key :: uintptr(309) +SYS_request_key :: uintptr(310) +SYS_keyctl :: uintptr(311) +SYS_semtimedop :: uintptr(312) +SYS_vserver :: uintptr(313) +SYS_ioprio_set :: uintptr(314) +SYS_ioprio_get :: uintptr(315) +SYS_inotify_init :: uintptr(316) +SYS_inotify_add_watch :: uintptr(317) +SYS_inotify_rm_watch :: uintptr(318) +SYS_mbind :: uintptr(319) +SYS_get_mempolicy :: uintptr(320) +SYS_set_mempolicy :: uintptr(321) +SYS_openat :: uintptr(322) +SYS_mkdirat :: uintptr(323) +SYS_mknodat :: uintptr(324) +SYS_fchownat :: uintptr(325) +SYS_futimesat :: uintptr(326) +SYS_fstatat64 :: uintptr(327) +SYS_unlinkat :: uintptr(328) +SYS_renameat :: uintptr(329) +SYS_linkat :: uintptr(330) +SYS_symlinkat :: uintptr(331) +SYS_readlinkat :: uintptr(332) +SYS_fchmodat :: uintptr(333) +SYS_faccessat :: uintptr(334) +SYS_pselect6 :: uintptr(335) +SYS_ppoll :: uintptr(336) +SYS_unshare :: uintptr(337) +SYS_set_robust_list :: uintptr(338) +SYS_get_robust_list :: uintptr(339) +SYS_splice :: uintptr(340) +SYS_arm_sync_file_range :: uintptr(341) +SYS_tee :: uintptr(342) +SYS_vmsplice :: uintptr(343) +SYS_move_pages :: uintptr(344) +SYS_getcpu :: uintptr(345) +SYS_epoll_pwait :: uintptr(346) +SYS_kexec_load :: uintptr(347) +SYS_utimensat :: uintptr(348) +SYS_signalfd :: uintptr(349) +SYS_timerfd_create :: uintptr(350) +SYS_eventfd :: uintptr(351) +SYS_fallocate :: uintptr(352) +SYS_timerfd_settime :: uintptr(353) +SYS_timerfd_gettime :: uintptr(354) +SYS_signalfd4 :: uintptr(355) +SYS_eventfd2 :: uintptr(356) +SYS_epoll_create1 :: uintptr(357) +SYS_dup3 :: uintptr(358) +SYS_pipe2 :: uintptr(359) +SYS_inotify_init1 :: uintptr(360) +SYS_preadv :: uintptr(361) +SYS_pwritev :: uintptr(362) +SYS_rt_tgsigqueueinfo :: uintptr(363) +SYS_perf_event_open :: uintptr(364) +SYS_recvmmsg :: uintptr(365) +SYS_accept4 :: uintptr(366) +SYS_fanotify_init :: uintptr(367) +SYS_fanotify_mark :: uintptr(368) +SYS_prlimit64 :: uintptr(369) +SYS_name_to_handle_at :: uintptr(370) +SYS_open_by_handle_at :: uintptr(371) +SYS_clock_adjtime :: uintptr(372) +SYS_syncfs :: uintptr(373) +SYS_sendmmsg :: uintptr(374) +SYS_setns :: uintptr(375) +SYS_process_vm_readv :: uintptr(376) +SYS_process_vm_writev :: uintptr(377) +SYS_kcmp :: uintptr(378) +SYS_finit_module :: uintptr(379) +SYS_sched_setattr :: uintptr(380) +SYS_sched_getattr :: uintptr(381) +SYS_renameat2 :: uintptr(382) +SYS_seccomp :: uintptr(383) +SYS_getrandom :: uintptr(384) +SYS_memfd_create :: uintptr(385) +SYS_bpf :: uintptr(386) +SYS_execveat :: uintptr(387) +SYS_userfaultfd :: uintptr(388) +SYS_membarrier :: uintptr(389) +SYS_mlock2 :: uintptr(390) +SYS_copy_file_range :: uintptr(391) +SYS_preadv2 :: uintptr(392) +SYS_pwritev2 :: uintptr(393) +SYS_pkey_mprotect :: uintptr(394) +SYS_pkey_alloc :: uintptr(395) +SYS_pkey_free :: uintptr(396) +SYS_statx :: uintptr(397) +SYS_rseq :: uintptr(398) +SYS_io_pgetevents :: uintptr(399) +SYS_migrate_pages :: uintptr(400) +SYS_kexec_file_load :: uintptr(401) +// 402 is unused +SYS_clock_gettime64 :: uintptr(403) +SYS_clock_settime64 :: uintptr(404) +SYS_clock_adjtime64 :: uintptr(405) +SYS_clock_getres_time64 :: uintptr(406) +SYS_clock_nanosleep_time64 :: uintptr(407) +SYS_timer_gettime64 :: uintptr(408) +SYS_timer_settime64 :: uintptr(409) +SYS_timerfd_gettime64 :: uintptr(410) +SYS_timerfd_settime64 :: uintptr(411) +SYS_utimensat_time64 :: uintptr(412) +SYS_pselect6_time64 :: uintptr(413) +SYS_ppoll_time64 :: uintptr(414) +SYS_io_pgetevents_time64 :: uintptr(416) +SYS_recvmmsg_time64 :: uintptr(417) +SYS_mq_timedsend_time64 :: uintptr(418) +SYS_mq_timedreceive_time64 :: uintptr(419) +SYS_semtimedop_time64 :: uintptr(420) +SYS_rt_sigtimedwait_time64 :: uintptr(421) +SYS_futex_time64 :: uintptr(422) +SYS_sched_rr_get_interval_time64:: uintptr(423) +SYS_pidfd_send_signal :: uintptr(424) +SYS_io_uring_setup :: uintptr(425) +SYS_io_uring_enter :: uintptr(426) +SYS_io_uring_register :: uintptr(427) +SYS_open_tree :: uintptr(428) +SYS_move_mount :: uintptr(429) +SYS_fsopen :: uintptr(430) +SYS_fsconfig :: uintptr(431) +SYS_fsmount :: uintptr(432) +SYS_fspick :: uintptr(433) +SYS_pidfd_open :: uintptr(434) +SYS_clone3 :: uintptr(435) +SYS_close_range :: uintptr(436) +SYS_openat2 :: uintptr(437) +SYS_pidfd_getfd :: uintptr(438) +SYS_faccessat2 :: uintptr(439) +SYS_process_madvise :: uintptr(440) +SYS_epoll_pwait2 :: uintptr(441) +SYS_mount_setattr :: uintptr(442) +SYS_quotactl_fd :: uintptr(443) +SYS_landlock_create_ruleset :: uintptr(444) +SYS_landlock_add_rule :: uintptr(445) +SYS_landlock_restrict_self :: uintptr(446) +// 447 reserved for memfd_secret +SYS_process_mrelease :: uintptr(448) +SYS_futex_waitv :: uintptr(449) +SYS_set_mempolicy_home_node :: uintptr(450) +SYS_cachestat :: uintptr(451) +SYS_fchmodat2 :: uintptr(452) diff --git a/core/sys/linux/syscall_arm64.odin b/core/sys/linux/syscall_arm64.odin new file mode 100644 index 000000000..61b5a31b7 --- /dev/null +++ b/core/sys/linux/syscall_arm64.odin @@ -0,0 +1,321 @@ +//+build arm64 +package linux + +// Syscalls for arm64 are defined using the new way, i.e. differently from +// the other platforms. It defines a few constants representing which optional +// syscalls it wants and includes the generic unistd.h file. + +SYS_io_setup :: uintptr(0) +SYS_io_destroy :: uintptr(1) +SYS_io_submit :: uintptr(2) +SYS_io_cancel :: uintptr(3) +// time32 syscall +SYS_io_getevents :: uintptr(4) +SYS_setxattr :: uintptr(5) +SYS_lsetxattr :: uintptr(6) +SYS_fsetxattr :: uintptr(7) +SYS_getxattr :: uintptr(8) +SYS_lgetxattr :: uintptr(9) +SYS_fgetxattr :: uintptr(10) +SYS_listxattr :: uintptr(11) +SYS_llistxattr :: uintptr(12) +SYS_flistxattr :: uintptr(13) +SYS_removexattr :: uintptr(14) +SYS_lremovexattr :: uintptr(15) +SYS_fremovexattr :: uintptr(16) +SYS_getcwd :: uintptr(17) +SYS_lookup_dcookie :: uintptr(18) +SYS_eventfd2 :: uintptr(19) +SYS_epoll_create1 :: uintptr(20) +SYS_epoll_ctl :: uintptr(21) +SYS_epoll_pwait :: uintptr(22) +SYS_dup :: uintptr(23) +SYS_dup3 :: uintptr(24) +SYS_fcntl :: uintptr(25) +SYS_inotify_init1 :: uintptr(26) +SYS_inotify_add_watch :: uintptr(27) +SYS_inotify_rm_watch :: uintptr(28) +SYS_ioctl :: uintptr(29) +SYS_ioprio_set :: uintptr(30) +SYS_ioprio_get :: uintptr(31) +SYS_flock :: uintptr(32) +SYS_mknodat :: uintptr(33) +SYS_mkdirat :: uintptr(34) +SYS_unlinkat :: uintptr(35) +SYS_symlinkat :: uintptr(36) +SYS_linkat :: uintptr(37) +SYS_renameat :: uintptr(38) +SYS_umount2 :: uintptr(39) +SYS_mount :: uintptr(40) +SYS_pivot_root :: uintptr(41) +SYS_nfsservctl :: uintptr(42) +SYS_statfs :: uintptr(43) +SYS_fstatfs :: uintptr(44) +SYS_truncate :: uintptr(45) +SYS_ftruncate :: uintptr(46) +SYS_fallocate :: uintptr(47) +SYS_faccessat :: uintptr(48) +SYS_chdir :: uintptr(49) +SYS_fchdir :: uintptr(50) +SYS_chroot :: uintptr(51) +SYS_fchmod :: uintptr(52) +SYS_fchmodat :: uintptr(53) +SYS_fchownat :: uintptr(54) +SYS_fchown :: uintptr(55) +SYS_openat :: uintptr(56) +SYS_close :: uintptr(57) +SYS_vhangup :: uintptr(58) +SYS_pipe2 :: uintptr(59) +SYS_quotactl :: uintptr(60) +SYS_getdents64 :: uintptr(61) +SYS_lseek :: uintptr(62) +SYS_read :: uintptr(63) +SYS_write :: uintptr(64) +SYS_readv :: uintptr(65) +SYS_writev :: uintptr(66) +SYS_pread64 :: uintptr(67) +SYS_pwrite64 :: uintptr(68) +SYS_preadv :: uintptr(69) +SYS_pwritev :: uintptr(70) +SYS_sendfile :: uintptr(71) +SYS_pselect6 :: uintptr(72) +SYS_ppoll :: uintptr(73) +SYS_signalfd4 :: uintptr(74) +SYS_vmsplice :: uintptr(75) +SYS_splice :: uintptr(76) +SYS_tee :: uintptr(77) +SYS_readlinkat :: uintptr(78) +SYS_fstatat :: uintptr(79) +SYS_fstat :: uintptr(80) +SYS_sync :: uintptr(81) +SYS_fsync :: uintptr(82) +SYS_fdatasync :: uintptr(83) +SYS_sync_file_range :: uintptr(84) +SYS_timerfd_create :: uintptr(85) +SYS_timerfd_settime :: uintptr(86) +SYS_timerfd_gettime :: uintptr(87) +SYS_utimensat :: uintptr(88) +SYS_acct :: uintptr(89) +SYS_capget :: uintptr(90) +SYS_capset :: uintptr(91) +SYS_personality :: uintptr(92) +SYS_exit :: uintptr(93) +SYS_exit_group :: uintptr(94) +SYS_waitid :: uintptr(95) +SYS_set_tid_address :: uintptr(96) +SYS_unshare :: uintptr(97) +SYS_futex :: uintptr(98) +SYS_set_robust_list :: uintptr(99) +SYS_get_robust_list :: uintptr(100) +SYS_nanosleep :: uintptr(101) +SYS_getitimer :: uintptr(102) +SYS_setitimer :: uintptr(103) +SYS_kexec_load :: uintptr(104) +SYS_init_module :: uintptr(105) +SYS_delete_module :: uintptr(106) +SYS_timer_create :: uintptr(107) +SYS_timer_gettime :: uintptr(108) +SYS_timer_getoverrun :: uintptr(109) +SYS_timer_settime :: uintptr(110) +SYS_timer_delete :: uintptr(111) +SYS_clock_settime :: uintptr(112) +SYS_clock_gettime :: uintptr(113) +SYS_clock_getres :: uintptr(114) +SYS_clock_nanosleep :: uintptr(115) +SYS_syslog :: uintptr(116) +SYS_ptrace :: uintptr(117) +SYS_sched_setparam :: uintptr(118) +SYS_sched_setscheduler :: uintptr(119) +SYS_sched_getscheduler :: uintptr(120) +SYS_sched_getparam :: uintptr(121) +SYS_sched_setaffinity :: uintptr(122) +SYS_sched_getaffinity :: uintptr(123) +SYS_sched_yield :: uintptr(124) +SYS_sched_get_priority_max :: uintptr(125) +SYS_sched_get_priority_min :: uintptr(126) +SYS_sched_rr_get_interval :: uintptr(127) +SYS_restart_syscall :: uintptr(128) +SYS_kill :: uintptr(129) +SYS_tkill :: uintptr(130) +SYS_tgkill :: uintptr(131) +SYS_sigaltstack :: uintptr(132) +SYS_rt_sigsuspend :: uintptr(133) +SYS_rt_sigaction :: uintptr(134) +SYS_rt_sigprocmask :: uintptr(135) +SYS_rt_sigpending :: uintptr(136) +SYS_rt_sigtimedwait :: uintptr(137) +SYS_rt_sigqueueinfo :: uintptr(138) +SYS_rt_sigreturn :: uintptr(139) +SYS_setpriority :: uintptr(140) +SYS_getpriority :: uintptr(141) +SYS_reboot :: uintptr(142) +SYS_setregid :: uintptr(143) +SYS_setgid :: uintptr(144) +SYS_setreuid :: uintptr(145) +SYS_setuid :: uintptr(146) +SYS_setresuid :: uintptr(147) +SYS_getresuid :: uintptr(148) +SYS_setresgid :: uintptr(149) +SYS_getresgid :: uintptr(150) +SYS_setfsuid :: uintptr(151) +SYS_setfsgid :: uintptr(152) +SYS_times :: uintptr(153) +SYS_setpgid :: uintptr(154) +SYS_getpgid :: uintptr(155) +SYS_getsid :: uintptr(156) +SYS_setsid :: uintptr(157) +SYS_getgroups :: uintptr(158) +SYS_setgroups :: uintptr(159) +SYS_uname :: uintptr(160) +SYS_sethostname :: uintptr(161) +SYS_setdomainname :: uintptr(162) +SYS_getrlimit :: uintptr(163) +SYS_setrlimit :: uintptr(164) +SYS_getrusage :: uintptr(165) +SYS_umask :: uintptr(166) +SYS_prctl :: uintptr(167) +SYS_getcpu :: uintptr(168) +SYS_gettimeofday :: uintptr(169) +SYS_settimeofday :: uintptr(170) +SYS_adjtimex :: uintptr(171) +SYS_getpid :: uintptr(172) +SYS_getppid :: uintptr(173) +SYS_getuid :: uintptr(174) +SYS_geteuid :: uintptr(175) +SYS_getgid :: uintptr(176) +SYS_getegid :: uintptr(177) +SYS_gettid :: uintptr(178) +SYS_sysinfo :: uintptr(179) +SYS_mq_open :: uintptr(180) +SYS_mq_unlink :: uintptr(181) +SYS_mq_timedsend :: uintptr(182) +SYS_mq_timedreceive :: uintptr(183) +SYS_mq_notify :: uintptr(184) +SYS_mq_getsetattr :: uintptr(185) +SYS_msgget :: uintptr(186) +SYS_msgctl :: uintptr(187) +SYS_msgrcv :: uintptr(188) +SYS_msgsnd :: uintptr(189) +SYS_semget :: uintptr(190) +SYS_semctl :: uintptr(191) +SYS_semtimedop :: uintptr(192) +SYS_semop :: uintptr(193) +SYS_shmget :: uintptr(194) +SYS_shmctl :: uintptr(195) +SYS_shmat :: uintptr(196) +SYS_shmdt :: uintptr(197) +SYS_socket :: uintptr(198) +SYS_socketpair :: uintptr(199) +SYS_bind :: uintptr(200) +SYS_listen :: uintptr(201) +SYS_accept :: uintptr(202) +SYS_connect :: uintptr(203) +SYS_getsockname :: uintptr(204) +SYS_getpeername :: uintptr(205) +SYS_sendto :: uintptr(206) +SYS_recvfrom :: uintptr(207) +SYS_setsockopt :: uintptr(208) +SYS_getsockopt :: uintptr(209) +SYS_shutdown :: uintptr(210) +SYS_sendmsg :: uintptr(211) +SYS_recvmsg :: uintptr(212) +SYS_readahead :: uintptr(213) +SYS_brk :: uintptr(214) +SYS_munmap :: uintptr(215) +SYS_mremap :: uintptr(216) +SYS_add_key :: uintptr(217) +SYS_request_key :: uintptr(218) +SYS_keyctl :: uintptr(219) +SYS_clone :: uintptr(220) +SYS_execve :: uintptr(221) +SYS_mmap :: uintptr(222) +SYS_fadvise64 :: uintptr(223) + +/* CONFIG_MMU only */ +SYS_swapon :: uintptr(224) +SYS_swapoff :: uintptr(225) +SYS_mprotect :: uintptr(226) +SYS_msync :: uintptr(227) +SYS_mlock :: uintptr(228) +SYS_munlock :: uintptr(229) +SYS_mlockall :: uintptr(230) +SYS_munlockall :: uintptr(231) +SYS_mincore :: uintptr(232) +SYS_madvise :: uintptr(233) +SYS_remap_file_pages :: uintptr(234) +SYS_mbind :: uintptr(235) +SYS_get_mempolicy :: uintptr(236) +SYS_set_mempolicy :: uintptr(237) +SYS_migrate_pages :: uintptr(238) +SYS_move_pages :: uintptr(239) + +SYS_rt_tgsigqueueinfo :: uintptr(240) +SYS_perf_event_open :: uintptr(241) +SYS_accept4 :: uintptr(242) +SYS_recvmmsg :: uintptr(243) +SYS_wait4 :: uintptr(260) +SYS_prlimit64 :: uintptr(261) +SYS_fanotify_init :: uintptr(262) +SYS_fanotify_mark :: uintptr(263) +SYS_name_to_handle_at :: uintptr(264) +SYS_open_by_handle_at :: uintptr(265) +SYS_clock_adjtime :: uintptr(266) +SYS_syncfs :: uintptr(267) +SYS_setns :: uintptr(268) +SYS_sendmmsg :: uintptr(269) +SYS_process_vm_readv :: uintptr(270) +SYS_process_vm_writev :: uintptr(271) +SYS_kcmp :: uintptr(272) +SYS_finit_module :: uintptr(273) +SYS_sched_setattr :: uintptr(274) +SYS_sched_getattr :: uintptr(275) +SYS_renameat2 :: uintptr(276) +SYS_seccomp :: uintptr(277) +SYS_getrandom :: uintptr(278) +SYS_memfd_create :: uintptr(279) +SYS_bpf :: uintptr(280) +SYS_execveat :: uintptr(281) +SYS_userfaultfd :: uintptr(282) +SYS_membarrier :: uintptr(283) +SYS_mlock2 :: uintptr(284) +SYS_copy_file_range :: uintptr(285) +SYS_preadv2 :: uintptr(286) +SYS_pwritev2 :: uintptr(287) +SYS_pkey_mprotect :: uintptr(288) +SYS_pkey_alloc :: uintptr(289) +SYS_pkey_free :: uintptr(290) +SYS_statx :: uintptr(291) +SYS_io_pgetevents :: uintptr(292) +SYS_rseq :: uintptr(293) +SYS_kexec_file_load :: uintptr(294) +SYS_pidfd_send_signal :: uintptr(424) +SYS_io_uring_setup :: uintptr(425) +SYS_io_uring_enter :: uintptr(426) +SYS_io_uring_register :: uintptr(427) +SYS_open_tree :: uintptr(428) +SYS_move_mount :: uintptr(429) +SYS_fsopen :: uintptr(430) +SYS_fsconfig :: uintptr(431) +SYS_fsmount :: uintptr(432) +SYS_fspick :: uintptr(433) +SYS_pidfd_open :: uintptr(434) +SYS_clone3 :: uintptr(435) +SYS_close_range :: uintptr(436) +SYS_openat2 :: uintptr(437) +SYS_pidfd_getfd :: uintptr(438) +SYS_faccessat2 :: uintptr(439) +SYS_process_madvise :: uintptr(440) +SYS_epoll_pwait2 :: uintptr(441) +SYS_mount_setattr :: uintptr(442) +SYS_quotactl_fd :: uintptr(443) +SYS_landlock_create_ruleset :: uintptr(444) +SYS_landlock_add_rule :: uintptr(445) +SYS_landlock_restrict_self :: uintptr(446) +SYS_memfd_secret :: uintptr(447) +SYS_process_mrelease :: uintptr(448) +SYS_futex_waitv :: uintptr(449) +SYS_set_mempolicy_home_node :: uintptr(450) +SYS_cachestat :: uintptr(451) +SYS_fchmodat2 :: uintptr(452) + + diff --git a/core/sys/linux/syscall_i386.odin b/core/sys/linux/syscall_i386.odin new file mode 100644 index 000000000..4609fc99c --- /dev/null +++ b/core/sys/linux/syscall_i386.odin @@ -0,0 +1,458 @@ +//+build i386 +package linux + +// The numbers are taken from +// /arch/x86/entry/syscalls/syscall_32.tbl +// in Linux headers. Only x64 and common ABI +// syscalls were taken, for x32 is not +// supported by Odin + +// This syscall is only used by the kernel internally +// userspace has no reason to use it. +SYS_restart_syscall :: uintptr(0) + +SYS_exit :: uintptr(1) +SYS_fork :: uintptr(2) +SYS_read :: uintptr(3) +SYS_write :: uintptr(4) +SYS_open :: uintptr(5) +SYS_close :: uintptr(6) +SYS_waitpid :: uintptr(7) +SYS_creat :: uintptr(8) +SYS_link :: uintptr(9) +SYS_unlink :: uintptr(10) +SYS_execve :: uintptr(11) +SYS_chdir :: uintptr(12) +SYS_time :: uintptr(13) +SYS_mknod :: uintptr(14) +SYS_chmod :: uintptr(15) +SYS_lchown :: uintptr(16) +SYS_break :: uintptr(17) +SYS_oldstat :: uintptr(18) +SYS_lseek :: uintptr(19) +SYS_getpid :: uintptr(20) +SYS_mount :: uintptr(21) +SYS_umount :: uintptr(22) +SYS_setuid :: uintptr(23) +SYS_getuid :: uintptr(24) +SYS_stime :: uintptr(25) +SYS_ptrace :: uintptr(26) +SYS_alarm :: uintptr(27) +SYS_oldfstat :: uintptr(28) +SYS_pause :: uintptr(29) +SYS_utime :: uintptr(30) +SYS_stty :: uintptr(31) +SYS_gtty :: uintptr(32) +SYS_access :: uintptr(33) +SYS_nice :: uintptr(34) +SYS_ftime :: uintptr(35) +SYS_sync :: uintptr(36) +SYS_kill :: uintptr(37) +SYS_rename :: uintptr(38) +SYS_mkdir :: uintptr(39) +SYS_rmdir :: uintptr(40) +SYS_dup :: uintptr(41) +SYS_pipe :: uintptr(42) +SYS_times :: uintptr(43) +SYS_prof :: uintptr(44) +SYS_brk :: uintptr(45) +SYS_setgid :: uintptr(46) +SYS_getgid :: uintptr(47) +SYS_signal :: uintptr(48) +SYS_geteuid :: uintptr(49) +SYS_getegid :: uintptr(50) +SYS_acct :: uintptr(51) +SYS_umount2 :: uintptr(52) +SYS_lock :: uintptr(53) +SYS_ioctl :: uintptr(54) +SYS_fcntl :: uintptr(55) +SYS_mpx :: uintptr(56) +SYS_setpgid :: uintptr(57) +SYS_ulimit :: uintptr(58) +SYS_oldolduname :: uintptr(59) +SYS_umask :: uintptr(60) +SYS_chroot :: uintptr(61) +SYS_ustat :: uintptr(62) +SYS_dup2 :: uintptr(63) +SYS_getppid :: uintptr(64) +SYS_getpgrp :: uintptr(65) +SYS_setsid :: uintptr(66) +SYS_sigaction :: uintptr(67) +SYS_sgetmask :: uintptr(68) +SYS_ssetmask :: uintptr(69) +SYS_setreuid :: uintptr(70) +SYS_setregid :: uintptr(71) +SYS_sigsuspend :: uintptr(72) +SYS_sigpending :: uintptr(73) +SYS_sethostname :: uintptr(74) +SYS_setrlimit :: uintptr(75) +SYS_getrlimit :: uintptr(76) +SYS_getrusage :: uintptr(77) +SYS_gettimeofday :: uintptr(78) +SYS_settimeofday :: uintptr(79) +SYS_getgroups :: uintptr(80) +SYS_setgroups :: uintptr(81) +SYS_select :: uintptr(82) +SYS_symlink :: uintptr(83) +SYS_oldlstat :: uintptr(84) +SYS_readlink :: uintptr(85) +SYS_uselib :: uintptr(86) +SYS_swapon :: uintptr(87) +SYS_reboot :: uintptr(88) +SYS_readdir :: uintptr(89) +SYS_mmap :: uintptr(90) +SYS_munmap :: uintptr(91) +SYS_truncate :: uintptr(92) +SYS_ftruncate :: uintptr(93) +SYS_fchmod :: uintptr(94) +SYS_fchown :: uintptr(95) +SYS_getpriority :: uintptr(96) +SYS_setpriority :: uintptr(97) +SYS_profil :: uintptr(98) +SYS_statfs :: uintptr(99) +SYS_fstatfs :: uintptr(100) +SYS_ioperm :: uintptr(101) +SYS_socketcall :: uintptr(102) +SYS_syslog :: uintptr(103) +SYS_setitimer :: uintptr(104) +SYS_getitimer :: uintptr(105) +SYS_stat :: uintptr(106) +SYS_lstat :: uintptr(107) +SYS_fstat :: uintptr(108) +SYS_olduname :: uintptr(109) +SYS_iopl :: uintptr(110) +SYS_vhangup :: uintptr(111) +SYS_idle :: uintptr(112) +SYS_vm86old :: uintptr(113) +SYS_wait4 :: uintptr(114) +SYS_swapoff :: uintptr(115) +SYS_sysinfo :: uintptr(116) +SYS_ipc :: uintptr(117) +SYS_fsync :: uintptr(118) +SYS_sigreturn :: uintptr(119) +SYS_clone :: uintptr(120) +SYS_setdomainname :: uintptr(121) +SYS_uname :: uintptr(122) +SYS_modify_ldt :: uintptr(123) +SYS_adjtimex :: uintptr(124) +SYS_mprotect :: uintptr(125) +SYS_sigprocmask :: uintptr(126) +SYS_create_module :: uintptr(127) +SYS_init_module :: uintptr(128) +SYS_delete_module :: uintptr(129) +SYS_get_kernel_syms :: uintptr(130) +SYS_quotactl :: uintptr(131) +SYS_getpgid :: uintptr(132) +SYS_fchdir :: uintptr(133) +SYS_bdflush :: uintptr(134) +SYS_sysfs :: uintptr(135) +SYS_personality :: uintptr(136) +SYS_afs_syscall :: uintptr(137) +SYS_setfsuid :: uintptr(138) +SYS_setfsgid :: uintptr(139) +SYS__llseek :: uintptr(140) +SYS_getdents :: uintptr(141) +SYS__newselect :: uintptr(142) +SYS_flock :: uintptr(143) +SYS_msync :: uintptr(144) +SYS_readv :: uintptr(145) +SYS_writev :: uintptr(146) +SYS_getsid :: uintptr(147) +SYS_fdatasync :: uintptr(148) +SYS__sysctl :: uintptr(149) +SYS_mlock :: uintptr(150) +SYS_munlock :: uintptr(151) +SYS_mlockall :: uintptr(152) +SYS_munlockall :: uintptr(153) +SYS_sched_setparam :: uintptr(154) +SYS_sched_getparam :: uintptr(155) +SYS_sched_setscheduler :: uintptr(156) +SYS_sched_getscheduler :: uintptr(157) +SYS_sched_yield :: uintptr(158) +SYS_sched_get_priority_max :: uintptr(159) +SYS_sched_get_priority_min :: uintptr(160) +SYS_sched_rr_get_interval :: uintptr(161) +SYS_nanosleep :: uintptr(162) +SYS_mremap :: uintptr(163) +SYS_setresuid :: uintptr(164) +SYS_getresuid :: uintptr(165) +SYS_vm86 :: uintptr(166) +SYS_query_module :: uintptr(167) +SYS_poll :: uintptr(168) +SYS_nfsservctl :: uintptr(169) +SYS_setresgid :: uintptr(170) +SYS_getresgid :: uintptr(171) +SYS_prctl :: uintptr(172) +SYS_rt_sigreturn :: uintptr(173) +SYS_rt_sigaction :: uintptr(174) +SYS_rt_sigprocmask :: uintptr(175) +SYS_rt_sigpending :: uintptr(176) +SYS_rt_sigtimedwait :: uintptr(177) +SYS_rt_sigqueueinfo :: uintptr(178) +SYS_rt_sigsuspend :: uintptr(179) +SYS_pread64 :: uintptr(180) +SYS_pwrite64 :: uintptr(181) +SYS_chown :: uintptr(182) +SYS_getcwd :: uintptr(183) +SYS_capget :: uintptr(184) +SYS_capset :: uintptr(185) +SYS_sigaltstack :: uintptr(186) +SYS_sendfile :: uintptr(187) +SYS_getpmsg :: uintptr(188) +SYS_putpmsg :: uintptr(189) +SYS_vfork :: uintptr(190) +SYS_ugetrlimit :: uintptr(191) +SYS_mmap2 :: uintptr(192) +SYS_truncate64 :: uintptr(193) +SYS_ftruncate64 :: uintptr(194) +SYS_stat64 :: uintptr(195) +SYS_lstat64 :: uintptr(196) +SYS_fstat64 :: uintptr(197) +SYS_lchown32 :: uintptr(198) +SYS_getuid32 :: uintptr(199) +SYS_getgid32 :: uintptr(200) +SYS_geteuid32 :: uintptr(201) +SYS_getegid32 :: uintptr(202) +SYS_setreuid32 :: uintptr(203) +SYS_setregid32 :: uintptr(204) +SYS_getgroups32 :: uintptr(205) +SYS_setgroups32 :: uintptr(206) +SYS_fchown32 :: uintptr(207) +SYS_setresuid32 :: uintptr(208) +SYS_getresuid32 :: uintptr(209) +SYS_setresgid32 :: uintptr(210) +SYS_getresgid32 :: uintptr(211) +SYS_chown32 :: uintptr(212) +SYS_setuid32 :: uintptr(213) +SYS_setgid32 :: uintptr(214) +SYS_setfsuid32 :: uintptr(215) +SYS_setfsgid32 :: uintptr(216) +SYS_pivot_root :: uintptr(217) +SYS_mincore :: uintptr(218) +SYS_madvise :: uintptr(219) +SYS_getdents64 :: uintptr(220) +SYS_fcntl64 :: uintptr(221) +// 222 is unused +// 223 is unused +SYS_gettid :: uintptr(224) +SYS_readahead :: uintptr(225) +SYS_setxattr :: uintptr(226) +SYS_lsetxattr :: uintptr(227) +SYS_fsetxattr :: uintptr(228) +SYS_getxattr :: uintptr(229) +SYS_lgetxattr :: uintptr(230) +SYS_fgetxattr :: uintptr(231) +SYS_listxattr :: uintptr(232) +SYS_llistxattr :: uintptr(233) +SYS_flistxattr :: uintptr(234) +SYS_removexattr :: uintptr(235) +SYS_lremovexattr :: uintptr(236) +SYS_fremovexattr :: uintptr(237) +SYS_tkill :: uintptr(238) +SYS_sendfile64 :: uintptr(239) +SYS_futex :: uintptr(240) +SYS_sched_setaffinity :: uintptr(241) +SYS_sched_getaffinity :: uintptr(242) +SYS_set_thread_area :: uintptr(243) +SYS_get_thread_area :: uintptr(244) +SYS_io_setup :: uintptr(245) +SYS_io_destroy :: uintptr(246) +SYS_io_getevents :: uintptr(247) +SYS_io_submit :: uintptr(248) +SYS_io_cancel :: uintptr(249) +SYS_fadvise64 :: uintptr(250) +// 251 is available for reuse (was briefly sys_set_zone_reclaim) +SYS_exit_group :: uintptr(252) +SYS_lookup_dcookie :: uintptr(253) +SYS_epoll_create :: uintptr(254) +SYS_epoll_ctl :: uintptr(255) +SYS_epoll_wait :: uintptr(256) +SYS_remap_file_pages :: uintptr(257) +SYS_set_tid_address :: uintptr(258) +SYS_timer_create :: uintptr(259) +SYS_timer_settime :: uintptr(260) +SYS_timer_gettime :: uintptr(261) +SYS_timer_getoverrun :: uintptr(262) +SYS_timer_delete :: uintptr(263) +SYS_clock_settime :: uintptr(264) +SYS_clock_gettime :: uintptr(265) +SYS_clock_getres :: uintptr(266) +SYS_clock_nanosleep :: uintptr(267) +SYS_statfs64 :: uintptr(268) +SYS_fstatfs64 :: uintptr(269) +SYS_tgkill :: uintptr(270) +SYS_utimes :: uintptr(271) +SYS_fadvise64_64 :: uintptr(272) +SYS_vserver :: uintptr(273) +SYS_mbind :: uintptr(274) +SYS_get_mempolicy :: uintptr(275) +SYS_set_mempolicy :: uintptr(276) +SYS_mq_open :: uintptr(277) +SYS_mq_unlink :: uintptr(278) +SYS_mq_timedsend :: uintptr(279) +SYS_mq_timedreceive :: uintptr(280) +SYS_mq_notify :: uintptr(281) +SYS_mq_getsetattr :: uintptr(282) +SYS_kexec_load :: uintptr(283) +SYS_waitid :: uintptr(284) +// 285 sys_setaltroot +SYS_add_key :: uintptr(286) +SYS_request_key :: uintptr(287) +SYS_keyctl :: uintptr(288) +SYS_ioprio_set :: uintptr(289) +SYS_ioprio_get :: uintptr(290) +SYS_inotify_init :: uintptr(291) +SYS_inotify_add_watch :: uintptr(292) +SYS_inotify_rm_watch :: uintptr(293) +SYS_migrate_pages :: uintptr(294) +SYS_openat :: uintptr(295) +SYS_mkdirat :: uintptr(296) +SYS_mknodat :: uintptr(297) +SYS_fchownat :: uintptr(298) +SYS_futimesat :: uintptr(299) +SYS_fstatat64 :: uintptr(300) +SYS_unlinkat :: uintptr(301) +SYS_renameat :: uintptr(302) +SYS_linkat :: uintptr(303) +SYS_symlinkat :: uintptr(304) +SYS_readlinkat :: uintptr(305) +SYS_fchmodat :: uintptr(306) +SYS_faccessat :: uintptr(307) +SYS_pselect6 :: uintptr(308) +SYS_ppoll :: uintptr(309) +SYS_unshare :: uintptr(310) +SYS_set_robust_list :: uintptr(311) +SYS_get_robust_list :: uintptr(312) +SYS_splice :: uintptr(313) +SYS_sync_file_range :: uintptr(314) +SYS_tee :: uintptr(315) +SYS_vmsplice :: uintptr(316) +SYS_move_pages :: uintptr(317) +SYS_getcpu :: uintptr(318) +SYS_epoll_pwait :: uintptr(319) +SYS_utimensat :: uintptr(320) +SYS_signalfd :: uintptr(321) +SYS_timerfd_create :: uintptr(322) +SYS_eventfd :: uintptr(323) +SYS_fallocate :: uintptr(324) +SYS_timerfd_settime :: uintptr(325) +SYS_timerfd_gettime :: uintptr(326) +SYS_signalfd4 :: uintptr(327) +SYS_eventfd2 :: uintptr(328) +SYS_epoll_create1 :: uintptr(329) +SYS_dup3 :: uintptr(330) +SYS_pipe2 :: uintptr(331) +SYS_inotify_init1 :: uintptr(332) +SYS_preadv :: uintptr(333) +SYS_pwritev :: uintptr(334) +SYS_rt_tgsigqueueinfo :: uintptr(335) +SYS_perf_event_open :: uintptr(336) +SYS_recvmmsg :: uintptr(337) +SYS_fanotify_init :: uintptr(338) +SYS_fanotify_mark :: uintptr(339) +SYS_prlimit64 :: uintptr(340) +SYS_name_to_handle_at :: uintptr(341) +SYS_open_by_handle_at :: uintptr(342) +SYS_clock_adjtime :: uintptr(343) +SYS_syncfs :: uintptr(344) +SYS_sendmmsg :: uintptr(345) +SYS_setns :: uintptr(346) +SYS_process_vm_readv :: uintptr(347) +SYS_process_vm_writev :: uintptr(348) +SYS_kcmp :: uintptr(349) +SYS_finit_module :: uintptr(350) +SYS_sched_setattr :: uintptr(351) +SYS_sched_getattr :: uintptr(352) +SYS_renameat2 :: uintptr(353) +SYS_seccomp :: uintptr(354) +SYS_getrandom :: uintptr(355) +SYS_memfd_create :: uintptr(356) +SYS_bpf :: uintptr(357) +SYS_execveat :: uintptr(358) +SYS_socket :: uintptr(359) +SYS_socketpair :: uintptr(360) +SYS_bind :: uintptr(361) +SYS_connect :: uintptr(362) +SYS_listen :: uintptr(363) +SYS_accept4 :: uintptr(364) +SYS_getsockopt :: uintptr(365) +SYS_setsockopt :: uintptr(366) +SYS_getsockname :: uintptr(367) +SYS_getpeername :: uintptr(368) +SYS_sendto :: uintptr(369) +SYS_sendmsg :: uintptr(370) +SYS_recvfrom :: uintptr(371) +SYS_recvmsg :: uintptr(372) +SYS_shutdown :: uintptr(373) +SYS_userfaultfd :: uintptr(374) +SYS_membarrier :: uintptr(375) +SYS_mlock2 :: uintptr(376) +SYS_copy_file_range :: uintptr(377) +SYS_preadv2 :: uintptr(378) +SYS_pwritev2 :: uintptr(379) +SYS_pkey_mprotect :: uintptr(380) +SYS_pkey_alloc :: uintptr(381) +SYS_pkey_free :: uintptr(382) +SYS_statx :: uintptr(383) +SYS_arch_prctl :: uintptr(384) +SYS_io_pgetevents :: uintptr(385) +SYS_rseq :: uintptr(386) +SYS_semget :: uintptr(393) +SYS_semctl :: uintptr(394) +SYS_shmget :: uintptr(395) +SYS_shmctl :: uintptr(396) +SYS_shmat :: uintptr(397) +SYS_shmdt :: uintptr(398) +SYS_msgget :: uintptr(399) +SYS_msgsnd :: uintptr(400) +SYS_msgrcv :: uintptr(401) +SYS_msgctl :: uintptr(402) +SYS_clock_gettime64 :: uintptr(403) +SYS_clock_settime64 :: uintptr(404) +SYS_clock_adjtime64 :: uintptr(405) +SYS_clock_getres_time64 :: uintptr(406) +SYS_clock_nanosleep_time64 :: uintptr(407) +SYS_timer_gettime64 :: uintptr(408) +SYS_timer_settime64 :: uintptr(409) +SYS_timerfd_gettime64 :: uintptr(410) +SYS_timerfd_settime64 :: uintptr(411) +SYS_utimensat_time64 :: uintptr(412) +SYS_pselect6_time64 :: uintptr(413) +SYS_ppoll_time64 :: uintptr(414) +SYS_io_pgetevents_time64 :: uintptr(416) +SYS_recvmmsg_time64 :: uintptr(417) +SYS_mq_timedsend_time64 :: uintptr(418) +SYS_mq_timedreceive_time64 :: uintptr(419) +SYS_semtimedop_time64 :: uintptr(420) +SYS_rt_sigtimedwait_time64 :: uintptr(421) +SYS_futex_time64 :: uintptr(422) +SYS_sched_rr_get_interval_time64 :: uintptr(423) +SYS_pidfd_send_signal :: uintptr(424) +SYS_io_uring_setup :: uintptr(425) +SYS_io_uring_enter :: uintptr(426) +SYS_io_uring_register :: uintptr(427) +SYS_open_tree :: uintptr(428) +SYS_move_mount :: uintptr(429) +SYS_fsopen :: uintptr(430) +SYS_fsconfig :: uintptr(431) +SYS_fsmount :: uintptr(432) +SYS_fspick :: uintptr(433) +SYS_pidfd_open :: uintptr(434) +SYS_clone3 :: uintptr(435) +SYS_close_range :: uintptr(436) +SYS_openat2 :: uintptr(437) +SYS_pidfd_getfd :: uintptr(438) +SYS_faccessat2 :: uintptr(439) +SYS_process_madvise :: uintptr(440) +SYS_epoll_pwait2 :: uintptr(441) +SYS_mount_setattr :: uintptr(442) +SYS_quotactl_fd :: uintptr(443) +SYS_landlock_create_ruleset :: uintptr(444) +SYS_landlock_add_rule :: uintptr(445) +SYS_landlock_restrict_self :: uintptr(446) +SYS_memfd_secret :: uintptr(447) +SYS_process_mrelease :: uintptr(448) +SYS_futex_waitv :: uintptr(449) +SYS_set_mempolicy_home_node :: uintptr(450) +SYS_cachestat :: uintptr(451) +SYS_fchmodat2 :: uintptr(452) diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin new file mode 100644 index 000000000..214aff9cf --- /dev/null +++ b/core/sys/linux/types.odin @@ -0,0 +1,566 @@ +//+build linux +package linux + +/// Represents storage device handle +Dev :: distinct int + +/// Represents 32-bit user id +Uid :: distinct u32 + +/// Represents 32-bit group id +Gid :: distinct u32 + +/// Process id's +Pid :: distinct int + +/// Represents pid, pifd, pgid values in general +Id :: distinct uint + +/// Represents a file descriptor +Fd :: distinct i32 + +/// Represents a PID file descriptor +Pid_FD :: distinct i32 + +/// Represents 64-bit inode number for files +/// Used pretty much only in struct Stat64 for 32-bit platforms +Inode :: distinct u64 + +/// Represents time with nanosecond precision +Time_Spec :: struct { + time_sec: uint, + time_nsec: uint, +} + +/// Represents time with millisecond precision +Time_Val :: struct { + seconds: int, + microseconds: int, +} + +/// open.2 flags +Open_Flags :: bit_set[Open_Flags_Bits; u32] + +/// Flags for the file descriptor to be passed in some syscalls +FD_Flags :: bit_set[FD_Flags_Bits; i32] + +/// Represents file's permission and status bits +/// Example: +/// When you're passing a value of this type the recommended usage is +/// sys.Mode{.S_IXOTH, .S_IROTH} | sys.S_IRWXU | sys.S_IRWXG +/// This would generate a mode that has full permissions for the +/// file's owner and group, and only "read" and "execute" bits +/// for others. +Mode :: bit_set[Mode_Bits; u32] + +when ODIN_ARCH == .amd64 { + // x86-64 has mode and nlink swapped for some reason + _Arch_Stat :: struct { + dev: Dev, + ino: Inode, + nlink: uint, + mode: Mode, + uid: Uid, + gid: Gid, + _: u32, + rdev: Dev, + size: uint, + blksize: uint, + blocks: uint, + atime: Time_Spec, + mtime: Time_Spec, + ctime: Time_Spec, + _: [3]uint, + } +} else when ODIN_ARCH == .arm64 { + _Arch_Stat :: struct { + dev: Dev, + ino: Inode, + mode: Mode, + nlink: u32, + uid: Uid, + gid: Gid, + rdev: Dev, + _: u64, + size: int, + blksize: i32, + _: i32, + blocks: int, + atime: Time_Spec, + mtime: Time_Spec, + ctime: Time_Spec, + _: [3]uint, + } +} else { + _Arch_Stat :: struct { + dev: Dev, + _: [4]u8, + _ino: uint, // Old 32-bit inode number, don't use + mode: Mode, + nlink: u32, + uid: Uid, + gid: Gid, + rdev: Dev, + size: i64, + blksize: uint, + blocks: u64, + atim: Time_Spec, + mtim: Time_Spec, + ctim: Time_Spec, + ino: Inode, + } +} + +/// Represents the file state. +/// Mirrors struct stat in glibc/linux kernel. +/// If you're on 32-bit platform, consider using Stat64 instead +Stat :: struct { + using _impl_stat: _Arch_Stat, +} + +/// Timestamp type used for Statx struct +Statx_Timestamp :: struct { + sec: i64, + nsec: u32, + _: i32, +} + +/// Query params/results for `statx()` +Statx_Mask :: bit_set[Statx_Mask_Bits; u32] + +/// File attributes, returned by statx. This bitset is also +/// used to specify which attributes are present, not just +/// their value. +Statx_Attr :: bit_set[Statx_Attr_Bits; u64] + +/// The extended Stat struct +Statx :: struct { + mask: Statx_Mask, + blksize: u32, + attributes: Statx_Attr, + nlink: u32, + uid: Uid, + gid: Gid, + // Note(flysand): mode is 16-bit on linux + there's + // 16-bit padding following it. Since our mode is 32-bits, + // we're using the padding. This should be fine because + // the placement of that padding suggests it was going to + // be used for the Mode bits anyway. + mode: Mode, + ino: Inode, + size: u64, + blocks: u64, + attributes_mask: Statx_Attr, + atime: Statx_Timestamp, + btime: Statx_Timestamp, + ctime: Statx_Timestamp, + mtime: Statx_Timestamp, + rdev_major: u32, + rdev_minor: u32, + dev_major: u32, + dev_minor: u32, + mnt_id: u64, + dio_mem_align: u32, + dio_offset_align: u32, + _: [12]u64, +} + +/// Mount flags for filesystem +FS_Flags :: bit_set[FS_Flags_Bits; u32] + +when size_of(int) == 8 { + _Arch_Stat_FS :: struct { + // Note(flysand): The FS_Magic bits are never above + // 32-bits, so it should be fine for now... + type: FS_Magic, + _: u32, + bsize: i64, + blocks: i64, + bfree: i64, + bavail: i64, + files: i64, + ffree: i64, + fsid : [2]i32, + namelen: i64, + frsize: i64, + // Note(flysand): Same story as type + flags: FS_Flags, + _: u32, + spare: [4]i64, + } +} else { + _Arch_Stat_FS :: struct { + type: FS_Magic, + bsize: u32, + blocks: u64, + bfree: u64, + bavail: u64, + files: u64, + ffree: u64, + fsid: [2]i32, + namelen: u32, + frsize: u32, + flags: FS_Flags, + spare: [4]u32, + } +} + +Stat_FS :: struct { + using _impl_stat_fs: _Arch_Stat_FS, +} + +/// Flags for close_range.2 +Close_Range_Flags :: bit_set[Close_Range_Flags_Bits; u32] + +/// Flags for rename.2 +Rename_Flags :: bit_set[Rename_Flags_Bits; u32] + +/// Directory entry +/// Recommended to use this with dirent_iterator() +/// and dirent_name() +Dirent :: struct { + ino: Inode, + off: i64, + reclen: u16, + type: Dirent_Type, + name: [0]u8, // See dirent_name +} + +/// Lock record for fcntl.2 +FLock :: struct { + type: FLock_Type, + whence: Seek_Whence, + start: i64, + len: i64, + pid: Pid, +} + +/// Flags for fcntl_notify +FD_Notifications :: bit_set[FD_Notifications_Bits; i32] + +/// Seals for fcntl_add_seals +Seal :: bit_set[Seal_Bits; i32] + +/// Represents owner that receives events on file updates +F_Owner :: struct { + type: F_Owner_Type, + pid: Pid, +} + +/// Events for ppoll +Fd_Poll_Events :: bit_set[Fd_Poll_Events_Bits; u16] + +/// Struct for ppoll +Poll_Fd :: struct { + fd: Fd, + events: Fd_Poll_Events, + revents: Fd_Poll_Events, +} + +/// Specifies protection for memory pages +Mem_Protection :: bit_set[Mem_Protection_Bits; i32] + +/// Flags for mmap +Map_Flags :: bit_set[Map_Flags_Bits; i32] + +/// Flags for mlock.2 +MLock_Flags :: bit_set[MLock_Flags_Bits; u32] + +/// Flags for msync.2 +MSync_Flags :: bit_set[MSync_Flags_Bits; i32] + +/// Access rights for pkey_alloc.2 +PKey_Access_Rights :: bit_set[PKey_Access_Bits; u32] + +/// Flags for mremap.2 +MRemap_Flags :: bit_set[MRemap_Flags_Bits; i32] + +/// Flags for getrandom syscall +Get_Random_Flags :: bit_set[Get_Random_Flags_Bits; i32] + +/// Flags for perf_event_open syscall +Perf_Flags :: bit_set[Perf_Flags_Bits; uint] + +Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64] + +Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64] + +Perf_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64] + +/// Specifies which branches to include in branch record +Branch_Sample_Type :: bit_set[Branch_Sample_Type_Bits; u64] + +/// The struct for perf_event_open +Perf_Event_Attr :: struct #packed { + type: Perf_Event_Type, + size: u32, + config: struct #raw_union { + hw: Perf_Hardware_Id, + sw: Perf_Software_Id, + cache: u64, + other: u64, + }, + sample: struct #raw_union { + period: u64, + frequency: u64, + }, + sample_type: Perf_Event_Sample_Type, + read_format: Perf_Read_Format, + flags: Perf_Event_Flags, + wakeup: struct #raw_union { + events: u32, + watermark: u32, + }, + breakpoint_type: Hardware_Breakpoint_Type, + using _: struct #raw_union { + breakpoint_addr: u64, + kprobe_func: u64, + uprobe_path: u64, + config1: u64, + }, + using _: struct #raw_union { + breakpoint_len: u64, + kprobe_addr: u64, + uprobe_offset: u64, + config2: u64, + }, + branch_sample_type: Branch_Sample_Type, + sample_regs_user: u64, + sample_stack_user: u32, + clock_id: i32, // TODO(flysand): clock_id + sample_regs_intr: u64, + aux_watermark: u32, + sample_max_stack: u16, + _: u16, +} + +/// The ring buffer structure when mmaping Perf_Event_Attr +Perf_Event_Mmap_Page :: struct #packed { + version: u32, + compat_version: u32, + lock: u32, + index: u32, + offset: i64, + time_enabled: u64, + time_running: u64, + cap: struct #raw_union { + capabilities: u64, + flags: Perf_Cap_Flags, + }, + pmc_width: u16, + time_shift: u16, + time_mult: u32, + time_offset: u64, + time_zero: u64, + size: u32, + reserved1: u32, + time_cycles: u64, + time_mask: u64, + reserved2: [116*8]u8, + data_head: u64, + data_tail: u64, + data_offset: u64, + data_size: u64, + aux_head: u64, + aux_tail: u64, + aux_offset: u64, + aux_size: u64, +} + +// TODO(flysand): Its taking too much effort to bind the other data structures related to perf_event_open + +/// Options for wait4() and waitpid() +Wait_Options :: bit_set[Wait_Option; i32] + +/// Flags for pidfd_open.2 +Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32] + +// Note(flysand): these could, in principle be implemented with bitfields, +// however there are ABI differences between odin's bitfields and linux sigsets. +// Mainly: +// 1. Odin's bitfields start from 0, whereas signals start from 1 +// 2. It's unclear how bitfields act in terms of ABI (are they an array of ints or an array of longs?). +// it makes a difference because ARM is big endian. +@private _SIGSET_NWORDS :: (1024 / (8 * size_of(uint))) +Sig_Set :: [_SIGSET_NWORDS]uint + +@private SI_MAX_SIZE :: 128 +@private SI_ARCH_PREAMBLE :: 3 * size_of(i32) +@private SI_PAD_SIZE :: (SI_MAX_SIZE - SI_ARCH_PREAMBLE) / size_of(i32) +@private SI_TIMER_PAD_SIZE :: size_of(Uid) - size_of(i32) + +Sig_Handler_Fn :: #type proc "c" (sig: Signal) +Sig_Restore_Fn :: #type proc "c" () + +Sig_Info :: struct #packed { + signo: Signal, + errno: Errno, + code: i32, + _pad0: i32, + using _union: struct #raw_union { + _pad1: [SI_PAD_SIZE]u8, + using _kill: struct { + pid: Pid, /* sender's pid */ + uid: Uid, /* sender's uid */ + }, + using _timer: struct { + timerid: i32, /* timer id */ + overrun: i32, /* overrun count */ + }, + /* POSIX.1b signals */ + using _rt: struct { + _pid0: Pid, /* sender's pid */ + _uid0: Uid, /* sender's uid */ + }, + /* SIGCHLD */ + using _sigchld: struct { + _pid1: Pid, /* which child */ + _uid1: Uid, /* sender's uid */ + status: i32, /* exit code */ + utime: uint, + stime: uint, //clock_t + }, + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + using _sigfault: struct { + addr: rawptr, /* faulting insn/memory ref. */ + addr_lsb: i16, /* LSB of the reported address */ + }, + /* SIGPOLL */ + using _sigpoll: struct { + band: int, /* POLL_IN, POLL_OUT, POLL_MSG */ + fd: Fd, + }, + /* SIGSYS */ + using _sigsys: struct { + call_addr: rawptr, /* calling user insn */ + syscall: i32, /* triggering system call number */ + arch: u32, /* AUDIT_ARCH_* of syscall */ + }, + }, +} + +Sig_Stack_Flags :: bit_set[Sig_Stack_Flag; i32] + +Sig_Stack :: struct { + sp: rawptr, + flags: Sig_Stack_Flags, + size: uintptr, +} + +Sig_Action :: struct($T: typeid) { + using _u: struct #raw_union { + handler: Sig_Handler_Fn, + sigaction: #type proc "c" (sig: Signal, si: ^Sig_Info, ctx: ^T), + }, + flags: uint, + restorer: Sig_Restore_Fn, + mask: Sig_Set, +} + + +/// Flags for the socket file descriptor +/// Note, on linux these are technically passed by OR'ing together +/// with Socket_Type, our wrapper does this under the hood. +Socket_FD_Flags :: bit_set[Socket_FD_Flags_Bits; int] + +/// Address family for the socket +/// Typically there's one address family for every protocol family +Address_Family :: distinct Protocol_Family + +/// Flags for the socket for send/recv calls +Socket_Msg :: bit_set[Socket_Msg_Bits; i32] + +/// Struct representing IPv4 socket address +Sock_Addr_In :: struct #packed { + sin_family: Address_Family, + sin_port: u16be, + sin_addr: [4]u8, +} + +/// Struct representing IPv6 socket address +Sock_Addr_In6 :: struct #packed { + sin6_family: Address_Family, + sin6_port: u16be, + sin6_flowinfo: u32, + sin6_addr: [16]u8, + sin6_scope_id: u32, +} + +/// Struct representing an arbitrary socket address +Sock_Addr_Any :: struct #raw_union { + using _: struct { + family: Address_Family, + port: u16be, + }, + using ipv4: Sock_Addr_In, + using ipv6: Sock_Addr_In6, +} + +/// Just an alias to make futex-values more visible +Futex :: u32 + +/// Flags for the futex (they are kept separately) +Futex_Flags :: bit_set[Futex_Flags_Bits; u32] + +/// Times +Tms :: struct { + tms_utime: int, + tms_stime: int, + tms_cutime: int, + tms_cstime: int, +} + +/// "Unix time-sharing system name", allegedly +/// Basically system info +UTS_Name :: struct { + sysname: [65]u8 `fmt:"s,0"`, + nodename: [65]u8 `fmt:"s,0"`, + release: [65]u8 `fmt:"s,0"`, + version: [65]u8 `fmt:"s,0"`, + machine: [65]u8 `fmt:"s,0"`, + domainname: [65]u8 `fmt:"s,0"`, +} + +/// Return buffer for the sysinfo syscall +Sys_Info :: struct { + uptime: int, + loads: [3]int, + totalram: uint, + freeram: uint, + sharedram: uint, + bufferram: uint, + totalswap: uint, + freeswap: uint, + procs: u16, + totalhigh: uint, + freehigh: uint, + mem_unit: i32, + _padding: [20 - (2 * size_of(int)) - size_of(i32)]u8, +} + +/// Resource limit +RLimit :: struct { + cur: uint, + max: uint, +} + +/// Structure representing how much of each resource +/// got used. +RUsage :: struct { + utime: Time_Val, + stime: Time_Val, + maxrss_word: int, + ixrss_word: int, + idrss_word: int, + isrss_word: int, + minflt_word: int, + majflt_word: int, + nswap_word: int, + inblock_word: int, + oublock_word: int, + msgsnd_word: int, + msgrcv_word: int, + nsignals_word: int, + nvcsw_word: int, + nivcsw_word: int, +} diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin new file mode 100644 index 000000000..a4c4aac32 --- /dev/null +++ b/core/sys/linux/wrappers.odin @@ -0,0 +1,121 @@ +//+build linux +package linux + +/// Low 8 bits of the exit code +/// Only retrieve the exit code if WIFEXITED(s) = true +WEXITSTATUS :: #force_inline proc "contextless" (s: u32) -> u32 { + return (s & 0xff00) >> 8 +} + +/// Termination signal +/// Only retrieve the code if WIFSIGNALED(s) = true +WTERMSIG :: #force_inline proc "contextless" (s: u32) -> u32 { + return s & 0x7f +} + +/// The signal that stopped the child +/// Only retrieve if WIFSTOPPED(s) = true +WSTOPSIG :: #force_inline proc "contextless" (s: u32) -> u32 { + return WEXITSTATUS(s) +} + +/// Check if the process terminated normally (via exit.2) +WIFEXITED :: #force_inline proc "contextless" (s: u32) -> bool { + return WTERMSIG(s) == 0 +} + +/// Check if the process signaled +WIFSIGNALED :: #force_inline proc "contextless" (s: u32) -> bool { + return cast(i8)(((s) & 0x7f) + 1) >> 1 > 0 +} + +/// Check if the process has stopped +WIFSTOPPED :: #force_inline proc "contextless" (s: u32) -> bool { + return (s & 0xff) == 0x7f +} + +/// Check if the process is continued by the tracee +WIFCONTINUED :: #force_inline proc "contextless" (s: u32) -> bool { + return s == 0xffff +} + +/// Check if the process dumped core +WCOREDUMP :: #force_inline proc "contextless" (s: u32) -> bool { + return s & 0x80 == 0x80 +} + +@private _sigmask :: proc "contextless" (sig: Signal) -> (uint) { + return 1 << ((cast(uint)(sig) - 1) % (8*size_of(uint))) +} +@private _sigword :: proc "contextless" (sig: Signal) -> (uint) { + return (cast(uint)sig - 1) / (8*size_of(uint)) +} + +// TODO: sigaddset etc + + +/// Iterate the results of getdents +/// Only iterates as much data as loaded in the buffer +/// In case you need to iterate *all* files in a directory +/// consider using dirent_get_iterate +/// +/// Example of using dirent_iterate_buf +/// // Get dirents into a buffer +/// buf: [128]u8 +/// sys.getdents(dirfd, buf[:]) +/// // Print the names of the files +/// for dir in sys.dirent_iterate_buf(buf[:], &offs) { +/// name := sys.dirent_name(dir) +/// fmt.println(name) +/// } +/// This function doesn't automatically make a request +/// for the buffer to be refilled +dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, cont: bool) { + // Stopped iterating when there's no space left + if offs^ >= len(buf) { + return nil, false + } + // Retrieve dirent form the current offset + dirent := cast(^Dirent) &buf[offs^] + // Add the stride of dirent struct to the current offset + offs^ += cast(int) dirent.reclen + return dirent, true +} + +/// Obtain the name of dirent as a string +/// The lifetime of the string is bound to the lifetime of the provided dirent structure +dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check { + str := transmute([^]u8) &dirent.name + // Note(flysand): The string size calculated above applies only to the ideal case + // we subtract 1 byte from the string size, because a null terminator is guaranteed + // to be present. But! That said, the dirents are aligned to 8 bytes and the padding + // between the null terminator and the start of the next struct may be not initialized + // which means we also have to scan these garbage bytes. + str_size := (cast(int) dirent.reclen) - 1 - cast(int) offset_of(Dirent, name) + // This skips *only* over the garbage, since if we're not garbage we're at nul terminator, + // which skips this loop + for str[str_size] != 0 { + str_size -= 1 + } + for str[str_size-1] == 0 { + str_size -= 1 + } + // Oh yeah btw i could also just `repne scasb` this thing, but honestly I started doing + // it the painful way, might as well finish doing it that way + return string(str[:str_size]) +} + +/// Constructor for the `futex_op` argument of a FUTEX_WAKE_OP call +futex_op :: proc "contextless" (arg_op: Futex_Arg_Op, cmp_op: Futex_Cmp_Op, op_arg: u32, cmp_arg: u32) -> u32 { + arg_op := cast(u32) arg_op + cmp_op := cast(u32) cmp_op + return (arg_op << 28) | (cmp_op << 24) | ((op_arg & 0xfff) << 12) | (cmp_arg & 0xfff) +} + +/// Helper function for constructing the config for caches +perf_cache_config :: #force_inline proc "contextless" (id: Perf_Hardware_Cache_Id, + op: Perf_Hardware_Cache_Op_Id, + res: Perf_Hardware_Cache_Result_Id) -> u64 +{ + return u64(id) | (u64(op) << 8) | (u64(res) << 16) +} \ No newline at end of file diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index c5f2902e9..77a79fe52 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -2,34 +2,32 @@ //+build linux package time -import "core:intrinsics" -import "core:sys/unix" +import linux "core:sys/linux" _get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - perf_attr := unix.Perf_Event_Attr{} - perf_attr.type = u32(unix.Perf_Type_Id.Hardware) - perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions) + // Get the file descriptor for the perf mapping + perf_attr := linux.Perf_Event_Attr{} perf_attr.size = size_of(perf_attr) + perf_attr.type = .HARDWARE + perf_attr.config.hw = .INSTRUCTIONS perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV} - fd := unix.sys_perf_event_open(&perf_attr, 0, -1, -1, 0) - if fd == -1 { + fd, perf_errno := linux.perf_event_open(&perf_attr, linux.Pid(0), -1, linux.Fd(-1), {}) + if perf_errno != nil { return 0, false } - defer unix.sys_close(fd) - + defer linux.close(fd) + // Map it into the memory page_size : uint = 4096 - ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0) - if ret < 0 && ret > -4096 { + addr, mmap_errno := linux.mmap(0, page_size, {.READ}, {.SHARED}, fd) + if mmap_errno != nil { return 0, false } - addr := rawptr(uintptr(ret)) - defer unix.sys_munmap(addr, page_size) - - event_page := (^unix.Perf_Event_mmap_Page)(addr) + defer linux.munmap(addr, page_size) + // Get the frequency from the mapped page + event_page := cast(^linux.Perf_Event_Mmap_Page) addr if .User_Time not_in event_page.cap.flags { return 0, false } - frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) return frequency, true } diff --git a/examples/all/all_linux.odin b/examples/all/all_linux.odin new file mode 100644 index 000000000..18bba951c --- /dev/null +++ b/examples/all/all_linux.odin @@ -0,0 +1,6 @@ +//+build linux +package all + +import linux "core:sys/linux" + +_ :: linux \ No newline at end of file diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index fa1e8d995..9cc915778 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -39,10 +39,13 @@ import TTF "vendor:sdl2/ttf" import vk "vendor:vulkan" -import NS "vendor:darwin/Foundation" -import MTL "vendor:darwin/Metal" -import MTK "vendor:darwin/MetalKit" -import CA "vendor:darwin/QuartzCore" +// NOTE(flysand): Since conditional imports are disabled for now I'll have to just disable these +// when ODIN_OS == "darwin" { +// import NS "vendor:darwin/Foundation" +// import MTL "vendor:darwin/Metal" +// import MTK "vendor:darwin/MetalKit" +// import CA "vendor:darwin/QuartzCore" +// } // NOTE(bill): only one can be checked at a time import lua_5_4 "vendor:lua/5.4" @@ -91,10 +94,10 @@ _ :: TTF _ :: vk -_ :: NS -_ :: MTL -_ :: MTK -_ :: CA +// _ :: NS +// _ :: MTL +// _ :: MTK +// _ :: CA _ :: lua_5_4 diff --git a/examples/test-freestanding/main.odin b/examples/test-freestanding/main.odin deleted file mode 100644 index 518e3d45e..000000000 --- a/examples/test-freestanding/main.odin +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import "core:intrinsics" - -SUS_exit :: uintptr(60) -SUS_write ::uintptr(1) -STDOUT_FILENO :: int(1) - -sus_write :: proc "contextless" (fd: int, buf: cstring, size: uint) -> int { - return int(intrinsics.syscall( - SUS_write, - cast(uintptr) fd, - cast(uintptr) cast(rawptr) buf, - cast(uintptr) size - )) -} - -@(link_name = "sussy_baka") -sus_exit :: proc "contextless" (code: $T)->! { - intrinsics.syscall(SUS_exit, uintptr(code)) - unreachable() -} - -sus :: proc {sus_write, sus_exit} - -@(link_name="_start", export) _start :: proc "c" ()->! { - str :: cstring("Hello, world!\n") - sus_write(STDOUT_FILENO, str, uint(14)); - sus_exit(0) -}