Browse Source

Merge pull request #4118 from andradei/posix-linux

Linux POSIX support
Laytan 1 year ago
parent
commit
0157ff1541

+ 7 - 4
core/os/os_linux.odin

@@ -242,10 +242,13 @@ F_SETFL: int : 4 /* Set file flags */
 
 
 // NOTE(zangent): These are OS specific!
 // NOTE(zangent): These are OS specific!
 // Do not mix these up!
 // Do not mix these up!
-RTLD_LAZY         :: 0x001
-RTLD_NOW          :: 0x002
-RTLD_BINDING_MASK :: 0x3
-RTLD_GLOBAL       :: 0x100
+RTLD_LAZY         :: 0x0001
+RTLD_NOW          :: 0x0002
+RTLD_BINDING_MASK :: 0x0003
+RTLD_GLOBAL       :: 0x0100
+RTLD_NOLOAD       :: 0x0004
+RTLD_DEEPBIND     :: 0x0008
+RTLD_NODELETE     :: 0x1000
 
 
 socklen_t :: c.int
 socklen_t :: c.int
 
 

+ 37 - 60
core/sys/linux/bits.odin

@@ -152,66 +152,43 @@ Errno :: enum i32 {
 	RDONLY flag is not present, because it has the value of 0, i.e. it is the
 	RDONLY flag is not present, because it has the value of 0, i.e. it is the
 	default, unless WRONLY or RDWR is specified.
 	default, unless WRONLY or RDWR is specified.
 */
 */
-when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 {
-	Open_Flags_Bits :: enum {
-		WRONLY    = 0,
-		RDWR      = 1,
-		CREAT     = 6,
-		EXCL      = 7,
-		NOCTTY    = 8,
-		TRUNC     = 9,
-		APPEND    = 10,
-		NONBLOCK  = 11,
-		DSYNC     = 12,
-		ASYNC     = 13,
-		DIRECT    = 14,
-		LARGEFILE = 15,
-		DIRECTORY = 16,
-		NOFOLLOW  = 17,
-		NOATIME   = 18,
-		CLOEXEC   = 19,
-		PATH      = 21,
-	}
-	// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
-	#assert(1 << uint(Open_Flags_Bits.WRONLY)    == 0o0000000_1)
-	#assert(1 << uint(Open_Flags_Bits.RDWR)      == 0o0000000_2)
-	#assert(1 << uint(Open_Flags_Bits.CREAT)     == 0o00000_100)
-	#assert(1 << uint(Open_Flags_Bits.EXCL)      == 0o00000_200)
-	#assert(1 << uint(Open_Flags_Bits.NOCTTY)    == 0o00000_400)
-	#assert(1 << uint(Open_Flags_Bits.TRUNC)     == 0o0000_1000)
-	#assert(1 << uint(Open_Flags_Bits.APPEND)    == 0o0000_2000)
-	#assert(1 << uint(Open_Flags_Bits.NONBLOCK)  == 0o0000_4000)
-	#assert(1 << uint(Open_Flags_Bits.DSYNC)     == 0o000_10000)
-	#assert(1 << uint(Open_Flags_Bits.ASYNC)     == 0o000_20000)
-	#assert(1 << uint(Open_Flags_Bits.DIRECT)    == 0o000_40000)
-	#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
-	#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
-	#assert(1 << uint(Open_Flags_Bits.NOFOLLOW)  == 0o00_400000)
-	#assert(1 << uint(Open_Flags_Bits.NOATIME)   == 0o0_1000000)
-	#assert(1 << uint(Open_Flags_Bits.CLOEXEC)   == 0o0_2000000)
-	#assert(1 << uint(Open_Flags_Bits.PATH)      == 0o_10000000)
-
-} else {
-	Open_Flags_Bits :: enum {
-		WRONLY    = 0,
-		RDWR      = 1,
-		CREAT     = 6,
-		EXCL      = 7,
-		NOCTTY    = 8,
-		TRUNC     = 9,
-		APPEND    = 10,
-		NONBLOCK  = 11,
-		DSYNC     = 12,
-		ASYNC     = 13,
-		DIRECTORY = 14,
-		NOFOLLOW  = 15,
-		DIRECT    = 16,
-		LARGEFILE = 17,
-		NOATIME   = 18,
-		CLOEXEC   = 19,
-		PATH      = 21,
-	}
-}
+Open_Flags_Bits :: enum {
+	WRONLY    = 0,
+	RDWR      = 1,
+	CREAT     = 6,
+	EXCL      = 7,
+	NOCTTY    = 8,
+	TRUNC     = 9,
+	APPEND    = 10,
+	NONBLOCK  = 11,
+	DSYNC     = 12,
+	ASYNC     = 13,
+	DIRECT    = 14,
+	LARGEFILE = 15,
+	DIRECTORY = 16,
+	NOFOLLOW  = 17,
+	NOATIME   = 18,
+	CLOEXEC   = 19,
+	PATH      = 21,
+}
+// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
+#assert(1 << uint(Open_Flags_Bits.WRONLY)    == 0o0000000_1)
+#assert(1 << uint(Open_Flags_Bits.RDWR)      == 0o0000000_2)
+#assert(1 << uint(Open_Flags_Bits.CREAT)     == 0o00000_100)
+#assert(1 << uint(Open_Flags_Bits.EXCL)      == 0o00000_200)
+#assert(1 << uint(Open_Flags_Bits.NOCTTY)    == 0o00000_400)
+#assert(1 << uint(Open_Flags_Bits.TRUNC)     == 0o0000_1000)
+#assert(1 << uint(Open_Flags_Bits.APPEND)    == 0o0000_2000)
+#assert(1 << uint(Open_Flags_Bits.NONBLOCK)  == 0o0000_4000)
+#assert(1 << uint(Open_Flags_Bits.DSYNC)     == 0o000_10000)
+#assert(1 << uint(Open_Flags_Bits.ASYNC)     == 0o000_20000)
+#assert(1 << uint(Open_Flags_Bits.DIRECT)    == 0o000_40000)
+#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
+#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
+#assert(1 << uint(Open_Flags_Bits.NOFOLLOW)  == 0o00_400000)
+#assert(1 << uint(Open_Flags_Bits.NOATIME)   == 0o0_1000000)
+#assert(1 << uint(Open_Flags_Bits.CLOEXEC)   == 0o0_2000000)
+#assert(1 << uint(Open_Flags_Bits.PATH)      == 0o_10000000)
 
 
 /*
 /*
 	Bits for FD_Flags bitset
 	Bits for FD_Flags bitset

+ 15 - 5
core/sys/posix/dirent.odin

@@ -193,13 +193,23 @@ when ODIN_OS == .Darwin {
 } else when ODIN_OS == .NetBSD {
 } else when ODIN_OS == .NetBSD {
 
 
 	dirent :: struct {
 	dirent :: struct {
-		d_ino:     ino_t,                    /* [PSX] file number of entry */
-		d_reclen:  c.uint16_t,               /* length of this record */
-		d_namelen: c.uint16_t,               /* length of string in d_name */
-		d_type:    D_Type,                   /* file type  */
-		d_name:    [512]c.char `fmt:"s,0"`,  /* [PSX] entry name */
+		d_ino:     ino_t,                   /* [PSX] file number of entry */
+		d_reclen:  c.uint16_t,              /* length of this record */
+		d_namelen: c.uint16_t,              /* length of string in d_name */
+		d_type:    D_Type,                  /* file type  */
+		d_name:    [512]c.char `fmt:"s,0"`, /* [PSX] entry name */
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+
+		dirent :: struct {
+			d_ino:    u64,                     /* [PSX] file number of entry */
+			d_off:    i64,                     /* directory offset of the next entry */
+			d_reclen: u16,                     /* length of this record */
+			d_type:   D_Type,                  /* file type  */
+			d_name:   [256]c.char `fmt:"s,0"`, /* [PSX] entry name */
+		}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 9 - 0
core/sys/posix/dlfcn.odin

@@ -111,6 +111,15 @@ when ODIN_OS == .Darwin {
 
 
 	RTLD_LOCAL   :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))}
 	RTLD_LOCAL   :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))}
 
 
+} else when ODIN_OS == .Linux {
+
+	RTLD_LAZY    :: 0x001
+	RTLD_NOW     :: 0x002
+	RTLD_GLOBAL  :: 0x100
+
+	_RTLD_LOCAL  :: 0
+	RTLD_LOCAL   :: RTLD_Flags{}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 95 - 6
core/sys/posix/errno.odin

@@ -141,7 +141,7 @@ when ODIN_OS == .Darwin {
 	EMLINK          :: 31
 	EMLINK          :: 31
 	EPIPE           :: 32
 	EPIPE           :: 32
 	EAGAIN          :: 35
 	EAGAIN          :: 35
-	EWOULDBLOCK     :: 35
+	EWOULDBLOCK     :: EAGAIN
 	EINPROGRESS     :: 36
 	EINPROGRESS     :: 36
 	EALREADY        :: 37
 	EALREADY        :: 37
 	ENOTSOCK        :: 38
 	ENOTSOCK        :: 38
@@ -151,7 +151,7 @@ when ODIN_OS == .Darwin {
 	ENOPROTOOPT     :: 42
 	ENOPROTOOPT     :: 42
 	EPROTONOSUPPORT :: 43
 	EPROTONOSUPPORT :: 43
 	ENOTSUP         :: 45
 	ENOTSUP         :: 45
-	EOPNOTSUPP      :: 45
+	EOPNOTSUPP      :: ENOTSUP
 	EAFNOSUPPORT    :: 47
 	EAFNOSUPPORT    :: 47
 	EADDRINUSE      :: 48
 	EADDRINUSE      :: 48
 	EADDRNOTAVAIL   :: 49
 	EADDRNOTAVAIL   :: 49
@@ -220,7 +220,7 @@ when ODIN_OS == .Darwin {
 	EMLINK          :: 31
 	EMLINK          :: 31
 	EPIPE           :: 32
 	EPIPE           :: 32
 	EAGAIN          :: 35
 	EAGAIN          :: 35
-	EWOULDBLOCK     :: 35
+	EWOULDBLOCK     :: EAGAIN
 	EINPROGRESS     :: 36
 	EINPROGRESS     :: 36
 	EALREADY        :: 37
 	EALREADY        :: 37
 	ENOTSOCK        :: 38
 	ENOTSOCK        :: 38
@@ -230,7 +230,7 @@ when ODIN_OS == .Darwin {
 	ENOPROTOOPT     :: 42
 	ENOPROTOOPT     :: 42
 	EPROTONOSUPPORT :: 43
 	EPROTONOSUPPORT :: 43
 	ENOTSUP         :: 45
 	ENOTSUP         :: 45
-	EOPNOTSUPP      :: 45
+	EOPNOTSUPP      :: ENOTSUP
 	EAFNOSUPPORT    :: 47
 	EAFNOSUPPORT    :: 47
 	EADDRINUSE      :: 48
 	EADDRINUSE      :: 48
 	EADDRNOTAVAIL   :: 49
 	EADDRNOTAVAIL   :: 49
@@ -301,7 +301,7 @@ when ODIN_OS == .Darwin {
 	EMLINK          :: 31
 	EMLINK          :: 31
 	EPIPE           :: 32
 	EPIPE           :: 32
 	EAGAIN          :: 35
 	EAGAIN          :: 35
-	EWOULDBLOCK     :: 35
+	EWOULDBLOCK     :: EAGAIN
 	EINPROGRESS     :: 36
 	EINPROGRESS     :: 36
 	EALREADY        :: 37
 	EALREADY        :: 37
 	ENOTSOCK        :: 38
 	ENOTSOCK        :: 38
@@ -311,7 +311,7 @@ when ODIN_OS == .Darwin {
 	ENOPROTOOPT     :: 42
 	ENOPROTOOPT     :: 42
 	EPROTONOSUPPORT :: 43
 	EPROTONOSUPPORT :: 43
 	ENOTSUP         :: 45
 	ENOTSUP         :: 45
-	EOPNOTSUPP      :: 45
+	EOPNOTSUPP      :: ENOTSUP
 	EAFNOSUPPORT    :: 47
 	EAFNOSUPPORT    :: 47
 	EADDRINUSE      :: 48
 	EADDRINUSE      :: 48
 	EADDRNOTAVAIL   :: 49
 	EADDRNOTAVAIL   :: 49
@@ -367,6 +367,95 @@ when ODIN_OS == .Darwin {
 		ETIME           :: -1
 		ETIME           :: -1
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+	EPERM           :: 1
+	ENOENT          :: 2
+	ESRCH           :: 3
+	EINTR           :: 4
+	EIO             :: 5
+	ENXIO           :: 6
+	E2BIG           :: 7
+	ENOEXEC         :: 8
+	EBADF           :: 9
+	ECHILD          :: 10
+	EAGAIN          :: 11
+	EWOULDBLOCK     :: EAGAIN
+	ENOMEM          :: 12
+	EACCES          :: 13
+	EFAULT          :: 14
+	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
+
+	EDEADLK         :: 35
+	ENAMETOOLONG    :: 36
+	ENOLCK          :: 37
+	ENOSYS          :: 38
+	ENOTEMPTY       :: 39
+	ELOOP           :: 40
+	ENOMSG          :: 42
+	EIDRM           :: 43
+
+	ENOSTR          :: 60
+	ENODATA         :: 61
+	ETIME           :: 62
+	ENOSR           :: 63
+
+	ENOLINK         :: 67
+
+	EPROTO          :: 71
+	EMULTIHOP       :: 72
+	EBADMSG         :: 74
+	EOVERFLOW       :: 75
+
+	ENOTSOCK        :: 88
+	EDESTADDRREQ    :: 89
+	EMSGSIZE        :: 90
+	EPROTOTYPE      :: 91
+	ENOPROTOOPT     :: 92
+	EPROTONOSUPPORT :: 93
+
+	EOPNOTSUPP      :: 95
+	ENOTSUP         :: EOPNOTSUPP
+	EAFNOSUPPORT    :: 97
+	EADDRINUSE      :: 98
+	EADDRNOTAVAIL   :: 99
+	ENETDOWN        :: 100
+	ENETUNREACH     :: 101
+	ENETRESET       :: 102
+	ECONNABORTED    :: 103
+	ECONNRESET      :: 104
+	ENOBUFS         :: 105
+	EISCONN         :: 106
+	ENOTCONN        :: 107
+
+	ETIMEDOUT       :: 110
+	ECONNREFUSED    :: 111
+
+	EHOSTUNREACH    :: 113
+	EALREADY        :: 114
+	EINPROGRESS     :: 115
+	ESTALE          :: 116
+
+	EDQUOT          :: 122
+	ECANCELED       :: 125
+
+	EOWNERDEAD      :: 130
+	ENOTRECOVERABLE :: 131
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 106 - 43
core/sys/posix/fcntl.odin

@@ -92,9 +92,6 @@ Lock_Type :: enum c.short {
 	WRLCK = F_WRLCK,
 	WRLCK = F_WRLCK,
 }
 }
 
 
-// Assertions made to unify this bit set.
-#assert(O_RDONLY == 0)
-
 O_Flag_Bits :: enum c.int {
 O_Flag_Bits :: enum c.int {
 	// Sets FD_CLOEXEC on the file descriptor.
 	// Sets FD_CLOEXEC on the file descriptor.
 	CLOEXEC   = log2(O_CLOEXEC),
 	CLOEXEC   = log2(O_CLOEXEC),
@@ -107,11 +104,11 @@ O_Flag_Bits :: enum c.int {
 	// If terminal device, do not make it the controlling terminal for the process.
 	// If terminal device, do not make it the controlling terminal for the process.
 	NOCTTY    = log2(O_NOCTTY),
 	NOCTTY    = log2(O_NOCTTY),
 	// Don't follow symbolic links, fail with errno ELOOP.
 	// Don't follow symbolic links, fail with errno ELOOP.
-	NOFOLLOW  = log2(O_NOFOLOW),
+	NOFOLLOW  = log2(O_NOFOLLOW),
 	// If exists and regular, truncate the length to 0.
 	// If exists and regular, truncate the length to 0.
 	TRUNC     = log2(O_TRUNC),
 	TRUNC     = log2(O_TRUNC),
 
 
- 	// NOTE: use with `posix.O_TTY_INIT + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
+	// NOTE: use with `posix.O_TTY_INIT + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
 	// this bit set enum because it is 0 on some platforms and a value on others.
 	// this bit set enum because it is 0 on some platforms and a value on others.
 	// TTY_INIT = O_TTY_INIT,
 	// TTY_INIT = O_TTY_INIT,
 
 
@@ -123,7 +120,8 @@ O_Flag_Bits :: enum c.int {
 	NONBLOCK  = log2(O_NONBLOCK),
 	NONBLOCK  = log2(O_NONBLOCK),
 	// Write I/O shall complete as defined by synchronized I/O file integrity completion.
 	// Write I/O shall complete as defined by synchronized I/O file integrity completion.
 	SYNC      = log2(O_SYNC),
 	SYNC      = log2(O_SYNC),
- 	// NOTE: use with `posix.O_RSYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
+
+	// NOTE: use with `posix.O_RSYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
 	// this bit set enum because it is 0 on some platforms and a value on others.
 	// this bit set enum because it is 0 on some platforms and a value on others.
 	// RSYNC = O_RSYNC,
 	// RSYNC = O_RSYNC,
 
 
@@ -135,11 +133,10 @@ O_Flag_Bits :: enum c.int {
 	WRONLY    = log2(O_WRONLY),
 	WRONLY    = log2(O_WRONLY),
 	// Reading only.
 	// Reading only.
 	// RDONLY = 0, // Default
 	// RDONLY = 0, // Default
-
 }
 }
+
 O_Flags :: bit_set[O_Flag_Bits; c.int]
 O_Flags :: bit_set[O_Flag_Bits; c.int]
 
 
-// A mask of all the access mode bits.
 O_ACCMODE :: O_Flags{ .EXEC, .RDWR, .WRONLY }
 O_ACCMODE :: O_Flags{ .EXEC, .RDWR, .WRONLY }
 
 
 AT_Flag_Bits :: enum c.int {
 AT_Flag_Bits :: enum c.int {
@@ -152,8 +149,8 @@ AT_Flags :: bit_set[AT_Flag_Bits; c.int]
 
 
 when ODIN_OS == .Darwin {
 when ODIN_OS == .Darwin {
 
 
-	off_t  :: distinct c.int64_t
-	pid_t  :: distinct c.int32_t
+	off_t :: distinct c.int64_t
+	pid_t :: distinct c.int32_t
 
 
 	F_DUPFD         :: 0
 	F_DUPFD         :: 0
 	F_DUPFD_CLOEXEC :: 67
 	F_DUPFD_CLOEXEC :: 67
@@ -178,7 +175,7 @@ when ODIN_OS == .Darwin {
 	O_DIRECTORY :: 0x00100000
 	O_DIRECTORY :: 0x00100000
 	O_EXCL      :: 0x00000800
 	O_EXCL      :: 0x00000800
 	O_NOCTTY    :: 0x00020000
 	O_NOCTTY    :: 0x00020000
-	O_NOFOLOW   :: 0x00000100
+	O_NOFOLLOW  :: 0x00000100
 	O_TRUNC     :: 0x00000400
 	O_TRUNC     :: 0x00000400
 
 
 	_O_TTY_INIT :: 0
 	_O_TTY_INIT :: 0
@@ -189,16 +186,16 @@ when ODIN_OS == .Darwin {
 	O_NONBLOCK :: 0x00000004
 	O_NONBLOCK :: 0x00000004
 	O_SYNC     :: 0x0080
 	O_SYNC     :: 0x0080
 
 
-	_O_RSYNC   :: 0
-	O_RSYNC    :: O_Flags{}
+	_O_RSYNC :: 0
+	O_RSYNC  :: O_Flags{}
 
 
-	O_EXEC    :: 0x40000000
-	O_RDONLY  :: 0
-	O_RDWR    :: 0x0002
-	O_WRONLY  :: 0x0001
+	O_EXEC   :: 0x40000000
+	O_RDONLY :: 0
+	O_RDWR   :: 0x0002
+	O_WRONLY :: 0x0001
 
 
 	_O_SEARCH :: O_EXEC | O_DIRECTORY
 	_O_SEARCH :: O_EXEC | O_DIRECTORY
-	O_SEARCH  :: O_Flags{ .EXEC, .DIRECTORY }
+	O_SEARCH  :: O_Flags{.EXEC, .DIRECTORY}
 
 
 	AT_FDCWD: FD: -2
 	AT_FDCWD: FD: -2
 
 
@@ -217,8 +214,8 @@ when ODIN_OS == .Darwin {
 
 
 } else when ODIN_OS == .FreeBSD {
 } else when ODIN_OS == .FreeBSD {
 
 
-	off_t  :: distinct c.int64_t
-	pid_t  :: distinct c.int32_t
+	off_t :: distinct c.int64_t
+	pid_t :: distinct c.int32_t
 
 
 	F_DUPFD         :: 0
 	F_DUPFD         :: 0
 	F_DUPFD_CLOEXEC :: 17
 	F_DUPFD_CLOEXEC :: 17
@@ -243,7 +240,7 @@ when ODIN_OS == .Darwin {
 	O_DIRECTORY :: 0x00020000
 	O_DIRECTORY :: 0x00020000
 	O_EXCL      :: 0x0800
 	O_EXCL      :: 0x0800
 	O_NOCTTY    :: 0x8000
 	O_NOCTTY    :: 0x8000
-	O_NOFOLOW   :: 0x0100
+	O_NOFOLLOW  :: 0x0100
 	O_TRUNC     :: 0x0400
 	O_TRUNC     :: 0x0400
 
 
 	_O_TTY_INIT :: 0x00080000
 	_O_TTY_INIT :: 0x00080000
@@ -256,10 +253,10 @@ when ODIN_OS == .Darwin {
 	_O_RSYNC   :: 0
 	_O_RSYNC   :: 0
 	O_RSYNC    :: O_Flags{} // NOTE: not defined in headers
 	O_RSYNC    :: O_Flags{} // NOTE: not defined in headers
 
 
-	O_EXEC    :: 0x00040000
-	O_RDONLY  :: 0
-	O_RDWR    :: 0x0002
-	O_WRONLY  :: 0x0001
+	O_EXEC   :: 0x00040000
+	O_RDONLY :: 0
+	O_RDWR   :: 0x0002
+	O_WRONLY :: 0x0001
 
 
 	_O_SEARCH :: O_EXEC
 	_O_SEARCH :: O_EXEC
 	O_SEARCH  :: O_Flags{ .EXEC }
 	O_SEARCH  :: O_Flags{ .EXEC }
@@ -282,8 +279,8 @@ when ODIN_OS == .Darwin {
 
 
 } else when ODIN_OS == .NetBSD {
 } else when ODIN_OS == .NetBSD {
 
 
-	off_t  :: distinct c.int64_t
-	pid_t  :: distinct c.int32_t
+	off_t :: distinct c.int64_t
+	pid_t :: distinct c.int32_t
 
 
 	F_DUPFD         :: 0
 	F_DUPFD         :: 0
 	F_DUPFD_CLOEXEC :: 12
 	F_DUPFD_CLOEXEC :: 12
@@ -308,7 +305,7 @@ when ODIN_OS == .Darwin {
 	O_DIRECTORY :: 0x0020000
 	O_DIRECTORY :: 0x0020000
 	O_EXCL      :: 0x0800
 	O_EXCL      :: 0x0800
 	O_NOCTTY    :: 0x8000
 	O_NOCTTY    :: 0x8000
-	O_NOFOLOW   :: 0x0100
+	O_NOFOLLOW  :: 0x0100
 	O_TRUNC     :: 0x0400
 	O_TRUNC     :: 0x0400
 
 
 	_O_TTY_INIT :: 0
 	_O_TTY_INIT :: 0
@@ -319,14 +316,14 @@ when ODIN_OS == .Darwin {
 	O_NONBLOCK :: 0x0004
 	O_NONBLOCK :: 0x0004
 	O_SYNC     :: 0x0080
 	O_SYNC     :: 0x0080
 
 
-	_O_RSYNC   :: 0x0002
-	O_RSYNC    :: O_Flags{O_Flag_Bits(log2(_O_RSYNC))}
+	_O_RSYNC :: 0x0002
+	O_RSYNC  :: O_Flags{O_Flag_Bits(log2(_O_RSYNC))}
 
 
 
 
-	O_EXEC    :: 0x04000000
-	O_RDONLY  :: 0
-	O_RDWR    :: 0x0002
-	O_WRONLY  :: 0x0001
+	O_EXEC   :: 0x04000000
+	O_RDONLY :: 0
+	O_RDWR   :: 0x0002
+	O_WRONLY :: 0x0001
 
 
 	_O_SEARCH :: 0x00800000
 	_O_SEARCH :: 0x00800000
 	O_SEARCH  :: O_Flags{O_Flag_Bits(log2(_O_SEARCH))}
 	O_SEARCH  :: O_Flags{O_Flag_Bits(log2(_O_SEARCH))}
@@ -347,8 +344,8 @@ when ODIN_OS == .Darwin {
 	}
 	}
 } else when ODIN_OS == .OpenBSD {
 } else when ODIN_OS == .OpenBSD {
 
 
-	off_t  :: distinct c.int64_t
-	pid_t  :: distinct c.int32_t
+	off_t :: distinct c.int64_t
+	pid_t :: distinct c.int32_t
 
 
 	F_DUPFD         :: 0
 	F_DUPFD         :: 0
 	F_DUPFD_CLOEXEC :: 10
 	F_DUPFD_CLOEXEC :: 10
@@ -373,7 +370,7 @@ when ODIN_OS == .Darwin {
 	O_DIRECTORY :: 0x20000
 	O_DIRECTORY :: 0x20000
 	O_EXCL      :: 0x0800
 	O_EXCL      :: 0x0800
 	O_NOCTTY    :: 0x8000
 	O_NOCTTY    :: 0x8000
-	O_NOFOLOW   :: 0x0100
+	O_NOFOLLOW  :: 0x0100
 	O_TRUNC     :: 0x0400
 	O_TRUNC     :: 0x0400
 
 
 	_O_TTY_INIT :: 0
 	_O_TTY_INIT :: 0
@@ -384,13 +381,13 @@ when ODIN_OS == .Darwin {
 	O_NONBLOCK :: 0x0004
 	O_NONBLOCK :: 0x0004
 	O_SYNC     :: 0x0080
 	O_SYNC     :: 0x0080
 
 
-	_O_RSYNC   :: O_SYNC
-	O_RSYNC    :: O_Flags{ .SYNC }
+	_O_RSYNC :: O_SYNC
+	O_RSYNC  :: O_Flags{.SYNC}
 
 
-	O_EXEC    :: 0x04000000 // NOTE: not defined in the headers
-	O_RDONLY  :: 0
-	O_RDWR    :: 0x0002
-	O_WRONLY  :: 0x0001
+	O_EXEC   :: 0x04000000 // NOTE: not defined in the headers
+	O_RDONLY :: 0
+	O_RDWR   :: 0x0002
+	O_WRONLY :: 0x0001
 
 
 	_O_SEARCH :: 0
 	_O_SEARCH :: 0
 	O_SEARCH  :: O_Flags{} // NOTE: not defined in the headers
 	O_SEARCH  :: O_Flags{} // NOTE: not defined in the headers
@@ -410,6 +407,72 @@ when ODIN_OS == .Darwin {
 		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset */
 		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset */
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+
+	off_t :: distinct c.int64_t
+	pid_t :: distinct c.int
+
+	F_DUPFD  :: 0
+	F_GETFD  :: 1
+	F_SETFD  :: 2
+	F_GETFL  :: 3
+	F_SETFL  :: 4
+	F_GETLK  :: 5
+	F_SETLK  :: 6
+	F_SETLKW :: 7
+	F_SETOWN :: 8
+	F_GETOWN :: 9
+	F_RDLCK  :: 0
+	F_UNLCK  :: 2
+	F_WRLCK  :: 1
+
+	F_DUPFD_CLOEXEC :: 1030
+
+	FD_CLOEXEC :: 1
+
+	O_CREAT     :: 0o0_000_100
+	O_EXCL      :: 0o0_000_200
+	O_NOCTTY    :: 0o0_000_400
+	O_TRUNC     :: 0o0_001_000
+	O_DIRECTORY :: 0o0_200_000
+	O_NOFOLLOW  :: 0o0_400_000
+	O_CLOEXEC   :: 0o2_000_000
+
+	_O_TTY_INIT :: 0
+	O_TTY_INIT  :: O_Flags{}
+
+	O_APPEND   :: 0o0_002_000
+	O_NONBLOCK :: 0o0_004_000
+	O_DSYNC    :: 0o0_010_000
+	O_SYNC     :: 0o4_010_000
+
+	_O_RSYNC :: 0
+	O_RSYNC  :: O_Flags{}
+
+	O_EXEC   :: 0x04000000 // NOTE: not defined in the headers
+
+	O_RDONLY :: 0
+	O_WRONLY :: 0o1
+	O_RDWR   :: 0o2
+
+	_O_SEARCH :: 0
+	O_SEARCH  :: O_Flags{}
+
+	AT_FDCWD: FD: -100
+
+	AT_EACCESS          :: 0x200
+	AT_SYMLINK_NOFOLLOW :: 0x100
+	AT_SYMLINK_FOLLOW   :: 0x400
+	AT_REMOVEDIR        :: 0x200
+
+	flock :: struct {
+		l_start:  off_t,     /* [PSX] relative offset in bytes. */
+		l_len:    off_t,     /* [PSX] size; if 0 then until EOF. */
+		l_pid:    pid_t,     /* [PSX] process ID of the process holding the lock. */
+		l_type:   Lock_Type, /* [PSX] type of lock. */
+		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset. */
+	}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 8 - 0
core/sys/posix/fnmatch.odin

@@ -53,6 +53,14 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	FNM_PERIOD   :: 0x04
 	FNM_PERIOD   :: 0x04
 	FNM_NOESCAPE :: 0x01
 	FNM_NOESCAPE :: 0x01
 
 
+} else when ODIN_OS == .Linux {
+
+	FNM_NOMATCH  :: 1
+
+	FNM_PATHNAME :: 0x01
+	FNM_NOESCAPE :: 0x02
+	FNM_PERIOD   :: 0x04
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 31 - 2
core/sys/posix/glob.odin

@@ -112,7 +112,7 @@ when ODIN_OS == .Darwin {
 
 
 	glob_t :: struct {
 	glob_t :: struct {
 		gl_pathc:  c.size_t,                      /* [PSX] count of paths matched by pattern */
 		gl_pathc:  c.size_t,                      /* [PSX] count of paths matched by pattern */
-		gl_matchc: c.size_t,                         /* count of paths matching pattern */
+		gl_matchc: c.size_t,                      /* count of paths matching pattern */
 		gl_offs:   c.size_t,                      /* [PSX] slots to reserve at the beginning of gl_pathv */
 		gl_offs:   c.size_t,                      /* [PSX] slots to reserve at the beginning of gl_pathv */
 		gl_flags:  Glob_Flags,                    /* copy of flags parameter to glob */
 		gl_flags:  Glob_Flags,                    /* copy of flags parameter to glob */
 		gl_pathv:  [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
 		gl_pathv:  [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
@@ -144,7 +144,7 @@ when ODIN_OS == .Darwin {
 
 
 	glob_t :: struct {
 	glob_t :: struct {
 		gl_pathc:  c.size_t,                      /* [PSX] count of paths matched by pattern */
 		gl_pathc:  c.size_t,                      /* [PSX] count of paths matched by pattern */
-		gl_matchc: c.size_t,                         /* count of paths matching pattern */
+		gl_matchc: c.size_t,                      /* count of paths matching pattern */
 		gl_offs:   c.size_t,                      /* [PSX] slots to reserve at the beginning of gl_pathv */
 		gl_offs:   c.size_t,                      /* [PSX] slots to reserve at the beginning of gl_pathv */
 		gl_flags:  Glob_Flags,                    /* copy of flags parameter to glob */
 		gl_flags:  Glob_Flags,                    /* copy of flags parameter to glob */
 		gl_pathv:  [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
 		gl_pathv:  [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
@@ -174,6 +174,35 @@ when ODIN_OS == .Darwin {
 	GLOB_NOMATCH :: -3
 	GLOB_NOMATCH :: -3
 	GLOB_NOSPACE :: -1
 	GLOB_NOSPACE :: -1
 
 
+} else when ODIN_OS == .Linux {
+
+	glob_t :: struct {
+		gl_pathc:  c.size_t,                      /* [PSX] count of paths matched by pattern */
+		gl_pathv:  [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */
+		gl_offs:   c.size_t,                      /* [PSX] slots to reserve at the beginning of gl_pathv */
+		gl_flags:  Glob_Flags,                    /* copy of flags parameter to glob */
+
+		// Non-standard alternate file system access functions:
+
+		gl_closedir: proc "c" (dirp: DIR),
+		gl_readdir:  proc "c" (dirp: DIR) -> ^dirent,
+		gl_opendir:  proc "c" (path: cstring) -> DIR,
+		gl_lstat:    proc "c" (path: cstring, buf: ^stat_t) -> result,
+		gl_stat:     proc "c" (path: cstring, buf: ^stat_t) -> result,
+	}
+
+	GLOB_ERR      :: 1 << 0
+	GLOB_MARK     :: 1 << 1
+	GLOB_NOSORT   :: 1 << 2
+	GLOB_DOOFFS   :: 1 << 3
+	GLOB_NOCHECK  :: 1 << 4
+	GLOB_APPEND   :: 1 << 5
+	GLOB_NOESCAPE :: 1 << 6
+
+	GLOB_NOSPACE :: 1
+	GLOB_ABORTED :: 2
+	GLOB_NOMATCH :: 3
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 1
core/sys/posix/grp.odin

@@ -114,7 +114,7 @@ foreign lib {
 	getgrnam_r :: proc(name: cstring, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno ---
 	getgrnam_r :: proc(name: cstring, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno ---
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	gid_t :: distinct c.uint32_t
 	gid_t :: distinct c.uint32_t
 
 

+ 86 - 2
core/sys/posix/langinfo.odin

@@ -238,7 +238,7 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
 	ABDAY_4 :: 16
 	ABDAY_4 :: 16
 	ABDAY_5 :: 17
 	ABDAY_5 :: 17
 	ABDAY_6 :: 18
 	ABDAY_6 :: 18
-	ABDAY_7 :: 19
+	ABDAY_7 :: 19	
 
 
 	MON_1  :: 20
 	MON_1  :: 20
 	MON_2  :: 21
 	MON_2  :: 21
@@ -278,7 +278,91 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
 	YESEXPR :: 47
 	YESEXPR :: 47
 	NOEXPR  :: 49
 	NOEXPR  :: 49
 
 
-	CRNCYSTR :: 50
+	CRNCYSTR :: 50	
+
+} else when ODIN_OS == .Linux {
+
+	// NOTE: declared with `_t` so we can enumerate the real `nl_info`.
+	nl_item_t :: distinct c.int
+
+	// NOTE: All these values are set in an enum on the Linux implementation.
+	// Some depend on locale.h contants (bits/locale.h to be precise).
+
+	// NOTE: ABDAY_1 is set to LC_TIME << 16 (LC_TIME is 2) on the enum group of
+	// the Linux implementation.
+	ABDAY_1 :: 0x20_000
+	ABDAY_2 :: 0x20_001
+	ABDAY_3 :: 0x20_002
+	ABDAY_4 :: 0x20_003
+	ABDAY_5 :: 0x20_004
+	ABDAY_6 :: 0x20_005
+	ABDAY_7 :: 0x20_006
+
+	DAY_1 :: 0x20_007
+	DAY_2 :: 0x20_008
+	DAY_3 :: 0x20_009
+	DAY_4 :: 0x20_00A
+	DAY_5 :: 0x20_00B
+	DAY_6 :: 0x20_00C
+	DAY_7 :: 0x20_00D
+
+	ABMON_1  :: 0x20_00E
+	ABMON_2  :: 0x20_010
+	ABMON_3  :: 0x20_011
+	ABMON_4  :: 0x20_012
+	ABMON_5  :: 0x20_013
+	ABMON_6  :: 0x20_014
+	ABMON_7  :: 0x20_015
+	ABMON_8  :: 0x20_016
+	ABMON_9  :: 0x20_017
+	ABMON_10 :: 0x20_018
+	ABMON_11 :: 0x20_019
+	ABMON_12 :: 0x20_01A
+
+	MON_1  :: 0x20_01B
+	MON_2  :: 0x20_01C
+	MON_3  :: 0x20_01D
+	MON_4  :: 0x20_01E
+	MON_5  :: 0x20_020
+	MON_6  :: 0x20_021
+	MON_7  :: 0x20_022
+	MON_8  :: 0x20_023
+	MON_9  :: 0x20_024
+	MON_10 :: 0x20_025
+	MON_11 :: 0x20_026
+	MON_12 :: 0x20_027
+
+	AM_STR :: 0x20_028
+	PM_STR :: 0x20_029
+
+	D_T_FMT    :: 0x20_02A
+	D_FMT      :: 0x20_02B
+	T_FMT      :: 0x20_02C
+	T_FMT_AMPM :: 0x20_02D
+
+	ERA         :: 0x20_02E
+	ERA_D_FMT   :: 0x20_030
+	ALT_DIGITS  :: 0x20_031
+	ERA_D_T_FMT :: 0x20_032
+	ERA_T_FMT   :: 0x20_033
+
+	// NOTE: CODESET is the 16th member of the enum group starting with value
+	// LC_CTYPE << 16, LC_CTYPE is 0.
+	CODESET :: 0x0F
+
+	// NOTE: CRNCYSTR is the 16th member of the enum group starting with value
+	// LC_MONETARY << 16, LC_MONETARY is 4.
+	CRNCYSTR :: 0x40_00F
+
+	// NOTE: RADIXCHAR is the 1st member of the enum group starting with value
+	// LC_NUMERIC << 16, LC_NUMERIC is 1.
+	RADIXCHAR :: 0x10_000
+	THOUSEP   :: 0x10_001
+
+	// NOTE: YESEXPR is the 1st member of the enum group starting with value
+	// LC_MESSAGES << 16, LC_MESSAGES is 5.
+	YESEXPR :: 0x50_000
+	NOEXPR  :: 0x50_001
 
 
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")

+ 95 - 0
core/sys/posix/limits.odin

@@ -454,6 +454,101 @@ when ODIN_OS == .Darwin {
 	NL_TEXTMAX :: 255
 	NL_TEXTMAX :: 255
 	NZERO      :: 20
 	NZERO      :: 20
 
 
+} else when ODIN_OS == .Linux {
+
+	// A definition of one of the symbolic constants in the following list shall be omitted from
+	// <limits.h> on specific implementations where the corresponding value is equal to or greater
+	// than the stated minimum, but is unspecified.
+	//
+	// This indetermination might depend on the amount of available memory space on a specific
+	// instance of a specific implementation. The actual value supported by a specific instance shall
+	// be provided by the sysconf() function.
+
+	// AIO_LISTIO_MAX             :: sysconf(._AIO_LISTIO_MAX)
+	// AIO_MAX                    :: sysconf(._AIO_MAX)
+	// AIO_PRIO_DELTA_MAX         :: sysconf(._AIO_PRIO_DELTA_MAX)
+	ARG_MAX                       :: 131_072
+	// ATEXIT_MAX                 :: sysconf(._ATEXIT_MAX)
+	// CHILD_MAX                  :: sysconf(._POSIX_ARG_MAX)
+	// DELAYTIMER_MAX             :: sysconf(._DELAYTIMER_MAX)
+	// HOST_NAME_MAX              :: sysconf(._HOST_NAME_MAX)
+	// IOV_MAX                    :: sysconf(._XOPEN_IOV_MAX)
+	// LOGIN_NAME_MAX             :: sysconf(._LOGIN_NAME_MAX)
+	// MQ_OPEN_MAX                :: sysconf(._MQ_OPEN_MAX)
+	// MQ_PRIO_MAX                :: sysconf(._MQ_PRIO_MAX)
+	// PAGESIZE                   :: PAGE_SIZE
+	// PAGE_SIZE                  :: sysconf(._PAGE_SIZE)
+	PTHREAD_DESTRUCTOR_ITERATIONS :: 4
+	// PTHREAD_KEYS_MAX           :: sysconf(._PTHREAD_KEYS_MAX)
+	// PTHREAD_STACK_MIN          :: sysconf(._PTHREAD_STACK_MIN)
+	// RTSIG_MAX                  :: sysconf(._RTSIG_MAX)
+	// SEM_NSEMS_MAX              :: sysconf(._SEM_NSEMS_MAX)
+	// SEM_VALUE_MAX              :: sysconf(._SEM_VALUE_MAX)
+	// SIGQUEUE_MAX               :: sysconf(._SIGQUEUE_MAX)
+	// SS_REPL_MAX                :: sysconf(._SS_REPL_MAX)
+	// STREAM_MAX                 :: sysconf(._STREAM_MAX)
+	// SYMLOOP_MAX                :: sysconf(._SYSLOOP_MAX)
+	// TIMER_MAX                  :: sysconf(._TIMER_MAX)
+	// TRACE_EVENT_NAME_MAX       :: sysconf(._TRACE_EVENT_NAME_MAX)
+	// TRACE_NAME_MAX             :: sysconf(._TRACE_NAME_MAX)
+	// TRACE_SYS_MAX              :: sysconf(._TRACE_SYS_MAX)
+	// TRACE_USER_EVENT_MAX       :: sysconf(._TRACE_USER_EVENT_MAX)
+	// TTY_NAME_MAX               :: sysconf(._TTY_NAME_MAX)
+	// TZNAME_MAX                 :: sysconf(._TZNAME_MAX)
+
+	// The values in the following list may be constants within an implementation or may vary from
+	// one pathname to another.
+	// For example, file systems or directories may have different characteristics.
+	//
+	// A definition of one of the symbolic constants in the following list shall be omitted from the 
+	// <limits.h> header on specific implementations where the corresponding value is equal to or
+	// greater than the stated minimum, but where the value can vary depending on the file to which
+	// it is applied.
+	// The actual value supported for a specific pathname shall be provided by the pathconf() function.
+
+	// FILESIZEBITS             :: pathconf(".", ._FILESIZEBITS)
+	LINK_MAX                    :: 127
+	MAX_CANON                   :: 255
+	MAX_INPUT                   :: 255
+	NAME_MAX                    :: 255
+	PATH_MAX                    :: 4096
+	PIPE_BUF                    :: 4096
+	// POSIX_ALLOC_SIZE_MIN     :: sysconf(._POSIX_ALLOC_SIZE_MIN)
+	// POSIX_REC_INCR_XFER_SIZE :: sysconf(._POSIX_REC_INCR_XFER_SIZE)
+	// POSIX_REC_MAX_XFER_SIZE  :: sysconf(._POSIX_REC_MAX_XFER_SIZE)
+	// POSIX_REC_MIN_XFER_SIZE  :: sysconf(._POSIX_REC_MIN_XFER_SIZE)
+	// POSIX_REC_XFER_ALIGN     :: sysconf(._POSIX_REC_XFER_ALIGN)
+	// SYMLINK_MAX              :: pathconf(".", ._SYMLINK_MAX)
+
+
+	// The magnitude limitations in the following list shall be fixed by specific implementations.
+	// An application should assume that the value of the symbolic constant defined by <limits.h>
+	// in a specific implementation is the minimum that pertains whenever the application is run
+	// under that implementation.
+	// A specific instance of a specific implementation may increase the value relative to that
+	// supplied by <limits.h> for that implementation.
+	// The actual value supported by a specific instance shall be provided by the sysconf() function.
+
+	BC_BASE_MAX         :: 99
+	BC_DIM_MAX          :: 2048
+	BC_SCALE_MAX        :: 99
+	BC_STRING_MAX       :: 1000
+	CHARCLASS_NAME_MAX  :: 14
+	COLL_WEIGHTS_MAX    :: 2
+	EXPR_NEST_MAX       :: 32
+	// LINE_MAX         :: sysconf(._LINE_MAX)
+	// NGROUPS_MAX      :: sysconf(._NGROUPS_MAX)
+	RE_DUP_MAX          :: 255
+
+	// Other limits.
+
+	NL_ARGMAX  :: 9
+	NL_LANGMAX :: 32 // 14 on glibc, 32 on musl
+	NL_MSGMAX  :: 32_767
+	NL_SETMAX  :: 255
+	NL_TEXTMAX :: 2048 // 255 on glibc, 2048 on musl
+	NZERO      :: 20
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 38 - 0
core/sys/posix/locale.odin

@@ -88,6 +88,44 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD  || ODIN_OS
 	LC_NUMERIC  :: 4
 	LC_NUMERIC  :: 4
 	LC_TIME     :: 5
 	LC_TIME     :: 5
 
 
+} else when ODIN_OS == .Linux {
+
+	// NOTE: All of these fields are standard ([PSX]).
+	lconv :: struct {
+		decimal_point:      cstring,
+		thousand_sep:       cstring,
+		grouping:           cstring,
+		int_curr_symbol:    cstring,
+		currency_symbol:    cstring,
+		mon_decimal_points: cstring,
+		mon_thousands_sep:  cstring,
+		mon_grouping:       cstring,
+		positive_sign:      cstring,
+		negative_sign:      cstring,
+		int_frac_digits:    c.char,
+		frac_digits:        c.char,
+		p_cs_precedes:      c.char,
+		p_sep_by_space:     c.char,
+		n_cs_precedes:      c.char,
+		n_sep_by_space:     c.char,
+		p_sign_posn:        c.char,
+		n_sign_posn:        c.char,
+		int_p_cs_precedes:  c.char,
+		int_n_cs_precedes:  c.char,
+		int_p_sep_by_space: c.char,
+		int_n_sep_by_space: c.char,
+		int_p_sign_posn:    c.char,
+		int_n_sign_posn:    c.char,
+	}
+
+	LC_CTYPE    :: 0
+	LC_NUMERIC  :: 1
+	LC_TIME     :: 2
+	LC_COLLATE  :: 3
+	LC_MONETARY :: 4
+	LC_MESSAGES :: 5
+	LC_ALL      :: 6
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 1
core/sys/posix/net_if.odin

@@ -44,7 +44,7 @@ foreign lib {
 	if_freenameindex :: proc(ptr: ^if_nameindex_t) ---
 	if_freenameindex :: proc(ptr: ^if_nameindex_t) ---
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	// NOTE: `_t` suffix added due to name conflict.
 	// NOTE: `_t` suffix added due to name conflict.
 
 

+ 36 - 2
core/sys/posix/netdb.odin

@@ -318,7 +318,7 @@ Info_Errno :: enum c.int {
 	OVERFLOW = EAI_OVERFLOW,
 	OVERFLOW = EAI_OVERFLOW,
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	hostent :: struct {
 	hostent :: struct {
 		h_name:      cstring,                /* [PSX] official name of host */
 		h_name:      cstring,                /* [PSX] official name of host */
@@ -412,9 +412,28 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		NI_NUMERICSERV  :: 2
 		NI_NUMERICSERV  :: 2
 		NI_NUMERICSCOPE :: 32
 		NI_NUMERICSCOPE :: 32
 		NI_DGRAM        :: 16
 		NI_DGRAM        :: 16
+
+	} else when ODIN_OS == .Linux {
+
+		AI_PASSIVE     :: 0x001
+		AI_CANONNAME   :: 0x002
+		AI_NUMERICHOST :: 0x004
+		AI_NUMERICSERV :: 0x400
+		AI_V4MAPPED    :: 0x008
+		AI_ALL         :: 0x010
+		AI_ADDRCONFIG  :: 0x020
+
+		NI_NOFQDN       :: 4
+		NI_NUMERICHOST  :: 1
+		NI_NAMEREQD     :: 8
+		NI_NUMERICSERV  :: 2
+		NI_NUMERICSCOPE :: 0x100
+		NI_DGRAM        :: 16
+
 	}
 	}
 
 
 	when ODIN_OS == .OpenBSD {
 	when ODIN_OS == .OpenBSD {
+
 		EAI_AGAIN    :: -3
 		EAI_AGAIN    :: -3
 		EAI_BADFLAGS :: -1
 		EAI_BADFLAGS :: -1
 		EAI_FAIL     :: -4
 		EAI_FAIL     :: -4
@@ -425,7 +444,22 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		EAI_SOCKTYPE :: -7
 		EAI_SOCKTYPE :: -7
 		EAI_SYSTEM   :: -11
 		EAI_SYSTEM   :: -11
 		EAI_OVERFLOW :: -14
 		EAI_OVERFLOW :: -14
+
+	} else when ODIN_OS == .Linux {
+
+		EAI_AGAIN    :: -3
+		EAI_BADFLAGS :: -1
+		EAI_FAIL     :: -4
+		EAI_FAMILY   :: -6
+		EAI_MEMORY   :: -10
+		EAI_NONAME   :: -2
+		EAI_SERVICE  :: -8
+		EAI_SOCKTYPE :: -7
+		EAI_SYSTEM   :: -11
+		EAI_OVERFLOW :: -12
+
 	} else {
 	} else {
+
 		EAI_AGAIN    :: 2
 		EAI_AGAIN    :: 2
 		EAI_BADFLAGS :: 3
 		EAI_BADFLAGS :: 3
 		EAI_FAIL     :: 4
 		EAI_FAIL     :: 4
@@ -438,6 +472,6 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		EAI_OVERFLOW :: 14
 		EAI_OVERFLOW :: 14
 	}
 	}
 
 
-}else {
+} else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 57 - 28
core/sys/posix/netinet_in.odin

@@ -30,7 +30,7 @@ Protocol :: enum c.int {
 	UDP  = IPPROTO_UDP,
 	UDP  = IPPROTO_UDP,
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	in_addr :: struct {
 	in_addr :: struct {
 		s_addr: in_addr_t, /* [PSX] big endian address */
 		s_addr: in_addr_t, /* [PSX] big endian address */
@@ -44,26 +44,63 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		},
 		},
 	}
 	}
 
 
-	sockaddr_in :: struct {
-		sin_len:    c.uint8_t,
-		sin_family: sa_family_t, /* [PSX] AF_INET (but a smaller size) */
-		sin_port:   in_port_t,   /* [PSX] port number */
-		sin_addr:   in_addr,     /* [PSX] IP address */
-		sin_zero:   [8]c.char,
-	}
-
-	sockaddr_in6 :: struct {
-		sin6_len:      c.uint8_t,
-		sin6_family:   sa_family_t, /* [PSX] AF_INET6 (but a smaller size) */
-		sin6_port:     in_port_t,   /* [PSX] port number */
-		sin6_flowinfo: c.uint32_t,  /* [PSX] IPv6 traffic class and flow information */
-		sin6_addr:     in6_addr,    /* [PSX] IPv6 address */
-		sin6_scope_id: c.uint32_t,  /* [PSX] set of interfaces for a scope */
-	}
+	when ODIN_OS == .Linux {
+
+		sockaddr_in :: struct {
+			sin_family: sa_family_t, /* [PSX] AF_INET (but a smaller size) */
+			sin_port:   in_port_t,   /* [PSX] port number */
+			sin_addr:   in_addr,     /* [PSX] IP address */
+			sin_zero:   [8]c.char,
+		}
+
+		sockaddr_in6 :: struct {
+			sin6_family:   sa_family_t, /* [PSX] AF_INET6 (but a smaller size) */
+			sin6_port:     in_port_t,   /* [PSX] port number */
+			sin6_flowinfo: u32be,       /* [PSX] IPv6 traffic class and flow information */
+			sin6_addr:     in6_addr,    /* [PSX] IPv6 address */
+			sin6_scope_id: c.uint32_t,  /* [PSX] set of interfaces for a scope */
+		}
+
+		IPV6_MULTICAST_IF   :: 17
+		IPV6_UNICAST_HOPS   :: 16
+		IPV6_MULTICAST_HOPS :: 18
+		IPV6_MULTICAST_LOOP :: 19
+		IPV6_JOIN_GROUP     :: 20
+		IPV6_LEAVE_GROUP    :: 21
+		IPV6_V6ONLY         :: 26
+
+	} else {
+
+		sockaddr_in :: struct {
+			sin_len:    c.uint8_t,
+			sin_family: sa_family_t, /* [PSX] AF_INET (but a smaller size) */
+			sin_port:   in_port_t,   /* [PSX] port number */
+			sin_addr:   in_addr,     /* [PSX] IP address */
+			sin_zero:   [8]c.char,
+		}
+
+		sockaddr_in6 :: struct {
+			sin6_len:      c.uint8_t,
+			sin6_family:   sa_family_t, /* [PSX] AF_INET6 (but a smaller size) */
+			sin6_port:     in_port_t,   /* [PSX] port number */
+			sin6_flowinfo: c.uint32_t,  /* [PSX] IPv6 traffic class and flow information */
+			sin6_addr:     in6_addr,    /* [PSX] IPv6 address */
+			sin6_scope_id: c.uint32_t,  /* [PSX] set of interfaces for a scope */
+		}
+
+		ipv6_mreq :: struct {
+			ipv6mr_multiaddr: in6_addr, /* [PSX] IPv6 multicast address */
+			ipv6mr_interface: c.uint,   /* [PSX] interface index */
+		}
+
+		IPV6_JOIN_GROUP     :: 12
+		IPV6_LEAVE_GROUP    :: 13
+		IPV6_MULTICAST_HOPS :: 10
+		IPV6_MULTICAST_IF   :: 9
+		IPV6_MULTICAST_LOOP :: 11
+		IPV6_UNICAST_HOPS   :: 4
+		IPV6_V6ONLY         :: 27
 
 
-	ipv6_mreq :: struct {
-		ipv6mr_multiaddr: in6_addr, /* [PSX] IPv6 multicast address */
-		ipv6mr_interface: c.uint,   /* [PSX] interface index */
 	}
 	}
 
 
 	IPPROTO_IP   :: 0
 	IPPROTO_IP   :: 0
@@ -76,14 +113,6 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	INADDR_ANY       :: 0x00000000
 	INADDR_ANY       :: 0x00000000
 	INADDR_BROADCAST :: 0xFFFFFFFF
 	INADDR_BROADCAST :: 0xFFFFFFFF
 
 
-	IPV6_JOIN_GROUP     :: 12
-	IPV6_LEAVE_GROUP    :: 13
-	IPV6_MULTICAST_HOPS :: 10
-	IPV6_MULTICAST_IF   :: 9
-	IPV6_MULTICAST_LOOP :: 11
-	IPV6_UNICAST_HOPS   :: 4
-	IPV6_V6ONLY         :: 27
-
 	IN6_IS_ADDR_UNSPECIFIED :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
 	IN6_IS_ADDR_UNSPECIFIED :: #force_inline proc "contextless" (a: in6_addr) -> b32 {
 		return a.s6_addr == 0
 		return a.s6_addr == 0
 	}
 	}

+ 1 - 1
core/sys/posix/netinet_tcp.odin

@@ -2,7 +2,7 @@ package posix
 
 
 // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
 // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP)
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	TCP_NODELAY :: 0x01
 	TCP_NODELAY :: 0x01
 
 

+ 20 - 0
core/sys/posix/poll.odin

@@ -72,6 +72,26 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	POLLHUP    :: 0x0010
 	POLLHUP    :: 0x0010
 	POLLNVAL   :: 0x0020
 	POLLNVAL   :: 0x0020
 
 
+} else when ODIN_OS == .Linux {
+
+	pollfd :: struct {
+		fd:      FD,         /* [PSX] the following descriptor being polled */
+		events:  Poll_Event, /* [PSX] the input event flags */
+		revents: Poll_Event, /* [PSX] the output event flags */
+	}
+
+	POLLIN     :: 0x0001
+	POLLRDNORM :: 0x0040
+	POLLRDBAND :: 0x0080
+	POLLPRI    :: 0x0002
+	POLLOUT    :: 0x0004
+	POLLWRNORM :: 0x0100
+	POLLWRBAND :: 0x0200
+
+	POLLERR    :: 0x0008
+	POLLHUP    :: 0x0010
+	POLLNVAL   :: 0x0020
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 3 - 1
core/sys/posix/posix.odin

@@ -1,5 +1,7 @@
 /*
 /*
-Bindings for most POSIX APIs.
+Raw bindings for most POSIX APIs.
+
+Targets glibc and musl compatibility.
 
 
 APIs that have been left out are due to not being useful,
 APIs that have been left out are due to not being useful,
 being fully replaced (and better) by other Odin packages,
 being fully replaced (and better) by other Odin packages,

+ 44 - 0
core/sys/posix/pthread.odin

@@ -513,6 +513,50 @@ when ODIN_OS == .Darwin {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+
+	PTHREAD_CANCEL_DEFERRED     :: 0
+	PTHREAD_CANCEL_ASYNCHRONOUS :: 1
+
+	PTHREAD_CANCEL_ENABLE       :: 0
+	PTHREAD_CANCEL_DISABLE      :: 1
+
+	PTHREAD_CANCELED :: rawptr(~uintptr(0))
+
+	PTHREAD_CREATE_JOINABLE :: 0
+	PTHREAD_CREATE_DETACHED :: 1
+
+	PTHREAD_INHERIT_SCHED  :: 0
+	PTHREAD_EXPLICIT_SCHED :: 1
+
+	PTHREAD_PRIO_NONE    :: 0
+	PTHREAD_PRIO_INHERIT :: 1
+	PTHREAD_PRIO_PROTECT :: 2
+
+	PTHREAD_PROCESS_PRIVATE :: 0
+	PTHREAD_PROCESS_SHARED  :: 1
+
+	PTHREAD_SCOPE_SYSTEM    :: 0
+	PTHREAD_SCOPE_PROCESS   :: 1
+
+	pthread_t :: distinct c.ulong
+
+	pthread_attr_t :: struct #raw_union {
+		__size: [56]c.char, // NOTE: may be smaller depending on libc or arch, but never larger.
+		__align: c.long,
+	}
+
+	pthread_key_t :: distinct c.uint
+
+	sched_param :: struct {
+		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
+
+		// NOTE: may be smaller depending on libc or arch, but never larger.
+		__reserved1: c.int,
+		__reserved2: [4]c.long,
+		__reserved3: c.int,
+	}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 1
core/sys/posix/sched.odin

@@ -94,7 +94,7 @@ when ODIN_OS == .Darwin {
 	SCHED_RR       :: 3
 	SCHED_RR       :: 3
 	SCHED_OTHER    :: 2
 	SCHED_OTHER    :: 2
 
 
-} else when ODIN_OS == .NetBSD {
+} else when ODIN_OS == .NetBSD || ODIN_OS == .Linux {
 
 
 	SCHED_OTHER    :: 0
 	SCHED_OTHER    :: 0
 	SCHED_FIFO     :: 1
 	SCHED_FIFO     :: 1

+ 174 - 15
core/sys/posix/signal.odin

@@ -480,11 +480,6 @@ when ODIN_OS == .Darwin {
 	uid_t :: distinct c.uint32_t
 	uid_t :: distinct c.uint32_t
 	sigset_t :: distinct c.uint32_t
 	sigset_t :: distinct c.uint32_t
 
 
-	// MOTE: unimplemented on darwin.
-	//
-	// SIGRTMIN :: 
-	// SIGRTMAX ::
-
 	SIGHUP    :: 1
 	SIGHUP    :: 1
 	SIGQUIT   :: 3
 	SIGQUIT   :: 3
 	SIGTRAP   :: 5
 	SIGTRAP   :: 5
@@ -625,11 +620,6 @@ when ODIN_OS == .Darwin {
 		__bits: [4]c.uint32_t,
 		__bits: [4]c.uint32_t,
 	}
 	}
 
 
-	// MOTE: unimplemented on darwin.
-	//
-	// SIGRTMIN :: 65
-	// SIGRTMAX :: 126
-
 	SIGHUP    :: 1
 	SIGHUP    :: 1
 	SIGQUIT   :: 3
 	SIGQUIT   :: 3
 	SIGTRAP   :: 5
 	SIGTRAP   :: 5
@@ -794,11 +784,6 @@ when ODIN_OS == .Darwin {
 		__bits: [4]c.uint32_t,
 		__bits: [4]c.uint32_t,
 	}
 	}
 
 
-	// MOTE: unimplemented on darwin.
-	//
-	// SIGRTMIN :: 33
-	// SIGRTMAX :: 63
-
 	SIGHUP    :: 1
 	SIGHUP    :: 1
 	SIGQUIT   :: 3
 	SIGQUIT   :: 3
 	SIGTRAP   :: 5
 	SIGTRAP   :: 5
@@ -1126,6 +1111,180 @@ when ODIN_OS == .Darwin {
 	SI_ASYNCIO :: -4 // NOTE: not implemented
 	SI_ASYNCIO :: -4 // NOTE: not implemented
 	SI_MESGQ   :: -5 // NOTE: not implemented
 	SI_MESGQ   :: -5 // NOTE: not implemented
 
 
+} else when ODIN_OS == .Linux {
+
+	// Request that signal be held
+	SIG_HOLD :: rawptr(uintptr(2))
+
+	uid_t :: distinct c.uint32_t
+	sigset_t :: struct {
+		[1024/(8 * size_of(c.ulong))]val,
+	}
+
+	SIGHUP    :: 1
+	SIGQUIT   :: 3
+	SIGTRAP   :: 5
+	SIGBUS    :: 7
+	SIGKILL   :: 9
+	SIGUSR1   :: 10
+	SIGUSR2   :: 12
+	SIGPIPE   :: 13
+	SIGALRM   :: 14
+	SIGCHLD   :: 17
+	SIGCONT   :: 18
+	SIGSTOP   :: 19
+	SIGTSTP   :: 20
+	SIGTTIN   :: 21
+	SIGTTOU   :: 22
+	SIGURG    :: 23
+	SIGXCPU   :: 24
+	SIGXFSZ   :: 25
+	SIGVTALRM :: 26
+	SIGPROF   :: 27
+	SIGPOLL   :: 29
+	SIGSYS    :: 31
+
+	// NOTE: this is actually defined as `sigaction`, but due to the function with the same name
+	// `_t` has been added.
+
+	sigaction_t :: struct {
+		using _: struct #raw_union {
+			sa_handler:   proc "c" (Signal),                     /* [PSX] signal-catching function or one of the SIG_IGN or SIG_DFL */
+			sa_sigaction: proc "c" (Signal, ^siginfo_t, rawptr), /* [PSX] signal-catching function */
+		},
+		sa_mask:     sigset_t, /* [PSX] set of signals to be blocked during execution of the signal handling function */
+		sa_flags:    SA_Flags, /* [PSX] special flags */
+		sa_restorer: proc "c" (),
+	}
+
+	SIG_BLOCK   :: 0
+	SIG_UNBLOCK :: 1
+	SIG_SETMASK :: 2
+
+	SA_NOCLDSTOP :: 1
+	SA_NOCLDWAIT :: 2
+	SA_SIGINFO   :: 4
+	SA_ONSTACK   :: 0x08000000
+	SA_RESTART   :: 0x10000000
+	SA_NODEFER   :: 0x40000000
+	SA_RESETHAND :: 0x80000000
+
+	SS_ONSTACK :: 1
+	SS_DISABLE :: 2
+
+	when ODIN_ARCH == .arm64 {
+		MINSIGSTKSZ :: 6144
+		SIGSTKSZ    :: 12288
+	} else {
+		MINSIGSTKSZ :: 2048
+		SIGSTKSZ    :: 8192
+	}
+
+	stack_t :: struct {
+		ss_sp:    rawptr,   /* [PSX] stack base or pointer */
+		ss_flags: SS_Flags, /* [PSX] flags */
+		ss_size:  c.size_t, /* [PSX] stack size */
+	}
+
+	@(private)
+	__SI_MAX_SIZE :: 128
+
+	when size_of(int) == 8 { 
+		@(private)
+		_pad0 :: struct {
+			_pad0: c.int,
+		}
+		@(private)
+		__SI_PAD_SIZE :: (__SI_MAX_SIZE / size_of(c.int)) - 4
+
+	} else {
+		@(private)
+		_pad0 :: struct {}
+		@(private)
+		__SI_PAD_SIZE :: (__SI_MAX_SIZE / size_of(c.int)) - 3
+	}
+
+	siginfo_t :: struct #align(8) {
+		si_signo:  Signal, /* [PSX] signal number */
+		si_errno:  Errno,  /* [PSX] errno value associated with this signal */
+		si_code: struct #raw_union { /* [PSX] specific more detailed codes per signal */
+			ill:  ILL_Code,
+			fpe:  FPE_Code,
+			segv: SEGV_Code,
+			bus:  BUS_Code,
+			trap: TRAP_Code,
+			chld: CLD_Code,
+			poll: POLL_Code,
+			any:  Any_Code,
+		},
+		__pad0: _pad0,
+		using _sifields: struct #raw_union {
+			_pad: [__SI_PAD_SIZE]c.int,
+
+			using _: struct {
+				si_pid: pid_t, /* [PSX] sending process ID */
+				si_uid: uid_t, /* [PSX] real user ID of sending process */
+				using _: struct #raw_union {
+					si_status: c.int,  /* [PSX] exit value or signal */
+					si_value:  sigval, /* [PSX] signal value */
+				},
+			},
+			using _: struct {
+				si_addr: rawptr, /* [PSX] address of faulting instruction */
+			},
+			using _: struct {
+				si_band: c.long, /* [PSX] band event for SIGPOLL */
+			},
+		},
+	}
+
+	ILL_ILLOPC :: 1
+	ILL_ILLOPN :: 2
+	ILL_ILLADR :: 3
+	ILL_ILLTRP :: 4
+	ILL_PRVOPC :: 5
+	ILL_PRVREG :: 6
+	ILL_COPROC :: 7
+	ILL_BADSTK :: 8
+
+	FPE_INTDIV :: 1
+	FPE_INTOVF :: 2
+	FPE_FLTDIV :: 3
+	FPE_FLTOVF :: 4
+	FPE_FLTUND :: 5
+	FPE_FLTRES :: 6
+	FPE_FLTINV :: 7
+	FPE_FLTSUB :: 8
+
+	SEGV_MAPERR :: 1
+	SEGV_ACCERR :: 2
+
+	BUS_ADRALN :: 1
+	BUS_ADRERR :: 2
+	BUS_OBJERR :: 3
+
+	TRAP_BRKPT :: 1
+	TRAP_TRACE :: 2
+
+	CLD_EXITED    :: 1
+	CLD_KILLED    :: 2
+	CLD_DUMPED    :: 3
+	CLD_TRAPPED   :: 4
+	CLD_STOPPED   :: 5
+	CLD_CONTINUED :: 6
+
+	POLL_IN  :: 1
+	POLL_OUT :: 2
+	POLL_MSG :: 3
+	POLL_ERR :: 4
+	POLL_PRI :: 5
+	POLL_HUP :: 6
+
+	SI_USER    :: 0
+	SI_QUEUE   :: -1
+	SI_TIMER   :: -2
+	SI_MESGQ   :: -3
+	SI_ASYNCIO :: -4
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 26 - 0
core/sys/posix/sys_ipc.odin

@@ -84,6 +84,32 @@ when ODIN_OS == .Darwin {
 	IPC_SET  :: 1
 	IPC_SET  :: 1
 	IPC_STAT :: 2
 	IPC_STAT :: 2
 
 
+} else when ODIN_OS == .Linux {
+
+	key_t :: distinct c.int32_t
+
+	ipc_perm :: struct {
+		__ipc_perm_key: key_t,
+		uid:            uid_t,     /* [PSX] owner's user ID */
+		gid:            gid_t,     /* [PSX] owner's group ID */
+		cuid:           uid_t,     /* [PSX] creator's user ID */
+		cgid:           gid_t,     /* [PSX] creator's group ID */
+		mode:           mode_t,    /* [PSX] read/write perms */
+		__ipc_perm_seq: c.int,
+		__pad1:         c.long,
+		__pad2:         c.long,
+	}
+
+	IPC_CREAT  :: 0o01000
+	IPC_EXCL   :: 0o02000
+	IPC_NOWAIT :: 0o04000
+
+	IPC_PRIVATE :: key_t(0)
+
+	IPC_RMID :: 0
+	IPC_SET  :: 1
+	IPC_STAT :: 2
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 3 - 2
core/sys/posix/sys_mman.odin

@@ -163,7 +163,7 @@ when ODIN_OS == .NetBSD {
 	@(private) LMSYNC :: "msync"
 	@(private) LMSYNC :: "msync"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	PROT_EXEC   :: 0x04
 	PROT_EXEC   :: 0x04
 	_PROT_NONE  :: 0x00
 	_PROT_NONE  :: 0x00
@@ -174,7 +174,7 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
 	MAP_PRIVATE :: 0x0002
 	MAP_PRIVATE :: 0x0002
 	MAP_SHARED  :: 0x0001
 	MAP_SHARED  :: 0x0001
 
 
-	when ODIN_OS == .Darwin {
+	when ODIN_OS == .Darwin || ODIN_OS == .Linux {
 		MS_INVALIDATE :: 0x0002
 		MS_INVALIDATE :: 0x0002
 		_MS_SYNC      :: 0x0010
 		_MS_SYNC      :: 0x0010
 	} else when ODIN_OS == .NetBSD {
 	} else when ODIN_OS == .NetBSD {
@@ -184,6 +184,7 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
 		MS_INVALIDATE :: 0x0004
 		MS_INVALIDATE :: 0x0004
 		_MS_SYNC      :: 0x0002
 		_MS_SYNC      :: 0x0002
 	}
 	}
+
 	MS_ASYNC :: 0x0001
 	MS_ASYNC :: 0x0001
 	MS_SYNC  :: Sync_Flags{Sync_Flags_Bits(log2(_MS_SYNC))}
 	MS_SYNC  :: Sync_Flags{Sync_Flags_Bits(log2(_MS_SYNC))}
 
 

+ 11 - 4
core/sys/posix/sys_resource.odin

@@ -95,7 +95,7 @@ when ODIN_OS == .NetBSD {
 	@(private) LGETRUSAGE :: "getrusage"
 	@(private) LGETRUSAGE :: "getrusage"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	PRIO_PROCESS :: 0
 	PRIO_PROCESS :: 0
 	PRIO_PGRP    :: 1
 	PRIO_PGRP    :: 1
@@ -103,7 +103,7 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 
 
 	rlim_t :: distinct c.uint64_t
 	rlim_t :: distinct c.uint64_t
 
 
-	RLIM_INFINITY  :: (rlim_t(1) << 63) - 1
+	RLIM_INFINITY  :: ~rlim_t(0) when ODIN_OS == .Linux else (rlim_t(1) << 63) - 1
 	RLIM_SAVED_MAX :: RLIM_INFINITY
 	RLIM_SAVED_MAX :: RLIM_INFINITY
 	RLIM_SAVED_CUR :: RLIM_INFINITY
 	RLIM_SAVED_CUR :: RLIM_INFINITY
 
 
@@ -143,9 +143,16 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	RLIMIT_CPU    :: 0
 	RLIMIT_CPU    :: 0
 	RLIMIT_DATA   :: 2
 	RLIMIT_DATA   :: 2
 	RLIMIT_FSIZE  :: 1
 	RLIMIT_FSIZE  :: 1
-	RLIMIT_NOFILE :: 8
+	RLIMIT_NOFILE :: 7 when ODIN_OS == .Linux else 8
 	RLIMIT_STACK  :: 3
 	RLIMIT_STACK  :: 3
-	RLIMIT_AS     :: 5 when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD else 10
+
+	when ODIN_OS == .Linux {
+		RLIMIT_AS :: 9
+	} else when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
+		RLIMIT_AS :: 5
+	} else {
+		RLIMIT_AS :: 10
+	}
 
 
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")

+ 1 - 1
core/sys/posix/sys_select.odin

@@ -55,7 +55,7 @@ when ODIN_OS == .NetBSD {
 	LSELECT  :: "select"
 	LSELECT  :: "select"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	suseconds_t :: distinct (c.int32_t when ODIN_OS == .Darwin || ODIN_OS == .NetBSD else c.long)
 	suseconds_t :: distinct (c.int32_t when ODIN_OS == .Darwin || ODIN_OS == .NetBSD else c.long)
 
 

+ 30 - 0
core/sys/posix/sys_sem.odin

@@ -123,6 +123,36 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		sem_flg: c.short,  /* [PSX] operation flags */
 		sem_flg: c.short,  /* [PSX] operation flags */
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+
+	SEM_UNDO :: 0x1000 // undo the operation on exit
+
+	// Commands for `semctl'.
+	GETPID  :: 11
+	GETVAL  :: 12
+	GETALL  :: 13
+	GETNCNT :: 14
+	GETZCNT :: 15
+	SETVAL  :: 16
+	SETALL  :: 17
+
+	semid_ds :: struct {
+		sem_perm:  ipc_perm,  // [PSX] operation permission structure
+		sem_otime: time_t,    // [PSX] last semop()
+		__sem_otime_high: c.ulong,
+		sem_ctime: time_t,    // [PSX] last time changed by semctl()
+		__sem_ctime_high: c.ulong,
+		sem_nsems: c.ulong, // [PSX] number of semaphores in set
+		__glibc_reserved3: c.ulong,
+		__glibc_reserved4: c.ulong,
+	}
+
+	sembuf :: struct {
+		sem_num: c.ushort, /* [PSX] semaphore number */
+		sem_op:  c.short,  /* [PSX] semaphore operation */
+		sem_flg: c.short,  /* [PSX] operation flags */
+	}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 142 - 71
core/sys/posix/sys_socket.odin

@@ -321,16 +321,23 @@ when ODIN_OS == .NetBSD {
 	@(private) LSOCKET :: "socket"
 	@(private) LSOCKET :: "socket"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	socklen_t :: distinct c.uint
 	socklen_t :: distinct c.uint
 
 
 	_sa_family_t :: distinct c.uint8_t
 	_sa_family_t :: distinct c.uint8_t
 
 
-	sockaddr :: struct {
-		sa_len:    c.uint8_t,   /* total length */
-		sa_family: sa_family_t, /* [PSX] address family */
-		sa_data:   [14]c.char,  /* [PSX] socket address */
+	when ODIN_OS == .Linux {
+		sockaddr :: struct {
+			sa_family: sa_family_t, /* [PSX] address family */
+			sa_data:   [14]c.char,  /* [PSX] socket address */
+		}
+	} else {
+		sockaddr :: struct {
+			sa_len:    c.uint8_t,   /* total length */
+			sa_family: sa_family_t, /* [PSX] address family */
+			sa_data:   [14]c.char,  /* [PSX] socket address */
+		}
 	}
 	}
 
 
 
 
@@ -339,6 +346,11 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		_SS_PAD1SIZE :: 6
 		_SS_PAD1SIZE :: 6
 		@(private)
 		@(private)
 		_SS_PAD2SIZE :: 240
 		_SS_PAD2SIZE :: 240
+	} else when ODIN_OS == .Linux {
+		@(private)
+		_SS_SIZE :: 128
+		@(private)
+		_SS_PADSIZE :: _SS_SIZE - size_of(c.uint16_t) - size_of(c.uint64_t)
 	} else {
 	} else {
 		@(private)
 		@(private)
 		_SS_MAXSIZE   :: 128
 		_SS_MAXSIZE   :: 128
@@ -350,28 +362,52 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		_SS_PAD2SIZE  :: _SS_MAXSIZE - size_of(c.uint8_t) - size_of(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE
 		_SS_PAD2SIZE  :: _SS_MAXSIZE - size_of(c.uint8_t) - size_of(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE
 	}
 	}
 
 
-	sockaddr_storage :: struct {
-		ss_len:     c.uint8_t,            /* address length */
-		ss_family:  sa_family_t,          /* [PSX] address family */
-		__ss_pad1:  [_SS_PAD1SIZE]c.char,
-		__ss_align: c.int64_t,            /* force structure storage alignment */
-		__ss_pad2:  [_SS_PAD2SIZE]c.char,
-	}
+	when ODIN_OS == .Linux {
+		sockaddr_storage :: struct {
+			ss_family:    sa_family_t,          /* [PSX] address family */
+			__ss_padding: [_SS_PADSIZE]c.char,
+			__ss_align:   c.uint64_t,           /* force structure storage alignment */
+		}
 
 
-	msghdr :: struct {
-		msg_name:       rawptr,    /* [PSX] optional address */
-		msg_namelen:    socklen_t, /* [PSX] size of address */
-		msg_iov:        [^]iovec,  /* [PSX] scatter/gather array */
-		msg_iovlen:     c.int,     /* [PSX] members in msg_iov */
-		msg_control:    rawptr,    /* [PSX] ancillary data */
-		msg_controllen: socklen_t, /* [PSX] ancillary data buffer length */
-		msg_flags:      Msg_Flags, /* [PSX] flags on received message */
-	}
+		msghdr :: struct {
+			msg_name:       rawptr,    /* [PSX] optional address */
+			msg_namelen:    socklen_t, /* [PSX] size of address */
+			msg_iov:        [^]iovec,  /* [PSX] scatter/gather array */
+			msg_iovlen:     c.size_t,  /* [PSX] members in msg_iov */
+			msg_control:    rawptr,    /* [PSX] ancillary data */
+			msg_controllen: c.size_t,  /* [PSX] ancillary data buffer length */
+			msg_flags:      Msg_Flags, /* [PSX] flags on received message */
+		}
 
 
-	cmsghdr :: struct {
-		cmsg_len:   socklen_t, /* [PSX] data byte count, including cmsghdr */
-		cmsg_level: c.int,     /* [PSX] originating protocol */
-		cmsg_type:  c.int,     /* [PSX] protocol-specific type */
+		cmsghdr :: struct {
+			cmsg_len:   c.size_t, /* [PSX] data byte count, including cmsghdr */
+			cmsg_level: c.int,     /* [PSX] originating protocol */
+			cmsg_type:  c.int,     /* [PSX] protocol-specific type */
+		}
+	} else {
+		sockaddr_storage :: struct {
+			ss_len:     c.uint8_t,            /* address length */
+			ss_family:  sa_family_t,          /* [PSX] address family */
+			__ss_pad1:  [_SS_PAD1SIZE]c.char,
+			__ss_align: c.int64_t,            /* force structure storage alignment */
+			__ss_pad2:  [_SS_PAD2SIZE]c.char,
+		}
+
+		msghdr :: struct {
+			msg_name:       rawptr,    /* [PSX] optional address */
+			msg_namelen:    socklen_t, /* [PSX] size of address */
+			msg_iov:        [^]iovec,  /* [PSX] scatter/gather array */
+			msg_iovlen:     c.int,     /* [PSX] members in msg_iov */
+			msg_control:    rawptr,    /* [PSX] ancillary data */
+			msg_controllen: socklen_t, /* [PSX] ancillary data buffer length */
+			msg_flags:      Msg_Flags, /* [PSX] flags on received message */
+		}
+
+		cmsghdr :: struct {
+			cmsg_len:   socklen_t, /* [PSX] data byte count, including cmsghdr */
+			cmsg_level: c.int,     /* [PSX] originating protocol */
+			cmsg_type:  c.int,     /* [PSX] protocol-specific type */
+		}
 	}
 	}
 
 
 	SCM_RIGHTS :: 0x01
 	SCM_RIGHTS :: 0x01
@@ -421,57 +457,90 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 	SOCK_STREAM    :: 1
 	SOCK_STREAM    :: 1
 
 
 	// Options to be accessed at socket level, not protocol level.
 	// Options to be accessed at socket level, not protocol level.
-	SOL_SOCKET :: 0xffff
-
-	SO_ACCEPTCONN :: 0x0002
-	SO_BROADCAST  :: 0x0020
-	SO_DEBUG      :: 0x0001
-	SO_DONTROUTE  :: 0x0010
-	SO_ERROR      :: 0x1007
-	SO_KEEPALIVE  :: 0x0008
-	SO_OOBINLINE  :: 0x0100
-	SO_RCVBUF     :: 0x1002
-	SO_RCVLOWAT   :: 0x1004
-	SO_REUSEADDR  :: 0x0004
-	SO_SNDBUF     :: 0x1001
-	SO_SNDLOWAT   :: 0x1003
-	SO_TYPE       :: 0x1008
-
-	when ODIN_OS == .Darwin {
-		SO_LINGER   :: 0x1080
-		SO_RCVTIMEO :: 0x1006
-		SO_SNDTIMEO :: 0x1005
-	} else when ODIN_OS == .FreeBSD {
-		SO_LINGER   :: 0x0080
-		SO_RCVTIMEO :: 0x1006
-		SO_SNDTIMEO :: 0x1005
-	} else when ODIN_OS == .NetBSD {
-		SO_LINGER   :: 0x0080
-		SO_RCVTIMEO :: 0x100c
-		SO_SNDTIMEO :: 0x100b
-	} else when ODIN_OS == .OpenBSD {
-		SO_LINGER   :: 0x0080
-		SO_RCVTIMEO :: 0x1006
-		SO_SNDTIMEO :: 0x1005
+	when ODIN_OS == .Linux {
+		SOL_SOCKET :: 1
+
+		SO_ACCEPTCONN :: 30
+		SO_BROADCAST  :: 6
+		SO_DEBUG      :: 1
+		SO_DONTROUTE  :: 5
+		SO_ERROR      :: 4
+		SO_KEEPALIVE  :: 9
+		SO_OOBINLINE  :: 10
+		SO_RCVBUF     :: 8
+		SO_RCVLOWAT   :: 18
+		SO_REUSEADDR  :: 2
+		SO_SNDBUF     :: 7
+		SO_SNDLOWAT   :: 19
+		SO_TYPE       :: 3
+		SO_LINGER     :: 13
+
+		SO_RCVTIMEO   :: 66
+		SO_SNDTIMEO   :: 67
+	} else {
+		SOL_SOCKET :: 0xffff
+
+		SO_ACCEPTCONN :: 0x0002
+		SO_BROADCAST  :: 0x0020
+		SO_DEBUG      :: 0x0001
+		SO_DONTROUTE  :: 0x0010
+		SO_ERROR      :: 0x1007
+		SO_KEEPALIVE  :: 0x0008
+		SO_OOBINLINE  :: 0x0100
+		SO_RCVBUF     :: 0x1002
+		SO_RCVLOWAT   :: 0x1004
+		SO_REUSEADDR  :: 0x0004
+		SO_SNDBUF     :: 0x1001
+		SO_SNDLOWAT   :: 0x1003
+		SO_TYPE       :: 0x1008
+
+		when ODIN_OS == .Darwin {
+			SO_LINGER   :: 0x1080
+			SO_RCVTIMEO :: 0x1006
+			SO_SNDTIMEO :: 0x1005
+		} else when ODIN_OS == .FreeBSD {
+			SO_LINGER   :: 0x0080
+			SO_RCVTIMEO :: 0x1006
+			SO_SNDTIMEO :: 0x1005
+		} else when ODIN_OS == .NetBSD {
+			SO_LINGER   :: 0x0080
+			SO_RCVTIMEO :: 0x100c
+			SO_SNDTIMEO :: 0x100b
+		} else when ODIN_OS == .OpenBSD {
+			SO_LINGER   :: 0x0080
+			SO_RCVTIMEO :: 0x1006
+			SO_SNDTIMEO :: 0x1005
+		}
 	}
 	}
 
 
 	// The maximum backlog queue length for listen().
 	// The maximum backlog queue length for listen().
 	SOMAXCONN :: 128
 	SOMAXCONN :: 128
 
 
-	MSG_CTRUNC    :: 0x20
-	MSG_DONTROUTE :: 0x4
-	MSG_EOR       :: 0x8
-	MSG_OOB       :: 0x1
-	MSG_PEEK      :: 0x2
-	MSG_TRUNC     :: 0x10
-	MSG_WAITALL   :: 0x40
-
-	when ODIN_OS == .Darwin {
-		MSG_NOSIGNAL :: 0x80000
-	} else when ODIN_OS == .FreeBSD {
-		MSG_NOSIGNAL :: 0x00020000
-	} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
-		MSG_NOSIGNAL :: 0x0400
+	when ODIN_OS == .Linux {
+		MSG_CTRUNC    :: 0x008
+		MSG_DONTROUTE :: 0x004
+		MSG_EOR       :: 0x080
+		MSG_OOB       :: 0x001
+		MSG_PEEK      :: 0x002
+		MSG_TRUNC     :: 0x020
+		MSG_WAITALL   :: 0x100
+		MSG_NOSIGNAL  :: 0x4000
+	} else {
+		MSG_CTRUNC    :: 0x20
+		MSG_DONTROUTE :: 0x4
+		MSG_EOR       :: 0x8
+		MSG_OOB       :: 0x1
+		MSG_PEEK      :: 0x2
+		MSG_TRUNC     :: 0x10
+		MSG_WAITALL   :: 0x40
+
+		when ODIN_OS == .Darwin {
+			MSG_NOSIGNAL :: 0x80000
+		} else when ODIN_OS == .FreeBSD {
+			MSG_NOSIGNAL :: 0x00020000
+		} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+			MSG_NOSIGNAL :: 0x0400
+		}
 	}
 	}
 
 
 	AF_INET   :: 2
 	AF_INET   :: 2
@@ -483,6 +552,8 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		AF_INET6 :: 28
 		AF_INET6 :: 28
 	} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
 	} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
 		AF_INET6 :: 24
 		AF_INET6 :: 24
+	} else when ODIN_OS == .Linux {
+		AF_INET6 :: 10
 	}
 	}
 
 
 	SHUT_RD   :: 0
 	SHUT_RD   :: 0

+ 1 - 1
core/sys/posix/sys_time.odin

@@ -66,7 +66,7 @@ when ODIN_OS == .NetBSD {
 	@(private) LUTIMES       :: "utimes"
 	@(private) LUTIMES       :: "utimes"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	itimerval :: struct {
 	itimerval :: struct {
 		it_interval: timeval, /* [PSX] timer interval */
 		it_interval: timeval, /* [PSX] timer interval */

+ 1 - 1
core/sys/posix/sys_times.odin

@@ -24,7 +24,7 @@ when ODIN_OS == .NetBSD {
 	@(private) LTIMES :: "times"
 	@(private) LTIMES :: "times"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	tms :: struct {
 	tms :: struct {
 		tms_utime:  clock_t, /* [PSX] user CPU time */
 		tms_utime:  clock_t, /* [PSX] user CPU time */

+ 1 - 1
core/sys/posix/sys_uio.odin

@@ -30,7 +30,7 @@ foreign libc {
 	writev :: proc(fildes: FD, iov: [^]iovec, iovcnt: c.int) -> c.ssize_t ---
 	writev :: proc(fildes: FD, iov: [^]iovec, iovcnt: c.int) -> c.ssize_t ---
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
 
 
 	iovec :: struct {
 	iovec :: struct {
 		iov_base: rawptr,   /* [PSX] base address of I/O memory region */
 		iov_base: rawptr,   /* [PSX] base address of I/O memory region */

+ 7 - 0
core/sys/posix/sys_un.odin

@@ -12,6 +12,13 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS
 		sun_path:   [104]c.char, /* [PSX] socket pathname */
 		sun_path:   [104]c.char, /* [PSX] socket pathname */
 	}
 	}
 
 
+} else when ODIN_OS == .Linux {
+
+	sockaddr_un :: struct {
+		sun_family: sa_family_t, /* [PSX] address family */
+		sun_path:   [108]c.char, /* [PSX] socket pathname */
+	}
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 9 - 4
core/sys/posix/sys_utsname.odin

@@ -37,10 +37,15 @@ foreign lib {
 	uname :: proc(uname: ^utsname) -> c.int ---
 	uname :: proc(uname: ^utsname) -> c.int ---
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
-
-	@(private)
-	_SYS_NAMELEN :: 256
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
+
+	when ODIN_OS == .Linux {
+		@(private)
+		_SYS_NAMELEN :: 65
+	} else {
+		@(private)
+		_SYS_NAMELEN :: 256
+	}
 
 
 	utsname :: struct {
 	utsname :: struct {
 		sysname:  [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */
 		sysname:  [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */

+ 1 - 1
core/sys/posix/ulimit.odin

@@ -31,7 +31,7 @@ Ulimit_Cmd :: enum c.int {
 	SETFSIZE = UL_SETFSIZE,
 	SETFSIZE = UL_SETFSIZE,
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD  || ODIN_OS == .Linux {
 
 
 	UL_GETFSIZE :: 1
 	UL_GETFSIZE :: 1
 	UL_SETFSIZE :: 2
 	UL_SETFSIZE :: 2

+ 243 - 57
core/sys/posix/unistd.odin

@@ -1181,20 +1181,20 @@ when ODIN_OS == .Darwin {
 	F_TLOCK :: 2
 	F_TLOCK :: 2
 	F_ULOCK :: 0
 	F_ULOCK :: 0
 
 
-	_CS_PATH                            :: 1
-	_CS_POSIX_V6_ILP32_OFF32_CFLAGS		:: 2
-	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS	:: 3
-	_CS_POSIX_V6_ILP32_OFF32_LIBS		:: 4
-	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS	:: 5
-	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS	:: 6
-	_CS_POSIX_V6_ILP32_OFFBIG_LIBS		:: 7
-	_CS_POSIX_V6_LP64_OFF64_CFLAGS		:: 8
-	_CS_POSIX_V6_LP64_OFF64_LDFLAGS		:: 9
-	_CS_POSIX_V6_LP64_OFF64_LIBS		:: 10
-	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS	:: 11
-	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS	:: 12
-	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS		:: 13
-	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	:: 14
+	_CS_PATH                           :: 1
+	_CS_POSIX_V6_ILP32_OFF32_CFLAGS    :: 2
+	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS   :: 3
+	_CS_POSIX_V6_ILP32_OFF32_LIBS      :: 4
+	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS   :: 5
+	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS  :: 6
+	_CS_POSIX_V6_ILP32_OFFBIG_LIBS     :: 7
+	_CS_POSIX_V6_LP64_OFF64_CFLAGS     :: 8
+	_CS_POSIX_V6_LP64_OFF64_LDFLAGS    :: 9
+	_CS_POSIX_V6_LP64_OFF64_LIBS       :: 10
+	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS   :: 11
+	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS  :: 12
+	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS     :: 13
+	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14
 
 
 	_PC_LINK_MAX           :: 1
 	_PC_LINK_MAX           :: 1
 	_PC_MAX_CANON          :: 2
 	_PC_MAX_CANON          :: 2
@@ -1362,20 +1362,20 @@ when ODIN_OS == .Darwin {
 	F_TLOCK :: 2
 	F_TLOCK :: 2
 	F_ULOCK :: 0
 	F_ULOCK :: 0
 
 
-	_CS_PATH                            :: 1
-	_CS_POSIX_V6_ILP32_OFF32_CFLAGS		:: 2
-	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS	:: 3
-	_CS_POSIX_V6_ILP32_OFF32_LIBS		:: 4
-	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS	:: 5
-	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS	:: 6
-	_CS_POSIX_V6_ILP32_OFFBIG_LIBS		:: 7
-	_CS_POSIX_V6_LP64_OFF64_CFLAGS		:: 8
-	_CS_POSIX_V6_LP64_OFF64_LDFLAGS		:: 9
-	_CS_POSIX_V6_LP64_OFF64_LIBS		:: 10
-	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS	:: 11
-	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS	:: 12
-	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS		:: 13
-	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	:: 14
+	_CS_PATH                           :: 1
+	_CS_POSIX_V6_ILP32_OFF32_CFLAGS    :: 2
+	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS   :: 3
+	_CS_POSIX_V6_ILP32_OFF32_LIBS      :: 4
+	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS   :: 5
+	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS  :: 6
+	_CS_POSIX_V6_ILP32_OFFBIG_LIBS     :: 7
+	_CS_POSIX_V6_LP64_OFF64_CFLAGS     :: 8
+	_CS_POSIX_V6_LP64_OFF64_LDFLAGS    :: 9
+	_CS_POSIX_V6_LP64_OFF64_LIBS       :: 10
+	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS   :: 11
+	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS  :: 12
+	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS     :: 13
+	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14
 
 
 	_PC_LINK_MAX           :: 1
 	_PC_LINK_MAX           :: 1
 	_PC_MAX_CANON          :: 2
 	_PC_MAX_CANON          :: 2
@@ -1543,20 +1543,20 @@ when ODIN_OS == .Darwin {
 	F_TLOCK :: 2
 	F_TLOCK :: 2
 	F_ULOCK :: 0
 	F_ULOCK :: 0
 
 
-	_CS_PATH                            :: 1
-	_CS_POSIX_V6_ILP32_OFF32_CFLAGS		:: 2
-	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS	:: 3
-	_CS_POSIX_V6_ILP32_OFF32_LIBS		:: 4
-	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS	:: 5
-	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS	:: 6
-	_CS_POSIX_V6_ILP32_OFFBIG_LIBS		:: 7
-	_CS_POSIX_V6_LP64_OFF64_CFLAGS		:: 8
-	_CS_POSIX_V6_LP64_OFF64_LDFLAGS		:: 9
-	_CS_POSIX_V6_LP64_OFF64_LIBS		:: 10
-	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS	:: 11
-	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS	:: 12
-	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS		:: 13
-	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	:: 14
+	_CS_PATH                           :: 1
+	_CS_POSIX_V6_ILP32_OFF32_CFLAGS    :: 2
+	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS   :: 3
+	_CS_POSIX_V6_ILP32_OFF32_LIBS      :: 4
+	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS   :: 5
+	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS  :: 6
+	_CS_POSIX_V6_ILP32_OFFBIG_LIBS     :: 7
+	_CS_POSIX_V6_LP64_OFF64_CFLAGS     :: 8
+	_CS_POSIX_V6_LP64_OFF64_LDFLAGS    :: 9
+	_CS_POSIX_V6_LP64_OFF64_LIBS       :: 10
+	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS   :: 11
+	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS  :: 12
+	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS     :: 13
+	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14
 
 
 	_PC_LINK_MAX           :: 1
 	_PC_LINK_MAX           :: 1
 	_PC_MAX_CANON          :: 2
 	_PC_MAX_CANON          :: 2
@@ -1655,7 +1655,6 @@ when ODIN_OS == .Darwin {
 	_SC_TTY_NAME_MAX                 :: 68
 	_SC_TTY_NAME_MAX                 :: 68
 	_SC_HOST_NAME_MAX                :: 69
 	_SC_HOST_NAME_MAX                :: 69
 
 
-	_SC_PASS_MAX                     :: 70
 	_SC_REGEXP                       :: 71
 	_SC_REGEXP                       :: 71
 	_SC_SHELL                        :: 72
 	_SC_SHELL                        :: 72
 	_SC_SYMLOOP_MAX                  :: 73
 	_SC_SYMLOOP_MAX                  :: 73
@@ -1729,20 +1728,20 @@ when ODIN_OS == .Darwin {
 	F_TLOCK :: 2
 	F_TLOCK :: 2
 	F_ULOCK :: 0
 	F_ULOCK :: 0
 
 
-	_CS_PATH                            :: 1
-	_CS_POSIX_V6_ILP32_OFF32_CFLAGS		:: 2
-	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS	:: 3
-	_CS_POSIX_V6_ILP32_OFF32_LIBS		:: 4
-	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS	:: 5
-	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS	:: 6
-	_CS_POSIX_V6_ILP32_OFFBIG_LIBS		:: 7
-	_CS_POSIX_V6_LP64_OFF64_CFLAGS		:: 8
-	_CS_POSIX_V6_LP64_OFF64_LDFLAGS		:: 9
-	_CS_POSIX_V6_LP64_OFF64_LIBS		:: 10
-	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS	:: 11
-	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS	:: 12
-	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS		:: 13
-	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	:: 14
+	_CS_PATH                           :: 1
+	_CS_POSIX_V6_ILP32_OFF32_CFLAGS    :: 2
+	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS   :: 3
+	_CS_POSIX_V6_ILP32_OFF32_LIBS      :: 4
+	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS   :: 5
+	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS  :: 6
+	_CS_POSIX_V6_ILP32_OFFBIG_LIBS     :: 7
+	_CS_POSIX_V6_LP64_OFF64_CFLAGS     :: 8
+	_CS_POSIX_V6_LP64_OFF64_LDFLAGS    :: 9
+	_CS_POSIX_V6_LP64_OFF64_LIBS       :: 10
+	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS   :: 11
+	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS  :: 12
+	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS     :: 13
+	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14
 
 
 	_PC_LINK_MAX           :: 1
 	_PC_LINK_MAX           :: 1
 	_PC_MAX_CANON          :: 2
 	_PC_MAX_CANON          :: 2
@@ -1911,6 +1910,193 @@ when ODIN_OS == .Darwin {
 
 
 	_POSIX_VDISABLE :: '\377'
 	_POSIX_VDISABLE :: '\377'
 
 
+} else when ODIN_OS == .Linux {
+
+	_F_OK :: 0
+	X_OK :: 1
+	W_OK :: 2
+	R_OK :: 4
+
+	F_LOCK  :: 1
+	F_TEST  :: 3
+	F_TLOCK :: 2
+	F_ULOCK :: 0
+
+	_CS_PATH                           :: 1
+	_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 2
+
+	_CS_POSIX_V6_ILP32_OFF32_CFLAGS   :: 1116
+	_CS_POSIX_V6_ILP32_OFF32_LDFLAGS  :: 1117
+	_CS_POSIX_V6_ILP32_OFF32_LIBS     :: 1118
+	_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS  :: 1120
+	_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS :: 1121
+	_CS_POSIX_V6_ILP32_OFFBIG_LIBS    :: 1122
+	_CS_POSIX_V6_LP64_OFF64_CFLAGS    :: 1124
+	_CS_POSIX_V6_LP64_OFF64_LDFLAGS   :: 1125
+	_CS_POSIX_V6_LP64_OFF64_LIBS      :: 1126
+	_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS  :: 1128
+	_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS :: 1129
+	_CS_POSIX_V6_LPBIG_OFFBIG_LIBS    :: 1130
+
+	_PC_LINK_MAX           :: 1
+	_PC_MAX_CANON          :: 2
+	_PC_MAX_INPUT          :: 3
+	_PC_NAME_MAX           :: 4
+	_PC_PATH_MAX           :: 5
+	_PC_PIPE_BUF           :: 6
+	_PC_CHOWN_RESTRICTED   :: 7
+	_PC_NO_TRUNC           :: 8
+	_PC_VDISABLE           :: 9
+	_PC_SYNC_IO            :: 10
+	_PC_ASYNC_IO           :: 11
+	_PC_PRIO_IO            :: 12
+	_PC_FILESIZEBITS       :: 14
+	_PC_REC_INCR_XFER_SIZE :: 15
+	_PC_REC_MAX_XFER_SIZE  :: 16
+	_PC_REC_MIN_XFER_SIZE  :: 17
+	_PC_REC_XFER_ALIGN     :: 18
+	_PC_ALLOC_SIZE_MIN     :: 19
+	_PC_SYMLINK_MAX        :: 20
+	_PC_2_SYMLINK          :: 21
+
+	_SC_ARG_MAX               :: 1
+	_SC_CHILD_MAX             :: 2
+	_SC_CLK_TCK               :: 3
+	_SC_NGROUPS_MAX           :: 4
+	_SC_OPEN_MAX              :: 5
+	_SC_STREAM_MAX            :: 6
+	_SC_TZNAME_MAX            :: 7
+	_SC_JOB_CONTROL           :: 8
+	_SC_SAVED_IDS             :: 9
+	_SC_REALTIME_SIGNALS      :: 10
+	_SC_PRIORITY_SCHEDULING   :: 11
+	_SC_TIMERS                :: 12
+	_SC_ASYNCHRONOUS_IO       :: 13
+	_SC_PRIORITIZED_IO        :: 14
+	_SC_SYNCHRONIZED_IO       :: 15
+	_SC_FSYNC                 :: 16
+	_SC_MAPPED_FILES          :: 17
+	_SC_MEMLOCK               :: 18
+	_SC_MEMLOCK_RANGE         :: 19
+	_SC_MEMORY_PROTECTION     :: 20
+	_SC_MESSAGE_PASSING       :: 21
+	_SC_SEMAPHORES            :: 22
+	_SC_SHARED_MEMORY_OBJECTS :: 23
+	_SC_AIO_LISTIO_MAX        :: 24
+	_SC_AIO_MAX               :: 25
+	_SC_AIO_PRIO_DELTA_MAX    :: 26
+	_SC_DELAYTIMER_MAX        :: 27
+	_SC_MQ_OPEN_MAX           :: 28
+	_SC_MQ_PRIO_MAX           :: 29
+	_SC_VERSION               :: 30
+	_SC_PAGESIZE              :: 31
+	_SC_PAGE_SIZE             :: _SC_PAGESIZE
+	_SC_RTSIG_MAX             :: 32
+	_SC_SEM_NSEMS_MAX         :: 33
+	_SC_SEM_VALUE_MAX         :: 34
+	_SC_SIGQUEUE_MAX          :: 35
+	_SC_TIMER_MAX             :: 36
+	_SC_BC_BASE_MAX           :: 37
+	_SC_BC_DIM_MAX            :: 38
+	_SC_BC_SCALE_MAX          :: 39
+	_SC_BC_STRING_MAX         :: 40
+	_SC_COLL_WEIGHTS_MAX      :: 41
+	_SC_EXPR_NEST_MAX         :: 43
+	_SC_LINE_MAX              :: 44
+	_SC_RE_DUP_MAX            :: 45
+	_SC_2_VERSION             :: 47
+	_SC_2_C_BIND              :: 48
+	_SC_2_C_DEV               :: 49
+	_SC_2_FORT_DEV            :: 50
+	_SC_2_FORT_RUN            :: 51
+	_SC_2_SW_DEV              :: 52
+	_SC_2_LOCALEDEF           :: 53
+
+	_SC_IOV_MAX                      :: 62
+	_SC_THREADS                      :: 69
+	_SC_THREAD_SAFE_FUNCTIONS        :: 70
+	_SC_GETGR_R_SIZE_MAX             :: 71
+	_SC_GETPW_R_SIZE_MAX             :: 72
+	_SC_LOGIN_NAME_MAX               :: 73
+	_SC_TTY_NAME_MAX                 :: 74
+	_SC_THREAD_DESTRUCTOR_ITERATIONS :: 75
+	_SC_THREAD_KEYS_MAX              :: 76
+	_SC_THREAD_STACK_MIN             :: 77
+	_SC_THREAD_THREADS_MAX           :: 78
+	_SC_THREAD_ATTR_STACKADDR        :: 79
+	_SC_THREAD_ATTR_STACKSIZE        :: 80
+	_SC_THREAD_PRIORITY_SCHEDULING   :: 81
+	_SC_THREAD_PRIO_INHERIT          :: 82
+	_SC_THREAD_PRIO_PROTECT          :: 83
+	_SC_THREAD_PROCESS_SHARED        :: 84
+	_SC_NPROCESSORS_CONF             :: 85
+	_SC_NPROCESSORS_ONLN             :: 86
+	_SC_PHYS_PAGES                   :: 87
+	_SC_AVPHYS_PAGES                 :: 88
+	_SC_ATEXIT_MAX                   :: 89
+	_SC_PASS_MAX                     :: 90
+	_SC_XOPEN_VERSION                :: 91
+	_SC_XOPEN_UNIX                   :: 92
+	_SC_XOPEN_CRYPT                  :: 93
+	_SC_XOPEN_ENH_I18N               :: 94
+	_SC_XOPEN_SHM                    :: 95
+	_SC_2_CHAR_TERM                  :: 96
+	_SC_2_UPE                        :: 97
+
+	_SC_XOPEN_LEGACY           :: 129
+	_SC_XOPEN_REALTIME         :: 130
+	_SC_XOPEN_REALTIME_THREADS :: 131
+	_SC_ADVISORY_INFO          :: 132
+	_SC_BARRIERS               :: 133
+	_SC_CLOCK_SELECTION        :: 137
+	_SC_CPUTIME                :: 138
+	_SC_THREAD_CPUTIME         :: 139
+	_SC_MONOTONIC_CLOCK        :: 149
+	_SC_READER_WRITER_LOCKS    :: 153
+	_SC_SPIN_LOCKS             :: 154
+	_SC_REGEXP                 :: 155
+	_SC_SHELL                  :: 157
+	_SC_SPAWN                  :: 159
+	_SC_SPORADIC_SERVER        :: 160
+	_SC_THREAD_SPORADIC_SERVER :: 161
+	_SC_TIMEOUTS               :: 164
+	_SC_TYPED_MEMORY_OBJECTS   :: 165
+	_SC_2_PBS                  :: 168
+	_SC_2_PBS_ACCOUNTING       :: 169
+	_SC_2_PBS_MESSAGE          :: 171
+	_SC_2_PBS_TRACK            :: 172
+	_SC_SYMLOOP_MAX            :: 173
+	_SC_2_PBS_CHECKPOINT       :: 174
+	_SC_V6_ILP32_OFF32         :: 175
+	_SC_V6_ILP32_OFFBIG        :: 176
+	_SC_V6_LP64_OFF64          :: 177
+	_SC_V6_LPBIG_OFFBIG        :: 178
+	_SC_HOST_NAME_MAX          :: 179
+	_SC_TRACE                  :: 180
+	_SC_TRACE_EVENT_FILTER     :: 181
+	_SC_TRACE_INHERIT          :: 182
+	_SC_TRACE_LOG              :: 183
+
+	_SC_IPV6                       :: 234
+	_SC_RAW_SOCKETS                :: 235
+	_SC_V7_ILP32_OFF32             :: 236
+	_SC_V7_ILP32_OFFBIG            :: 237
+	_SC_V7_LP64_OFF64              :: 238
+	_SC_V7_LPBIG_OFFBIG            :: 239
+	_SC_SS_REPL_MAX                :: 240
+	_SC_TRACE_EVENT_NAME_MAX       :: 241
+	_SC_TRACE_NAME_MAX             :: 242
+	_SC_TRACE_SYS_MAX              :: 243
+	_SC_TRACE_USER_EVENT_MAX       :: 244
+	_SC_XOPEN_STREAMS              :: 245
+	_SC_THREAD_ROBUST_PRIO_INHERIT :: 246
+	_SC_THREAD_ROBUST_PRIO_PROTECT :: 247
+
+	// NOTE: Not implemented.
+	_SC_XOPEN_UUCP :: 0
+	// NOTE: Not implemented.
+	_POSIX_VDISABLE :: 0
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }

+ 1 - 1
core/sys/posix/utime.odin

@@ -24,7 +24,7 @@ when ODIN_OS == .NetBSD {
 	@(private) LUTIME :: "utime"
 	@(private) LUTIME :: "utime"
 }
 }
 
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD	{
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD	|| ODIN_OS == .Linux {
 
 
 	utimbuf :: struct {
 	utimbuf :: struct {
 		actime:  time_t, /* [PSX] access time (seconds since epoch) */
 		actime:  time_t, /* [PSX] access time (seconds since epoch) */

+ 21 - 0
core/sys/posix/wordexp.odin

@@ -102,6 +102,27 @@ when ODIN_OS == .Darwin {
 	WRDE_NOSPACE :: 4
 	WRDE_NOSPACE :: 4
 	WRDE_SYNTAX  :: 6
 	WRDE_SYNTAX  :: 6
 
 
+} else when ODIN_OS == .Linux {
+
+	wordexp_t :: struct {
+		we_wordc: c.size_t,   /* [PSX] count of words matched by words */
+		we_wordv: [^]cstring, /* [PSX] pointer to list of expanded words */
+		we_offs:  c.size_t,   /* [PSX] slots to reserve at the beginning of we_wordv */
+	}
+
+	WRDE_DOOFFS  :: 1 << 0	/* Insert PWORDEXP->we_offs NULLs.  */
+	WRDE_APPEND  :: 1 << 1	/* Append to results of a previous call.  */
+	WRDE_NOCMD   :: 1 << 2	/* Don't do command substitution.  */
+	WRDE_REUSE   :: 1 << 3	/* Reuse storage in PWORDEXP.  */
+	WRDE_SHOWERR :: 1 << 4	/* Don't redirect stderr to /dev/null.  */
+	WRDE_UNDEF   :: 1 << 5	/* Error for expanding undefined variables.  */
+
+	WRDE_NOSPACE :: 1
+	WRDE_BADCHAR :: 2
+	WRDE_BADVAL  :: 3
+	WRDE_CMDSUB  :: 4
+	WRDE_SYNTAX  :: 5
+
 } else {
 } else {
 	#panic("posix is unimplemented for the current target")
 	#panic("posix is unimplemented for the current target")
 }
 }