diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index 1fe8ca89d2..ae3a3e9d9e 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -41,6 +41,7 @@ pub const max_name_len = switch (target.os.tag) { .netbsd => 31, .freebsd => 15, .openbsd => 31, + .solaris => 31, else => 0, }; @@ -112,7 +113,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void { else => |e| return os.unexpectedErrno(e), } }, - .netbsd => if (use_pthreads) { + .netbsd, .solaris => if (use_pthreads) { const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr, null); switch (err) { .SUCCESS => return, @@ -202,7 +203,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co else => |e| return os.unexpectedErrno(e), } }, - .netbsd => if (use_pthreads) { + .netbsd, .solaris => if (use_pthreads) { const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1); switch (err) { .SUCCESS => return std.mem.sliceTo(buffer, 0), @@ -565,6 +566,16 @@ const PosixThreadImpl = struct { }; return @intCast(usize, count); }, + .solaris => { + // The "proper" way to get the cpu count would be to query + // /dev/kstat via ioctls, and traverse a linked list for each + // cpu. + const rc = c.sysconf(os._SC.NPROCESSORS_ONLN); + return switch (os.errno(rc)) { + .SUCCESS => @intCast(usize, rc), + else => |err| os.unexpectedErrno(err), + }; + }, .haiku => { var count: u32 = undefined; var system_info: os.system_info = undefined; diff --git a/lib/std/c.zig b/lib/std/c.zig index 6a2624a93e..84fbb59640 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -252,6 +252,33 @@ pub extern "c" fn kevent( timeout: ?*const c.timespec, ) c_int; +pub extern "c" fn port_create() c.port_t; +pub extern "c" fn port_associate( + port: c.port_t, + source: u32, + object: usize, + events: u32, + user_var: ?*c_void, +) c_int; +pub extern "c" fn port_dissociate(port: c.port_t, source: u32, object: usize) c_int; +pub extern "c" fn port_send(port: c.port_t, events: u32, user_var: ?*c_void) c_int; +pub extern "c" fn port_sendn( + ports: [*]c.port_t, + errors: []u32, + num_ports: u32, + events: u32, + user_var: ?*c_void, +) c_int; +pub extern "c" fn port_get(port: c.port_t, event: *c.port_event, timeout: ?*c.timespec) c_int; +pub extern "c" fn port_getn( + port: c.port_t, + event_list: []c.port_event, + max_events: u32, + events_retrieved: *u32, + timeout: ?*c.timespec, +) c_int; +pub extern "c" fn port_alert(port: c.port_t, flags: u32, events: u32, user_var: ?*c_void) c_int; + pub extern "c" fn getaddrinfo( noalias node: ?[*:0]const u8, noalias service: ?[*:0]const u8, diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig index 7c70a01fc4..283ea792cd 100644 --- a/lib/std/c/solaris.zig +++ b/lib/std/c/solaris.zig @@ -1,15 +1,1913 @@ +const std = @import("../std.zig"); +const builtin = @import("builtin"); +const maxInt = std.math.maxInt; +const iovec = std.os.iovec; +const iovec_const = std.os.iovec_const; +const timezone = std.c.timezone; + +extern "c" fn ___errno() *c_int; +pub const _errno = ___errno; + +pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int; +pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; + +pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; +pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; +pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; +pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void; +pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int; +pub extern "c" fn sysconf(sc: c_int) i64; +pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int; +pub extern "c" fn madvise(address: [*]u8, len: usize, advise: u32) c_int; + pub const pthread_mutex_t = extern struct { - __pthread_mutex_flag1: u16 = 0, - __pthread_mutex_flag2: u8 = 0, - __pthread_mutex_ceiling: u8 = 0, - __pthread_mutex_type: u16 = 0, - __pthread_mutex_magic: u16 = 0x4d58, - __pthread_mutex_lock: u64 = 0, - __pthread_mutex_data: u64 = 0, + flag1: u16 = 0, + flag2: u8 = 0, + ceiling: u8 = 0, + @"type": u16 = 0, + magic: u16 = 0x4d58, + lock: u64 = 0, + data: u64 = 0, }; pub const pthread_cond_t = extern struct { - __pthread_cond_flag: u32 = 0, - __pthread_cond_type: u16 = 0, - __pthread_cond_magic: u16 = 0x4356, - __pthread_cond_data: u64 = 0, + flag: [4]u8 = [_]u8{0} ** 4, + @"type": u16 = 0, + magic: u16 = 0x4356, + data: u64 = 0, }; +pub const pthread_rwlock_t = extern struct { + readers: i32 = 0, + @"type": u16 = 0, + magic: u16 = 0x5257, + mutex: pthread_mutex_t = .{}, + readercv: pthread_cond_t = .{}, + writercv: pthread_cond_t = .{}, +}; +pub const pthread_attr_t = extern struct { + mutexattr: ?*c_void = null, +}; +pub const pthread_key_t = c_int; + +pub const sem_t = extern struct { + count: u32 = 0, + @"type": u16 = 0, + magic: u16 = 0x534d, + __pad1: [3]u64 = [_]u64{0} ** 3, + __pad2: [2]u64 = [_]u64{0} ** 2, +}; + +pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8, arg: ?*c_void) E; +pub extern "c" fn pthread_getname_np(thread: std.c.pthread_t, name: [*:0]u8, len: usize) E; + +pub const blkcnt_t = i64; +pub const blksize_t = i32; +pub const clock_t = i64; +pub const dev_t = i32; +pub const fd_t = c_int; +pub const gid_t = u32; +pub const ino_t = u64; +pub const mode_t = u32; +pub const nlink_t = u32; +pub const off_t = i64; +pub const pid_t = i32; +pub const socklen_t = u32; +pub const time_t = i64; +pub const suseconds_t = i64; +pub const uid_t = u32; +pub const major_t = u32; +pub const minor_t = u32; +pub const port_t = c_int; +pub const nfds_t = usize; +pub const id_t = i32; +pub const taskid_t = id_t; +pub const projid_t = id_t; +pub const poolid_t = id_t; +pub const zoneid_t = id_t; +pub const ctid_t = id_t; + +pub const dl_phdr_info = extern struct { + dlpi_addr: std.elf.Addr, + dlpi_name: ?[*:0]const u8, + dlpi_phdr: [*]std.elf.Phdr, + dlpi_phnum: std.elf.Half, + /// Incremented when a new object is mapped into the process. + dlpi_adds: u64, + /// Incremented when an object is unmapped from the process. + dlpi_subs: u64, +}; + +pub const RTLD = struct { + pub const LAZY = 0x00001; + pub const NOW = 0x00002; + pub const NOLOAD = 0x00004; + pub const GLOBAL = 0x00100; + pub const LOCAL = 0x00000; + pub const PARENT = 0x00200; + pub const GROUP = 0x00400; + pub const WORLD = 0x00800; + pub const NODELETE = 0x01000; + pub const FIRST = 0x02000; + pub const CONFGEN = 0x10000; + + pub const NEXT = @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))); + pub const DEFAULT = @intToPtr(*c_void, @bitCast(usize, @as(isize, -2))); + pub const SELF = @intToPtr(*c_void, @bitCast(usize, @as(isize, -3))); + pub const PROBE = @intToPtr(*c_void, @bitCast(usize, @as(isize, -4))); +}; + +pub const Flock = extern struct { + l_type: c_short, + l_whence: c_short, + l_start: off_t, + // len == 0 means until end of file. + l_len: off_t, + l_sysid: c_int, + l_pid: pid_t, + __pad: [4]c_long, +}; + +pub const utsname = extern struct { + sysname: [256:0]u8, + nodename: [256:0]u8, + release: [256:0]u8, + version: [256:0]u8, + machine: [256:0]u8, + domainname: [256:0]u8, +}; + +pub const addrinfo = extern struct { + flags: i32, + family: i32, + socktype: i32, + protocol: i32, + addrlen: socklen_t, + canonname: ?[*:0]u8, + addr: ?*sockaddr, + next: ?*addrinfo, +}; + +pub const EAI = enum(c_int) { + /// address family for hostname not supported + ADDRFAMILY = 1, + /// name could not be resolved at this time + AGAIN = 2, + /// flags parameter had an invalid value + BADFLAGS = 3, + /// non-recoverable failure in name resolution + FAIL = 4, + /// address family not recognized + FAMILY = 5, + /// memory allocation failure + MEMORY = 6, + /// no address associated with hostname + NODATA = 7, + /// name does not resolve + NONAME = 8, + /// service not recognized for socket type + SERVICE = 9, + /// intended socket type was not recognized + SOCKTYPE = 10, + /// system error returned in errno + SYSTEM = 11, + /// argument buffer overflow + OVERFLOW = 12, + /// resolved protocol is unknown + PROTOCOL = 13, + + _, +}; + +pub const EAI_MAX = 14; + +pub const msghdr = extern struct { + /// optional address + msg_name: ?*sockaddr, + /// size of address + msg_namelen: socklen_t, + /// scatter/gather array + msg_iov: [*]iovec, + /// # elements in msg_iov + msg_iovlen: i32, + /// ancillary data + msg_control: ?*c_void, + /// ancillary data buffer len + msg_controllen: socklen_t, + /// flags on received message + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + /// optional address + msg_name: ?*const sockaddr, + /// size of address + msg_namelen: socklen_t, + /// scatter/gather array + msg_iov: [*]iovec_const, + /// # elements in msg_iov + msg_iovlen: i32, + /// ancillary data + msg_control: ?*c_void, + /// ancillary data buffer len + msg_controllen: socklen_t, + /// flags on received message + msg_flags: i32, +}; + +pub const cmsghdr = extern struct { + cmsg_len: socklen_t, + cmsg_level: i32, + cmsg_type: i32, +}; + +/// The stat structure used by libc. +pub const Stat = extern struct { + dev: dev_t, + ino: ino_t, + mode: mode_t, + nlink: nlink_t, + uid: uid_t, + gid: gid_t, + rdev: dev_t, + size: off_t, + atim: timespec, + mtim: timespec, + ctim: timespec, + blksize: blksize_t, + blocks: blkcnt_t, + fstype: [16]u8, + + pub fn atime(self: @This()) timespec { + return self.atim; + } + + pub fn mtime(self: @This()) timespec { + return self.mtim; + } + + pub fn ctime(self: @This()) timespec { + return self.ctim; + } +}; + +pub const timespec = extern struct { + tv_sec: i64, + tv_nsec: isize, +}; + +pub const timeval = extern struct { + /// seconds + tv_sec: time_t, + /// microseconds + tv_usec: suseconds_t, +}; + +pub const MAXNAMLEN = 511; + +pub const dirent = extern struct { + /// Inode number of entry. + d_ino: ino_t, + /// Offset of this entry on disk. + d_off: off_t, + /// Length of this record. + d_reclen: u16, + /// File name. + d_name: [MAXNAMLEN:0]u8, + + pub fn reclen(self: dirent) u16 { + return self.d_reclen; + } +}; + +pub const SOCK = struct { + /// Datagram. + pub const DGRAM = 1; + /// STREAM. + pub const STREAM = 2; + /// Raw-protocol interface. + pub const RAW = 4; + /// Reliably-delivered message. + pub const RDM = 5; + /// Sequenced packed stream. + pub const SEQPACKET = 6; + + pub const NONBLOCK = 0x100000; + pub const NDELAY = 0x200000; + pub const CLOEXEC = 0x080000; +}; + +pub const SO = struct { + pub const DEBUG = 0x0001; + pub const ACCEPTCONN = 0x0002; + pub const REUSEADDR = 0x0004; + pub const KEEPALIVE = 0x0008; + pub const DONTROUTE = 0x0010; + pub const BROADCAST = 0x0020; + pub const USELOOPBACK = 0x0040; + pub const LINGER = 0x0080; + pub const OOBINLINE = 0x0100; + pub const DGRAM_ERRIND = 0x0200; + pub const RECVUCRED = 0x0400; + + pub const SNDBUF = 0x1001; + pub const RCVBUF = 0x1002; + pub const SNDLOWAT = 0x1003; + pub const RCVLOWAT = 0x1004; + pub const SNDTIMEO = 0x1005; + pub const RCVTIMEO = 0x1006; + pub const ERROR = 0x1007; + pub const TYPE = 0x1008; + pub const PROTOTYPE = 0x1009; + pub const ANON_MLP = 0x100a; + pub const MAC_EXEMPT = 0x100b; + pub const DOMAIN = 0x100c; + pub const RCVPSH = 0x100d; + + pub const SECATTR = 0x1011; + pub const TIMESTAMP = 0x1013; + pub const ALLZONES = 0x1014; + pub const EXCLBIND = 0x1015; + pub const MAC_IMPLICIT = 0x1016; + pub const VRRP = 0x1017; +}; + +pub const SOMAXCONN = 128; + +pub const SCM = struct { + pub const UCRED = 0x1012; + pub const RIGHTS = 0x1010; + pub const TIMESTAMP = SO.TIMESTAMP; +}; + +pub const AF = struct { + pub const UNSPEC = 0; + pub const UNIX = 1; + pub const LOCAL = UNIX; + pub const FILE = UNIX; + pub const INET = 2; + pub const IMPLINK = 3; + pub const PUP = 4; + pub const CHAOS = 5; + pub const NS = 6; + pub const NBS = 7; + pub const ECMA = 8; + pub const DATAKIT = 9; + pub const CCITT = 10; + pub const SNA = 11; + pub const DECnet = 12; + pub const DLI = 13; + pub const LAT = 14; + pub const HYLINK = 15; + pub const APPLETALK = 16; + pub const NIT = 17; + pub const @"802" = 18; + pub const OSI = 19; + pub const X25 = 20; + pub const OSINET = 21; + pub const GOSIP = 22; + pub const IPX = 23; + pub const ROUTE = 24; + pub const LINK = 25; + pub const INET6 = 26; + pub const KEY = 27; + pub const NCA = 28; + pub const POLICY = 29; + pub const INET_OFFLOAD = 30; + pub const TRILL = 31; + pub const PACKET = 32; + pub const LX_NETLINK = 33; + pub const MAX = 33; +}; + +pub const SOL = struct { + pub const SOCKET = 0xffff; + pub const ROUTE = 0xfffe; + pub const PACKET = 0xfffd; + pub const FILTER = 0xfffc; +}; + +pub const PF = struct { + pub const UNSPEC = AF.UNSPEC; + pub const UNIX = AF.UNIX; + pub const LOCAL = UNIX; + pub const FILE = UNIX; + pub const INET = AF.INET; + pub const IMPLINK = AF.IMPLINK; + pub const PUP = AF.PUP; + pub const CHAOS = AF.CHAOS; + pub const NS = AF.NS; + pub const NBS = AF.NBS; + pub const ECMA = AF.ECMA; + pub const DATAKIT = AF.DATAKIT; + pub const CCITT = AF.CCITT; + pub const SNA = AF.SNA; + pub const DECnet = AF.DECnet; + pub const DLI = AF.DLI; + pub const LAT = AF.LAT; + pub const HYLINK = AF.HYLINK; + pub const APPLETALK = AF.APPLETALK; + pub const NIT = AF.NIT; + pub const @"802" = AF.@"802"; + pub const OSI = AF.OSI; + pub const X25 = AF.X25; + pub const OSINET = AF.OSINET; + pub const GOSIP = AF.GOSIP; + pub const IPX = AF.IPX; + pub const ROUTE = AF.ROUTE; + pub const LINK = AF.LINK; + pub const INET6 = AF.INET6; + pub const KEY = AF.KEY; + pub const NCA = AF.NCA; + pub const POLICY = AF.POLICY; + pub const TRILL = AF.TRILL; + pub const PACKET = AF.PACKET; + pub const LX_NETLINK = AF.LX_NETLINK; + pub const MAX = AF.MAX; +}; + +pub const in_port_t = u16; +pub const sa_family_t = u16; + +pub const sockaddr = extern struct { + /// address family + family: sa_family_t, + + /// actually longer; address value + data: [14]u8, + + pub const SS_MAXSIZE = 256; + pub const storage = std.x.os.Socket.Address.Native.Storage; + + pub const in = extern struct { + family: sa_family_t = AF.INET, + port: in_port_t, + addr: u32, + zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }, + }; + + pub const in6 = extern struct { + family: sa_family_t = AF.INET6, + port: in_port_t, + flowinfo: u32, + addr: [16]u8, + scope_id: u32, + __src_id: u32 = 0, + }; + + /// Definitions for UNIX IPC domain. + pub const un = extern struct { + family: sa_family_t = AF.UNIX, + path: [108]u8, + }; +}; + +pub const AI = struct { + /// IPv4-mapped IPv6 address + pub const V4MAPPED = 0x0001; + pub const ALL = 0x0002; + /// only if any address is assigned + pub const ADDRCONFIG = 0x0004; + /// get address to use bind() + pub const PASSIVE = 0x0008; + /// fill ai_canonname + pub const CANONNAME = 0x0010; + /// prevent host name resolution + pub const NUMERICHOST = 0x0020; + /// prevent service name resolution + pub const NUMERICSERV = 0x0040; +}; + +pub const NI = struct { + pub const NOFQDN = 0x0001; + pub const NUMERICHOST = 0x0002; + pub const NAMEREQD = 0x0004; + pub const NUMERICSERV = 0x0008; + pub const DGRAM = 0x0010; + pub const WITHSCOPEID = 0x0020; + pub const NUMERICSCOPE = 0x0040; + + pub const MAXHOST = 1025; + pub const MAXSERV = 32; +}; + +pub const PATH_MAX = 1024; +pub const IOV_MAX = 1024; + +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +pub const PROT = struct { + pub const NONE = 0; + pub const READ = 1; + pub const WRITE = 2; + pub const EXEC = 4; +}; + +pub const CLOCK = struct { + pub const VIRTUAL = 1; + pub const THREAD_CPUTIME_ID = 2; + pub const REALTIME = 3; + pub const MONOTONIC = 4; + pub const PROCESS_CPUTIME_ID = 5; + pub const HIGHRES = MONOTONIC; + pub const PROF = THREAD_CPUTIME_ID; +}; + +pub const MAP = struct { + pub const FAILED = @intToPtr(*c_void, maxInt(usize)); + pub const SHARED = 0x0001; + pub const PRIVATE = 0x0002; + pub const TYPE = 0x000f; + + pub const FILE = 0x0000; + pub const FIXED = 0x0010; + // Unimplemented + pub const RENAME = 0x0020; + pub const NORESERVE = 0x0040; + /// Force mapping in lower 4G address space + pub const @"32BIT" = 0x0080; + + pub const ANON = 0x0100; + pub const ANONYMOUS = ANON; + pub const ALIGN = 0x0200; + pub const TEXT = 0x0400; + pub const INITDATA = 0x0800; +}; + +pub const MADV = struct { + /// no further special treatment + pub const NORMAL = 0; + /// expect random page references + pub const RANDOM = 1; + /// expect sequential page references + pub const SEQUENTIAL = 2; + /// will need these pages + pub const WILLNEED = 3; + /// don't need these pages + pub const DONTNEED = 4; + /// contents can be freed + pub const FREE = 5; + /// default access + pub const ACCESS_DEFAULT = 6; + /// next LWP to access heavily + pub const ACCESS_LWP = 7; + /// many processes to access heavily + pub const ACCESS_MANY = 8; + /// contents will be purged + pub const PURGE = 9; +}; + +pub const W = struct { + pub const EXITED = 0o001; + pub const TRAPPED = 0o002; + pub const UNTRACED = 0o004; + pub const STOPPED = UNTRACED; + pub const CONTINUED = 0o010; + pub const NOHANG = 0o100; + pub const NOWAIT = 0o200; + + pub fn EXITSTATUS(s: u32) u8 { + return @intCast(u8, (s >> 8) & 0xff); + } + pub fn TERMSIG(s: u32) u32 { + return s & 0x7f; + } + pub fn STOPSIG(s: u32) u32 { + return EXITSTATUS(s); + } + pub fn IFEXITED(s: u32) bool { + return TERMSIG(s) == 0; + } + + pub fn IFCONTINUED(s: u32) bool { + return ((s & 0o177777) == 0o177777); + } + + pub fn IFSTOPPED(s: u32) bool { + return (s & 0x00ff != 0o177) and !(s & 0xff00 != 0); + } + + pub fn IFSIGNALED(s: u32) bool { + return s & 0x00ff > 0 and s & 0xff00 == 0; + } +}; + +pub const SA = struct { + pub const ONSTACK = 0x00000001; + pub const RESETHAND = 0x00000002; + pub const RESTART = 0x00000004; + pub const SIGINFO = 0x00000008; + pub const NODEFER = 0x00000010; + pub const NOCLDWAIT = 0x00010000; +}; + +// access function +pub const F_OK = 0; // test for existence of file +pub const X_OK = 1; // test for execute or search permission +pub const W_OK = 2; // test for write permission +pub const R_OK = 4; // test for read permission + +pub const F = struct { + /// Unlock a previously locked region + pub const ULOCK = 0; + /// Lock a region for exclusive use + pub const LOCK = 1; + /// Test and lock a region for exclusive use + pub const TLOCK = 2; + /// Test a region for other processes locks + pub const TEST = 3; + + /// Duplicate fildes + pub const DUPFD = 0; + /// Get fildes flags + pub const GETFD = 1; + /// Set fildes flags + pub const SETFD = 2; + /// Get file flags + pub const GETFL = 3; + /// Get file flags including open-only flags + pub const GETXFL = 45; + /// Set file flags + pub const SETFL = 4; + + /// Unused + pub const CHKFL = 8; + /// Duplicate fildes at third arg + pub const DUP2FD = 9; + /// Like DUP2FD with O_CLOEXEC set EINVAL is fildes matches arg1 + pub const DUP2FD_CLOEXEC = 36; + /// Like DUPFD with O_CLOEXEC set + pub const DUPFD_CLOEXEC = 37; + + /// Is the file desc. a stream ? + pub const ISSTREAM = 13; + /// Turn on private access to file + pub const PRIV = 15; + /// Turn off private access to file + pub const NPRIV = 16; + /// UFS quota call + pub const QUOTACTL = 17; + /// Get number of BLKSIZE blocks allocated + pub const BLOCKS = 18; + /// Get optimal I/O block size + pub const BLKSIZE = 19; + /// Get owner (socket emulation) + pub const GETOWN = 23; + /// Set owner (socket emulation) + pub const SETOWN = 24; + /// Object reuse revoke access to file desc. + pub const REVOKE = 25; + /// Does vp have NFS locks private to lock manager + pub const HASREMOTELOCKS = 26; + + /// Set file lock + pub const SETLK = 6; + /// Set file lock and wait + pub const SETLKW = 7; + /// Allocate file space + pub const ALLOCSP = 10; + /// Free file space + pub const FREESP = 11; + /// Get file lock + pub const GETLK = 14; + /// Get file lock owned by file + pub const OFD_GETLK = 47; + /// Set file lock owned by file + pub const OFD_SETLK = 48; + /// Set file lock owned by file and wait + pub const OFD_SETLKW = 49; + /// Set a file share reservation + pub const SHARE = 40; + /// Remove a file share reservation + pub const UNSHARE = 41; + /// Create Poison FD + pub const BADFD = 46; + + /// Read lock + pub const RDLCK = 1; + /// Write lock + pub const WRLCK = 2; + /// Remove lock(s) + pub const UNLCK = 3; + /// remove remote locks for a given system + pub const UNLKSYS = 4; + + // f_access values + /// Read-only share access + pub const RDACC = 0x1; + /// Write-only share access + pub const WRACC = 0x2; + /// Read-Write share access + pub const RWACC = 0x3; + + // f_deny values + /// Don't deny others access + pub const NODNY = 0x0; + /// Deny others read share access + pub const RDDNY = 0x1; + /// Deny others write share access + pub const WRDNY = 0x2; + /// Deny others read or write share access + pub const RWDNY = 0x3; + /// private flag: Deny delete share access + pub const RMDNY = 0x4; +}; + +pub const O = struct { + pub const RDONLY = 0; + pub const WRONLY = 1; + pub const RDWR = 2; + pub const SEARCH = 0x200000; + pub const EXEC = 0x400000; + pub const NDELAY = 0x04; + pub const APPEND = 0x08; + pub const SYNC = 0x10; + pub const DSYNC = 0x40; + pub const RSYNC = 0x8000; + pub const NONBLOCK = 0x80; + pub const LARGEFILE = 0x2000; + + pub const CREAT = 0x100; + pub const TRUNC = 0x200; + pub const EXCL = 0x400; + pub const NOCTTY = 0x800; + pub const XATTR = 0x4000; + pub const NOFOLLOW = 0x20000; + pub const NOLINKS = 0x40000; + pub const CLOEXEC = 0x800000; + pub const DIRECTORY = 0x1000000; + pub const DIRECT = 0x2000000; +}; + +pub const LOCK = struct { + pub const SH = 1; + pub const EX = 2; + pub const NB = 4; + pub const UN = 8; +}; + +pub const FD_CLOEXEC = 1; + +pub const SEEK = struct { + pub const SET = 0; + pub const CUR = 1; + pub const END = 2; + pub const DATA = 3; + pub const HOLE = 4; +}; + +pub const tcflag_t = c_uint; +pub const cc_t = u8; +pub const speed_t = c_uint; + +pub const NCCS = 19; + +pub const termios = extern struct { + c_iflag: tcflag_t, + c_oflag: tcflag_t, + c_cflag: tcflag_t, + c_lflag: tcflag_t, + c_cc: [NCCS]cc_t, +}; + +fn tioc(t: u16, num: u8) u16 { + return (t << 8) | num; +} + +pub const T = struct { + pub const CGETA = tioc('T', 1); + pub const CSETA = tioc('T', 2); + pub const CSETAW = tioc('T', 3); + pub const CSETAF = tioc('T', 4); + pub const CSBRK = tioc('T', 5); + pub const CXONC = tioc('T', 6); + pub const CFLSH = tioc('T', 7); + pub const IOCGWINSZ = tioc('T', 104); + pub const IOCSWINSZ = tioc('T', 103); + // Softcarrier ioctls + pub const IOCGSOFTCAR = tioc('T', 105); + pub const IOCSSOFTCAR = tioc('T', 106); + // termios ioctls + pub const CGETS = tioc('T', 13); + pub const CSETS = tioc('T', 14); + pub const CSANOW = tioc('T', 14); + pub const CSETSW = tioc('T', 15); + pub const CSADRAIN = tioc('T', 15); + pub const CSETSF = tioc('T', 16); + pub const IOCSETLD = tioc('T', 123); + pub const IOCGETLD = tioc('T', 124); + // NTP PPS ioctls + pub const IOCGPPS = tioc('T', 125); + pub const IOCSPPS = tioc('T', 126); + pub const IOCGPPSEV = tioc('T', 127); + + pub const IOCGETD = tioc('t', 0); + pub const IOCSETD = tioc('t', 1); + pub const IOCHPCL = tioc('t', 2); + pub const IOCGETP = tioc('t', 8); + pub const IOCSETP = tioc('t', 9); + pub const IOCSETN = tioc('t', 10); + pub const IOCEXCL = tioc('t', 13); + pub const IOCNXCL = tioc('t', 14); + pub const IOCFLUSH = tioc('t', 16); + pub const IOCSETC = tioc('t', 17); + pub const IOCGETC = tioc('t', 18); + /// bis local mode bits + pub const IOCLBIS = tioc('t', 127); + /// bic local mode bits + pub const IOCLBIC = tioc('t', 126); + /// set entire local mode word + pub const IOCLSET = tioc('t', 125); + /// get local modes + pub const IOCLGET = tioc('t', 124); + /// set break bit + pub const IOCSBRK = tioc('t', 123); + /// clear break bit + pub const IOCCBRK = tioc('t', 122); + /// set data terminal ready + pub const IOCSDTR = tioc('t', 121); + /// clear data terminal ready + pub const IOCCDTR = tioc('t', 120); + /// set local special chars + pub const IOCSLTC = tioc('t', 117); + /// get local special chars + pub const IOCGLTC = tioc('t', 116); + /// driver output queue size + pub const IOCOUTQ = tioc('t', 115); + /// void tty association + pub const IOCNOTTY = tioc('t', 113); + /// get a ctty + pub const IOCSCTTY = tioc('t', 132); + /// stop output, like ^S + pub const IOCSTOP = tioc('t', 111); + /// start output, like ^Q + pub const IOCSTART = tioc('t', 110); + /// get pgrp of tty + pub const IOCGPGRP = tioc('t', 20); + /// set pgrp of tty + pub const IOCSPGRP = tioc('t', 21); + /// get session id on ctty + pub const IOCGSID = tioc('t', 22); + /// simulate terminal input + pub const IOCSTI = tioc('t', 23); + /// set all modem bits + pub const IOCMSET = tioc('t', 26); + /// bis modem bits + pub const IOCMBIS = tioc('t', 27); + /// bic modem bits + pub const IOCMBIC = tioc('t', 28); + /// get all modem bits + pub const IOCMGET = tioc('t', 29); +}; + +pub const winsize = extern struct { + ws_row: u16, + ws_col: u16, + ws_xpixel: u16, + ws_ypixel: u16, +}; + +const NSIG = 75; + +pub const SIG = struct { + pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); + pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); + pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); + pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 2); + + pub const WORDS = 4; + pub const MAXSIG = 75; + + pub const SIG_BLOCK = 1; + pub const SIG_UNBLOCK = 2; + pub const SIG_SETMASK = 3; + + pub const HUP = 1; + pub const INT = 2; + pub const QUIT = 3; + pub const ILL = 4; + pub const TRAP = 5; + pub const IOT = 6; + pub const ABRT = 6; + pub const EMT = 7; + pub const FPE = 8; + pub const KILL = 9; + pub const BUS = 10; + pub const SEGV = 11; + pub const SYS = 12; + pub const PIPE = 13; + pub const ALRM = 14; + pub const TERM = 15; + pub const USR1 = 16; + pub const USR2 = 17; + pub const CLD = 18; + pub const CHLD = 18; + pub const PWR = 19; + pub const WINCH = 20; + pub const URG = 21; + pub const POLL = 22; + pub const IO = .POLL; + pub const STOP = 23; + pub const TSTP = 24; + pub const CONT = 25; + pub const TTIN = 26; + pub const TTOU = 27; + pub const VTALRM = 28; + pub const PROF = 29; + pub const XCPU = 30; + pub const XFSZ = 31; + pub const WAITING = 32; + pub const LWP = 33; + pub const FREEZE = 34; + pub const THAW = 35; + pub const CANCEL = 36; + pub const LOST = 37; + pub const XRES = 38; + pub const JVM1 = 39; + pub const JVM2 = 40; + pub const INFO = 41; + + pub const RTMIN = 42; + pub const RTMAX = 74; + + pub inline fn IDX(sig: usize) usize { + return sig - 1; + } + pub inline fn WORD(sig: usize) usize { + return IDX(sig) >> 5; + } + pub inline fn BIT(sig: usize) usize { + return 1 << (IDX(sig) & 31); + } + pub inline fn VALID(sig: usize) usize { + return sig <= MAXSIG and sig > 0; + } +}; + +/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. +pub const Sigaction = extern struct { + pub const handler_fn = fn (c_int) callconv(.C) void; + pub const sigaction_fn = fn (c_int, *const siginfo_t, ?*const c_void) callconv(.C) void; + + /// signal options + flags: c_uint, + /// signal handler + handler: extern union { + handler: ?handler_fn, + sigaction: ?sigaction_fn, + }, + /// signal mask to apply + mask: sigset_t, +}; + +pub const sigval_t = extern union { + int: c_int, + ptr: ?*c_void, +}; + +pub const siginfo_t = extern struct { + signo: c_int, + code: c_int, + errno: c_int, + // 64bit architectures insert 4bytes of padding here, this is done by + // correctly aligning the reason field + reason: extern union { + proc: extern struct { + pid: pid_t, + pdata: extern union { + kill: extern struct { + uid: uid_t, + value: sigval_t, + }, + cld: extern struct { + utime: clock_t, + status: c_int, + stime: clock_t, + }, + }, + contract: ctid_t, + zone: zoneid_t, + }, + fault: extern struct { + addr: ?*c_void, + trapno: c_int, + pc: ?*c_void, + }, + file: extern struct { + // fd not currently available for SIGPOLL. + fd: c_int, + band: c_long, + }, + prof: extern struct { + addr: ?*c_void, + timestamp: timespec, + syscall: c_short, + sysarg: u8, + fault: u8, + args: [8]c_long, + state: [10]c_int, + }, + rctl: extern struct { + entity: i32, + }, + __pad: [256 - 4 * @sizeOf(c_int)]u8, + } align(@sizeOf(usize)), +}; + +comptime { + std.debug.assert(@sizeOf(siginfo_t) == 256); + std.debug.assert(@alignOf(siginfo_t) == @sizeOf(usize)); +} + +pub const sigset_t = extern struct { + __bits: [SIG.WORDS]u32, +}; + +pub const empty_sigset = sigset_t{ .__bits = [_]u32{0} ** SIG.WORDS }; + +pub const fpregset_t = extern union { + regs: [130]u32, + chip_state: extern struct { + cw: u16, + sw: u16, + fctw: u8, + __fx_rsvd: u8, + fop: u16, + rip: u64, + rdp: u64, + mxcsr: u32, + mxcsr_mask: u32, + st: [8]extern union { + fpr_16: [5]u16, + __fpr_pad: u128, + }, + xmm: [16]u128, + __fx_ign2: [6]u128, + status: u32, + xstatus: u32, + }, +}; + +pub const mcontext_t = extern struct { + gregs: [28]u64, + fpregs: fpregset_t, +}; + +pub const REG = struct { + pub const RBP = 10; + pub const RIP = 17; + pub const RSP = 20; +}; + +pub const ucontext_t = extern struct { + flags: u64, + link: ?*ucontext_t, + sigmask: sigset_t, + stack: stack_t, + mcontext: mcontext_t, + brand_data: [3]?*c_void, + filler: [2]i64, +}; + +pub const GETCONTEXT = 0; +pub const SETCONTEXT = 1; +pub const GETUSTACK = 2; +pub const SETUSTACK = 3; + +pub const E = enum(u16) { + /// No error occurred. + SUCCESS = 0, + /// Not super-user + PERM = 1, + /// No such file or directory + NOENT = 2, + /// No such process + SRCH = 3, + /// interrupted system call + INTR = 4, + /// I/O error + IO = 5, + /// No such device or address + NXIO = 6, + /// Arg list too long + @"2BIG" = 7, + /// Exec format error + NOEXEC = 8, + /// Bad file number + BADF = 9, + /// No children + CHILD = 10, + /// Resource temporarily unavailable. + /// also: WOULDBLOCK: Operation would block. + AGAIN = 11, + /// Not enough core + NOMEM = 12, + /// Permission denied + ACCES = 13, + /// Bad address + FAULT = 14, + /// Block device required + NOTBLK = 15, + /// Mount device busy + BUSY = 16, + /// File exists + EXIST = 17, + /// Cross-device link + XDEV = 18, + /// No such device + NODEV = 19, + /// Not a directory + NOTDIR = 20, + /// Is a directory + ISDIR = 21, + /// Invalid argument + INVAL = 22, + /// File table overflow + NFILE = 23, + /// Too many open files + MFILE = 24, + /// Inappropriate ioctl for device + NOTTY = 25, + /// Text file busy + TXTBSY = 26, + /// File too large + FBIG = 27, + /// No space left on device + NOSPC = 28, + /// Illegal seek + SPIPE = 29, + /// Read only file system + ROFS = 30, + /// Too many links + MLINK = 31, + /// Broken pipe + PIPE = 32, + /// Math arg out of domain of func + DOM = 33, + /// Math result not representable + RANGE = 34, + /// No message of desired type + NOMSG = 35, + /// Identifier removed + IDRM = 36, + /// Channel number out of range + CHRNG = 37, + /// Level 2 not synchronized + L2NSYNC = 38, + /// Level 3 halted + L3HLT = 39, + /// Level 3 reset + L3RST = 40, + /// Link number out of range + LNRNG = 41, + /// Protocol driver not attached + UNATCH = 42, + /// No CSI structure available + NOCSI = 43, + /// Level 2 halted + L2HLT = 44, + /// Deadlock condition. + DEADLK = 45, + /// No record locks available. + NOLCK = 46, + /// Operation canceled + CANCELED = 47, + /// Operation not supported + NOTSUP = 48, + + // Filesystem Quotas + /// Disc quota exceeded + DQUOT = 49, + + // Convergent Error Returns + /// invalid exchange + BADE = 50, + /// invalid request descriptor + BADR = 51, + /// exchange full + XFULL = 52, + /// no anode + NOANO = 53, + /// invalid request code + BADRQC = 54, + /// invalid slot + BADSLT = 55, + /// file locking deadlock error + DEADLOCK = 56, + /// bad font file fmt + BFONT = 57, + + // Interprocess Robust Locks + /// process died with the lock + OWNERDEAD = 58, + /// lock is not recoverable + NOTRECOVERABLE = 59, + /// locked lock was unmapped + LOCKUNMAPPED = 72, + /// Facility is not active + NOTACTIVE = 73, + /// multihop attempted + MULTIHOP = 74, + /// trying to read unreadable message + BADMSG = 77, + /// path name is too long + NAMETOOLONG = 78, + /// value too large to be stored in data type + OVERFLOW = 79, + /// given log. name not unique + NOTUNIQ = 80, + /// f.d. invalid for this operation + BADFD = 81, + /// Remote address changed + REMCHG = 82, + + // Stream Problems + /// Device not a stream + NOSTR = 60, + /// no data (for no delay io) + NODATA = 61, + /// timer expired + TIME = 62, + /// out of streams resources + NOSR = 63, + /// Machine is not on the network + NONET = 64, + /// Package not installed + NOPKG = 65, + /// The object is remote + REMOTE = 66, + /// the link has been severed + NOLINK = 67, + /// advertise error + ADV = 68, + /// srmount error + SRMNT = 69, + /// Communication error on send + COMM = 70, + /// Protocol error + PROTO = 71, + + // Shared Library Problems + /// Can't access a needed shared lib. + LIBACC = 83, + /// Accessing a corrupted shared lib. + LIBBAD = 84, + /// .lib section in a.out corrupted. + LIBSCN = 85, + /// Attempting to link in too many libs. + LIBMAX = 86, + /// Attempting to exec a shared library. + LIBEXEC = 87, + /// Illegal byte sequence. + ILSEQ = 88, + /// Unsupported file system operation + NOSYS = 89, + /// Symbolic link loop + LOOP = 90, + /// Restartable system call + RESTART = 91, + /// if pipe/FIFO, don't sleep in stream head + STRPIPE = 92, + /// directory not empty + NOTEMPTY = 93, + /// Too many users (for UFS) + USERS = 94, + + // BSD Networking Software + // Argument Errors + /// Socket operation on non-socket + NOTSOCK = 95, + /// Destination address required + DESTADDRREQ = 96, + /// Message too long + MSGSIZE = 97, + /// Protocol wrong type for socket + PROTOTYPE = 98, + /// Protocol not available + NOPROTOOPT = 99, + /// Protocol not supported + PROTONOSUPPORT = 120, + /// Socket type not supported + SOCKTNOSUPPORT = 121, + /// Operation not supported on socket + OPNOTSUPP = 122, + /// Protocol family not supported + PFNOSUPPORT = 123, + /// Address family not supported by + AFNOSUPPORT = 124, + /// Address already in use + ADDRINUSE = 125, + /// Can't assign requested address + ADDRNOTAVAIL = 126, + + // Operational Errors + /// Network is down + NETDOWN = 127, + /// Network is unreachable + NETUNREACH = 128, + /// Network dropped connection because + NETRESET = 129, + /// Software caused connection abort + CONNABORTED = 130, + /// Connection reset by peer + CONNRESET = 131, + /// No buffer space available + NOBUFS = 132, + /// Socket is already connected + ISCONN = 133, + /// Socket is not connected + NOTCONN = 134, + /// Can't send after socket shutdown + SHUTDOWN = 143, + /// Too many references: can't splice + TOOMANYREFS = 144, + /// Connection timed out + TIMEDOUT = 145, + /// Connection refused + CONNREFUSED = 146, + /// Host is down + HOSTDOWN = 147, + /// No route to host + HOSTUNREACH = 148, + /// operation already in progress + ALREADY = 149, + /// operation now in progress + INPROGRESS = 150, + + // SUN Network File System + /// Stale NFS file handle + STALE = 151, + + _, +}; + +pub const MINSIGSTKSZ = 2048; +pub const SIGSTKSZ = 8192; + +pub const SS_ONSTACK = 0x1; +pub const SS_DISABLE = 0x2; + +pub const stack_t = extern struct { + sp: [*]u8, + size: isize, + flags: i32, +}; + +pub const S = struct { + pub const IFMT = 0o170000; + + pub const IFIFO = 0o010000; + pub const IFCHR = 0o020000; + pub const IFDIR = 0o040000; + pub const IFBLK = 0o060000; + pub const IFREG = 0o100000; + pub const IFLNK = 0o120000; + pub const IFSOCK = 0o140000; + /// SunOS 2.6 Door + pub const IFDOOR = 0o150000; + /// Solaris 10 Event Port + pub const IFPORT = 0o160000; + + pub const ISUID = 0o4000; + pub const ISGID = 0o2000; + pub const ISVTX = 0o1000; + pub const IRWXU = 0o700; + pub const IRUSR = 0o400; + pub const IWUSR = 0o200; + pub const IXUSR = 0o100; + pub const IRWXG = 0o070; + pub const IRGRP = 0o040; + pub const IWGRP = 0o020; + pub const IXGRP = 0o010; + pub const IRWXO = 0o007; + pub const IROTH = 0o004; + pub const IWOTH = 0o002; + pub const IXOTH = 0o001; + + pub fn ISFIFO(m: u32) bool { + return m & IFMT == IFIFO; + } + + pub fn ISCHR(m: u32) bool { + return m & IFMT == IFCHR; + } + + pub fn ISDIR(m: u32) bool { + return m & IFMT == IFDIR; + } + + pub fn ISBLK(m: u32) bool { + return m & IFMT == IFBLK; + } + + pub fn ISREG(m: u32) bool { + return m & IFMT == IFREG; + } + + pub fn ISLNK(m: u32) bool { + return m & IFMT == IFLNK; + } + + pub fn ISSOCK(m: u32) bool { + return m & IFMT == IFSOCK; + } + + pub fn ISDOOR(m: u32) bool { + return m & IFMT == IFDOOR; + } + + pub fn ISPORT(m: u32) bool { + return m & IFMT == IFPORT; + } +}; + +pub const AT = struct { + /// Magic value that specify the use of the current working directory + /// to determine the target of relative file paths in the openat() and + /// similar syscalls. + pub const FDCWD = @bitCast(fd_t, @as(u32, 0xffd19553)); + + /// Do not follow symbolic links + pub const SYMLINK_NOFOLLOW = 0x1000; + /// Follow symbolic link + pub const SYMLINK_FOLLOW = 0x2000; + /// Remove directory instead of file + pub const REMOVEDIR = 0x1; + pub const TRIGGER = 0x2; + /// Check access using effective user and group ID + pub const EACCESS = 0x4; +}; + +pub const POSIX_FADV = struct { + pub const NORMAL = 0; + pub const RANDOM = 1; + pub const SEQUENTIAL = 2; + pub const WILLNEED = 3; + pub const DONTNEED = 4; + pub const NOREUSE = 5; +}; + +pub const HOST_NAME_MAX = 255; + +pub const IPPROTO = struct { + /// dummy for IP + pub const IP = 0; + /// Hop by hop header for IPv6 + pub const HOPOPTS = 0; + /// control message protocol + pub const ICMP = 1; + /// group control protocol + pub const IGMP = 2; + /// gateway^2 (deprecated) + pub const GGP = 3; + /// IP in IP encapsulation + pub const ENCAP = 4; + /// tcp + pub const TCP = 6; + /// exterior gateway protocol + pub const EGP = 8; + /// pup + pub const PUP = 12; + /// user datagram protocol + pub const UDP = 17; + /// xns idp + pub const IDP = 22; + /// IPv6 encapsulated in IP + pub const IPV6 = 41; + /// Routing header for IPv6 + pub const ROUTING = 43; + /// Fragment header for IPv6 + pub const FRAGMENT = 44; + /// rsvp + pub const RSVP = 46; + /// IPsec Encap. Sec. Payload + pub const ESP = 50; + /// IPsec Authentication Hdr. + pub const AH = 51; + /// ICMP for IPv6 + pub const ICMPV6 = 58; + /// No next header for IPv6 + pub const NONE = 59; + /// Destination options + pub const DSTOPTS = 60; + /// "hello" routing protocol + pub const HELLO = 63; + /// UNOFFICIAL net disk proto + pub const ND = 77; + /// ISO clnp + pub const EON = 80; + /// OSPF + pub const OSPF = 89; + /// PIM routing protocol + pub const PIM = 103; + /// Stream Control + pub const SCTP = 132; + /// raw IP packet + pub const RAW = 255; + /// Sockets Direct Protocol + pub const PROTO_SDP = 257; +}; + +pub const priority = enum(c_int) { + PROCESS = 0, + PGRP = 1, + USER = 2, + GROUP = 3, + SESSION = 4, + LWP = 5, + TASK = 6, + PROJECT = 7, + ZONE = 8, + CONTRACT = 9, +}; + +pub const rlimit_resource = enum(c_int) { + CPU = 0, + FSIZE = 1, + DATA = 2, + STACK = 3, + CORE = 4, + NOFILE = 5, + VMEM = 6, + _, + + pub const AS: rlimit_resource = .VMEM; +}; + +pub const rlim_t = u64; + +pub const RLIM = struct { + /// No limit + pub const INFINITY: rlim_t = (1 << 63) - 3; + pub const SAVED_MAX: rlim_t = (1 << 63) - 2; + pub const SAVED_CUR: rlim_t = (1 << 63) - 1; +}; + +pub const rlimit = extern struct { + /// Soft limit + cur: rlim_t, + /// Hard limit + max: rlim_t, +}; + +pub const RUSAGE_SELF = 0; +pub const RUSAGE_CHILDREN = -1; +pub const RUSAGE_THREAD = 1; + +pub const rusage = extern struct { + utime: timeval, + stime: timeval, + maxrss: isize, + ixrss: isize, + idrss: isize, + isrss: isize, + minflt: isize, + majflt: isize, + nswap: isize, + inblock: isize, + oublock: isize, + msgsnd: isize, + msgrcv: isize, + nsignals: isize, + nvcsw: isize, + nivcsw: isize, +}; + +pub const SHUT = struct { + pub const RD = 0; + pub const WR = 1; + pub const RDWR = 2; +}; + +pub const pollfd = extern struct { + fd: fd_t, + events: i16, + revents: i16, +}; + +/// Testable events (may be specified in ::pollfd::events). +pub const POLL = struct { + pub const IN = 0x0001; + pub const PRI = 0x0002; + pub const OUT = 0x0004; + pub const RDNORM = 0x0040; + pub const WRNORM = .OUT; + pub const RDBAND = 0x0080; + pub const WRBAND = 0x0100; + /// Read-side hangup. + pub const RDHUP = 0x4000; + + /// Non-testable events (may not be specified in events). + pub const ERR = 0x0008; + pub const HUP = 0x0010; + pub const NVAL = 0x0020; + + /// Events to control `/dev/poll` (not specified in revents) + pub const REMOVE = 0x0800; + pub const ONESHOT = 0x1000; + pub const ET = 0x2000; +}; + +/// Extensions to the ELF auxiliary vector. +pub const AT_SUN = struct { + /// effective user id + pub const UID = 2000; + /// real user id + pub const RUID = 2001; + /// effective group id + pub const GID = 2002; + /// real group id + pub const RGID = 2003; + /// dynamic linker's ELF header + pub const LDELF = 2004; + /// dynamic linker's section headers + pub const LDSHDR = 2005; + /// name of dynamic linker + pub const LDNAME = 2006; + /// large pagesize + pub const LPAGESZ = 2007; + /// platform name + pub const PLATFORM = 2008; + /// hints about hardware capabilities. + pub const HWCAP = 2009; + pub const HWCAP2 = 2023; + /// flush icache? + pub const IFLUSH = 2010; + /// cpu name + pub const CPU = 2011; + /// exec() path name in the auxv, null terminated. + pub const EXECNAME = 2014; + /// mmu module name + pub const MMU = 2015; + /// dynamic linkers data segment + pub const LDDATA = 2016; + /// AF_SUN_ flags passed from the kernel + pub const AUXFLAGS = 2017; + /// name of the emulation binary for the linker + pub const EMULATOR = 2018; + /// name of the brand library for the linker + pub const BRANDNAME = 2019; + /// vectors for brand modules. + pub const BRAND_AUX1 = 2020; + pub const BRAND_AUX2 = 2021; + pub const BRAND_AUX3 = 2022; + pub const BRAND_AUX4 = 2025; + pub const BRAND_NROOT = 2024; + /// vector for comm page. + pub const COMMPAGE = 2026; + /// information about the x86 FPU. + pub const FPTYPE = 2027; + pub const FPSIZE = 2028; +}; + +/// ELF auxiliary vector flags. +pub const AF_SUN = struct { + /// tell ld.so.1 to run "secure" and ignore the environment. + pub const SETUGID = 0x00000001; + /// hardware capabilities can be verified against AT_SUN_HWCAP + pub const HWCAPVERIFY = 0x00000002; + pub const NOPLM = 0x00000004; +}; + +// TODO: Add sysconf numbers when the other OSs do. +pub const _SC = struct { + pub const NPROCESSORS_ONLN = 15; +}; + +pub const procfs = struct { + pub const misc_header = extern struct { + size: u32, + @"type": enum(u32) { + Pathname, + Socketname, + Peersockname, + SockoptsBoolOpts, + SockoptLinger, + SockoptSndbuf, + SockoptRcvbuf, + SockoptIpNexthop, + SockoptIpv6Nexthop, + SockoptType, + SockoptTcpCongestion, + SockfiltersPriv = 14, + }, + }; + + pub const fdinfo = extern struct { + fd: fd_t, + mode: mode_t, + ino: ino_t, + size: off_t, + offset: off_t, + uid: uid_t, + gid: gid_t, + dev_major: major_t, + dev_minor: minor_t, + special_major: major_t, + special_minor: minor_t, + fileflags: i32, + fdflags: i32, + locktype: i16, + lockpid: pid_t, + locksysid: i32, + peerpid: pid_t, + __filler: [25]c_int, + peername: [15:0]u8, + misc: [1]u8, + }; +}; + +pub const SFD = struct { + pub const CLOEXEC = 0o2000000; + pub const NONBLOCK = 0o4000; +}; + +pub const signalfd_siginfo = extern struct { + signo: u32, + errno: i32, + code: i32, + pid: u32, + uid: uid_t, + fd: i32, + tid: u32, // unused + band: u32, + overrun: u32, // unused + trapno: u32, + status: i32, + int: i32, // unused + ptr: u64, // unused + utime: u64, + stime: u64, + addr: u64, + __pad: [48]u8, +}; + +pub const PORT_SOURCE = struct { + pub const AIO = 1; + pub const TIMER = 2; + pub const USER = 3; + pub const FD = 4; + pub const ALERT = 5; + pub const MQ = 6; + pub const FILE = 7; +}; + +pub const PORT_ALERT = struct { + pub const SET = 0x01; + pub const UPDATE = 0x02; +}; + +/// User watchable file events. +pub const FILE_EVENT = struct { + pub const ACCESS = 0x00000001; + pub const MODIFIED = 0x00000002; + pub const ATTRIB = 0x00000004; + pub const DELETE = 0x00000010; + pub const RENAME_TO = 0x00000020; + pub const RENAME_FROM = 0x00000040; + pub const TRUNC = 0x00100000; + pub const NOFOLLOW = 0x10000000; + /// The filesystem holding the watched file was unmounted. + pub const UNMOUNTED = 0x20000000; + /// Some other file/filesystem got mounted over the watched file/directory. + pub const MOUNTEDOVER = 0x40000000; + + pub fn isException(event: u32) bool { + return event & (UNMOUNTED | DELETE | RENAME_TO | RENAME_FROM | MOUNTEDOVER) > 0; + } +}; + +pub const port_event = extern struct { + events: u32, + /// Event source. + source: u16, + __pad: u16, + /// Source-specific object. + object: ?*c_void, + /// User cookie. + cookie: ?*c_void, +}; + +pub const port_notify = extern struct { + /// Bind request(s) to port. + port: u32, + /// User defined variable. + user: ?*void, +}; + +pub const file_obj = extern struct { + /// Access time. + atim: timespec, + /// Modification time + mtim: timespec, + /// Change time + ctim: timespec, + __pad: [3]usize, + name: [*:0]u8, +}; + +// struct ifreq is marked obsolete, with struct lifreq prefered for interface requests. +// Here we alias lifreq to ifreq to avoid chainging existing code in os and x.os.IPv6. +pub const SIOCGLIFINDEX = IOWR('i', 133, lifreq); +pub const SIOCGIFINDEX = SIOCGLIFINDEX; +pub const MAX_HDW_LEN = 64; +pub const IFNAMESIZE = 32; + +pub const lif_nd_req = extern struct { + addr: sockaddr.storage, + state_create: u8, + state_same_lla: u8, + state_diff_lla: u8, + hdw_len: i32, + flags: i32, + __pad: i32, + hdw_addr: [MAX_HDW_LEN]u8, +}; + +pub const lif_ifinfo_req = extern struct { + maxhops: u8, + reachtime: u32, + reachretrans: u32, + maxmtu: u32, +}; + +/// IP interface request. See if_tcp(7p) for more info. +pub const lifreq = extern struct { + // Not actually in a union, but the stdlib expects one for ifreq + ifrn: extern union { + /// Interface name, e.g. "lo0", "en0". + name: [IFNAMESIZE]u8, + }, + ru1: extern union { + /// For subnet/token etc. + addrlen: i32, + /// Driver's PPA (physical point of attachment). + ppa: u32, + }, + /// One of the IFT types, e.g. IFT_ETHER. + @"type": u32, + ifru: extern union { + /// Address. + addr: sockaddr.storage, + /// Other end of a peer-to-peer link. + dstaddr: sockaddr.storage, + /// Broadcast address. + broadaddr: sockaddr.storage, + /// Address token. + token: sockaddr.storage, + /// Subnet prefix. + subnet: sockaddr.storage, + /// Interface index. + ivalue: i32, + /// Flags for SIOC?LIFFLAGS. + flags: u64, + /// Hop count metric + metric: i32, + /// Maximum transmission unit + mtu: u32, + // Technically [2]i32 + muxid: packed struct { ip: i32, arp: i32 }, + /// Neighbor reachability determination entries + nd_req: lif_nd_req, + /// Link info + ifinfo_req: lif_ifinfo_req, + /// Name of the multipath interface group + groupname: [IFNAMESIZE]u8, + binding: [IFNAMESIZE]u8, + /// Zone id associated with this interface. + zoneid: zoneid_t, + /// Duplicate address detection state. Either in progress or completed. + dadstate: u32, + }, +}; + +pub const ifreq = lifreq; + +const IoCtlCommand = enum(u32) { + none = 0x20000000, // no parameters + write = 0x40000000, // copy out parameters + read = 0x80000000, // copy in parameters + read_write = 0xc0000000, +}; + +fn ioImpl(cmd: IoCtlCommand, io_type: u8, nr: u8, comptime IOT: type) i32 { + const size = @intCast(u32, @truncate(u8, @sizeOf(IOT))) << 16; + const t = @intCast(u32, io_type) << 8; + return @bitCast(i32, @enumToInt(cmd) | size | t | nr); +} + +pub fn IO(io_type: u8, nr: u8) i32 { + return ioImpl(.none, io_type, nr, void); +} + +pub fn IOR(io_type: u8, nr: u8, comptime IOT: type) i32 { + return ioImpl(.write, io_type, nr, IOT); +} + +pub fn IOW(io_type: u8, nr: u8, comptime IOT: type) i32 { + return ioImpl(.read, io_type, nr, IOT); +} + +pub fn IOWR(io_type: u8, nr: u8, comptime IOT: type) i32 { + return ioImpl(.read_write, io_type, nr, IOT); +} diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 8517703566..6e2cef1f0c 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -654,6 +654,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { .openbsd, .macos, .windows, + .solaris, => return DebugInfo.init(allocator), else => return error.UnsupportedDebugInfo, } @@ -1420,7 +1421,7 @@ pub const ModuleDebugInfo = switch (native_os) { }; } }, - .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku => struct { + .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct { base_address: usize, dwarf: DW.DwarfInfo, mapped_memory: []const u8, @@ -1468,7 +1469,7 @@ fn getDebugInfoAllocator() *mem.Allocator { /// Whether or not the current target can print useful debug information when a segfault occurs. pub const have_segfault_handling_support = switch (native_os) { - .linux, .netbsd => true, + .linux, .netbsd, .solaris => true, .windows => true, .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"), else => false, @@ -1535,6 +1536,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v .freebsd => @ptrToInt(info.addr), .netbsd => @ptrToInt(info.info.reason.fault.addr), .openbsd => @ptrToInt(info.data.fault.addr), + .solaris => @ptrToInt(info.reason.fault.addr), else => unreachable, }; @@ -1559,13 +1561,13 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const c_v .x86_64 => { const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr)); const ip = switch (native_os) { - .linux, .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]), + .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]), .freebsd => @intCast(usize, ctx.mcontext.rip), .openbsd => @intCast(usize, ctx.sc_rip), else => unreachable, }; const bp = switch (native_os) { - .linux, .netbsd => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]), + .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]), .openbsd => @intCast(usize, ctx.sc_rbp), .freebsd => @intCast(usize, ctx.mcontext.rbp), else => unreachable, diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index fb4cefed0a..91c66503f1 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -14,7 +14,7 @@ const max = std.math.max; pub const DynLib = switch (builtin.os.tag) { .linux => if (builtin.link_libc) DlDynlib else ElfDynLib, .windows => WindowsDynLib, - .macos, .tvos, .watchos, .ios, .freebsd, .netbsd, .openbsd, .dragonfly => DlDynlib, + .macos, .tvos, .watchos, .ios, .freebsd, .netbsd, .openbsd, .dragonfly, .solaris => DlDynlib, else => void, }; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 66eb1d6642..7aa5dd3976 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -35,7 +35,7 @@ pub const Watch = @import("fs/watch.zig").Watch; /// fit into a UTF-8 encoded array of this length. /// The byte count includes room for a null sentinel byte. pub const MAX_PATH_BYTES = switch (builtin.os.tag) { - .linux, .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .haiku => os.PATH_MAX, + .linux, .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .haiku, .solaris => os.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. // If it would require 4 UTF-8 bytes, then there would be a surrogate // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. @@ -298,10 +298,10 @@ pub const Dir = struct { pub const Kind = File.Kind; }; - const IteratorError = error{AccessDenied} || os.UnexpectedError; + const IteratorError = error{ AccessDenied, SystemResources } || os.UnexpectedError; pub const Iterator = switch (builtin.os.tag) { - .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd => struct { + .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => struct { dir: Dir, seek: i64, buf: [8192]u8, // TODO align(@alignOf(os.system.dirent)), @@ -318,6 +318,7 @@ pub const Dir = struct { switch (builtin.os.tag) { .macos, .ios => return self.nextDarwin(), .freebsd, .netbsd, .dragonfly, .openbsd => return self.nextBsd(), + .solaris => return self.nextSolaris(), else => @compileError("unimplemented"), } } @@ -372,6 +373,60 @@ pub const Dir = struct { } } + fn nextSolaris(self: *Self) !?Entry { + start_over: while (true) { + if (self.index >= self.end_index) { + const rc = os.system.getdents(self.dir.fd, &self.buf, self.buf.len); + switch (os.errno(rc)) { + .SUCCESS => {}, + .BADF => unreachable, // Dir is invalid or was opened without iteration ability + .FAULT => unreachable, + .NOTDIR => unreachable, + .INVAL => unreachable, + else => |err| return os.unexpectedErrno(err), + } + if (rc == 0) return null; + self.index = 0; + self.end_index = @intCast(usize, rc); + } + const entry = @ptrCast(*align(1) os.system.dirent, &self.buf[self.index]); + const next_index = self.index + entry.reclen(); + self.index = next_index; + + const name = mem.spanZ(@ptrCast([*:0]u8, &entry.d_name)); + if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) + continue :start_over; + + // Solaris dirent doesn't expose d_type, so we have to call stat to get it. + const stat_info = os.fstatat( + self.dir.fd, + name, + os.AT.SYMLINK_NOFOLLOW, + ) catch |err| switch (err) { + error.NameTooLong => unreachable, + error.SymLinkLoop => unreachable, + error.FileNotFound => unreachable, // lost the race + else => |e| return e, + }; + const entry_kind = switch (stat_info.mode & os.S.IFMT) { + os.S.IFIFO => Entry.Kind.NamedPipe, + os.S.IFCHR => Entry.Kind.CharacterDevice, + os.S.IFDIR => Entry.Kind.Directory, + os.S.IFBLK => Entry.Kind.BlockDevice, + os.S.IFREG => Entry.Kind.File, + os.S.IFLNK => Entry.Kind.SymLink, + os.S.IFSOCK => Entry.Kind.UnixDomainSocket, + os.S.IFDOOR => Entry.Kind.Door, + os.S.IFPORT => Entry.Kind.EventPort, + else => Entry.Kind.Unknown, + }; + return Entry{ + .name = name, + .kind = entry_kind, + }; + } + } + fn nextBsd(self: *Self) !?Entry { start_over: while (true) { if (self.index >= self.end_index) { @@ -704,6 +759,7 @@ pub const Dir = struct { .netbsd, .dragonfly, .openbsd, + .solaris, => return Iterator{ .dir = self, .seek = 0, @@ -1556,7 +1612,7 @@ pub const Dir = struct { error.AccessDenied => |e| switch (builtin.os.tag) { // non-Linux POSIX systems return EPERM when trying to delete a directory, so // we need to handle that case specifically and translate the error - .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd => { + .macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => { // Don't follow symlinks to match unlinkat (which acts on symlinks rather than follows them) const fstat = os.fstatatZ(self.fd, sub_path_c, os.AT.SYMLINK_NOFOLLOW) catch return e; const is_dir = fstat.mode & os.S.IFMT == os.S.IFDIR; @@ -2441,6 +2497,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { } switch (builtin.os.tag) { .linux => return os.readlinkZ("/proc/self/exe", out_buffer), + .solaris => return os.readlinkZ("/proc/self/path/a.out", out_buffer), .freebsd, .dragonfly => { var mib = [4]c_int{ os.CTL.KERN, os.KERN.PROC, os.KERN.PROC_PATHNAME, -1 }; var out_len: usize = out_buffer.len; diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index d08b743919..fd0492f0bf 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -41,6 +41,8 @@ pub const File = struct { File, UnixDomainSocket, Whiteout, + Door, + EventPort, Unknown, }; @@ -320,28 +322,40 @@ pub const File = struct { const atime = st.atime(); const mtime = st.mtime(); const ctime = st.ctime(); + const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) { + .BLOCK_DEVICE => Kind.BlockDevice, + .CHARACTER_DEVICE => Kind.CharacterDevice, + .DIRECTORY => Kind.Directory, + .SYMBOLIC_LINK => Kind.SymLink, + .REGULAR_FILE => Kind.File, + .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket, + else => Kind.Unknown, + } else blk: { + const m = st.mode & os.S.IFMT; + switch (m) { + os.S.IFBLK => break :blk Kind.BlockDevice, + os.S.IFCHR => break :blk Kind.CharacterDevice, + os.S.IFDIR => break :blk Kind.Directory, + os.S.IFIFO => break :blk Kind.NamedPipe, + os.S.IFLNK => break :blk Kind.SymLink, + os.S.IFREG => break :blk Kind.File, + os.S.IFSOCK => break :blk Kind.UnixDomainSocket, + else => {}, + } + if (builtin.os.tag == .solaris) switch (m) { + os.S.IFDOOR => break :blk Kind.Door, + os.S.IFPORT => break :blk Kind.EventPort, + else => {}, + }; + + break :blk .Unknown; + }; + return Stat{ .inode = st.ino, .size = @bitCast(u64, st.size), .mode = st.mode, - .kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) { - .BLOCK_DEVICE => Kind.BlockDevice, - .CHARACTER_DEVICE => Kind.CharacterDevice, - .DIRECTORY => Kind.Directory, - .SYMBOLIC_LINK => Kind.SymLink, - .REGULAR_FILE => Kind.File, - .SOCKET_STREAM, .SOCKET_DGRAM => Kind.UnixDomainSocket, - else => Kind.Unknown, - } else switch (st.mode & os.S.IFMT) { - os.S.IFBLK => Kind.BlockDevice, - os.S.IFCHR => Kind.CharacterDevice, - os.S.IFDIR => Kind.Directory, - os.S.IFIFO => Kind.NamedPipe, - os.S.IFLNK => Kind.SymLink, - os.S.IFREG => Kind.File, - os.S.IFSOCK => Kind.UnixDomainSocket, - else => Kind.Unknown, - }, + .kind = kind, .atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec, .mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec, .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, diff --git a/lib/std/fs/get_app_data_dir.zig b/lib/std/fs/get_app_data_dir.zig index fed1c85f39..491b6fe824 100644 --- a/lib/std/fs/get_app_data_dir.zig +++ b/lib/std/fs/get_app_data_dir.zig @@ -44,7 +44,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD }; return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname }); }, - .linux, .freebsd, .netbsd, .dragonfly, .openbsd => { + .linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => { const home_dir = os.getenv("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 0ce416454b..a6e1e440fd 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -188,7 +188,7 @@ fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool { test "Dir.realpath smoke test" { switch (builtin.os.tag) { - .linux, .windows, .macos, .ios, .watchos, .tvos => {}, + .linux, .windows, .macos, .ios, .watchos, .tvos, .solaris => {}, else => return error.SkipZigTest, } diff --git a/lib/std/os.zig b/lib/std/os.zig index 5a4828286d..d85815dde0 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -31,6 +31,7 @@ pub const freebsd = std.c; pub const haiku = std.c; pub const netbsd = std.c; pub const openbsd = std.c; +pub const solaris = std.c; pub const linux = @import("os/linux.zig"); pub const uefi = @import("os/uefi.zig"); pub const wasi = @import("os/wasi.zig"); @@ -64,8 +65,10 @@ else switch (builtin.os.tag) { }; pub const AF = system.AF; +pub const AF_SUN = system.AF_SUN; pub const ARCH = system.ARCH; pub const AT = system.AT; +pub const AT_SUN = system.AT_SUN; pub const CLOCK = system.CLOCK; pub const CPU_COUNT = system.CPU_COUNT; pub const CTL = system.CTL; @@ -101,6 +104,7 @@ pub const RR = system.RR; pub const S = system.S; pub const SA = system.SA; pub const SC = system.SC; +pub const _SC = system._SC; pub const SEEK = system.SEEK; pub const SHUT = system.SHUT; pub const SIG = system.SIG; @@ -143,6 +147,10 @@ pub const off_t = system.off_t; pub const oflags_t = system.oflags_t; pub const pid_t = system.pid_t; pub const pollfd = system.pollfd; +pub const port_t = system.port_t; +pub const port_event = system.port_event; +pub const port_notify = system.port_notify; +pub const file_obj = system.file_obj; pub const rights_t = system.rights_t; pub const rlim_t = system.rlim_t; pub const rlimit = system.rlimit; @@ -2038,6 +2046,7 @@ pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatEr .NOTDIR => return error.NotDir, .NOMEM => return error.SystemResources, .ROFS => return error.ReadOnlyFileSystem, + .EXIST => return error.DirNotEmpty, .NOTEMPTY => return error.DirNotEmpty, .INVAL => unreachable, // invalid flags, or pathname has . as last component @@ -4667,6 +4676,16 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { }; return target; }, + .solaris => { + var procfs_buf: ["/proc/self/path/-2147483648".len:0]u8 = undefined; + const proc_path = std.fmt.bufPrintZ(procfs_buf[0..], "/proc/self/path/{d}", .{fd}) catch unreachable; + + const target = readlinkZ(proc_path, out_buffer) catch |err| switch (err) { + error.UnsupportedReparsePointType => unreachable, + else => |e| return e, + }; + return target; + }, else => @compileError("querying for canonical path of a handle is unsupported on this host"), } } diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 3a0187f735..d3c8d13bd1 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -188,7 +188,10 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void { } test "link with relative paths" { - if (native_os != .linux) return error.SkipZigTest; + switch (native_os) { + .linux, .solaris => {}, + else => return error.SkipZigTest, + } var cwd = fs.cwd(); cwd.deleteFile("example.txt") catch {}; @@ -222,7 +225,10 @@ test "link with relative paths" { } test "linkat with different directories" { - if (native_os != .linux) return error.SkipZigTest; + switch (native_os) { + .linux, .solaris => {}, + else => return error.SkipZigTest, + } var cwd = fs.cwd(); var tmp = tmpDir(.{}); @@ -634,8 +640,10 @@ test "fcntl" { } test "signalfd" { - if (native_os != .linux) - return error.SkipZigTest; + switch (native_os) { + .linux, .solaris => {}, + else => return error.SkipZigTest, + } _ = std.os.signalfd; } @@ -658,8 +666,10 @@ test "sync" { } test "fsync" { - if (native_os != .linux and native_os != .windows) - return error.SkipZigTest; + switch (native_os) { + .linux, .windows, .solaris => {}, + else => return error.SkipZigTest, + } var tmp = tmpDir(.{}); defer tmp.cleanup(); @@ -754,7 +764,10 @@ test "sigaction" { } test "dup & dup2" { - if (native_os != .linux) return error.SkipZigTest; + switch (native_os) { + .linux, .solaris => {}, + else => return error.SkipZigTest, + } var tmp = tmpDir(.{}); defer tmp.cleanup(); diff --git a/lib/std/process.zig b/lib/std/process.zig index f8b986d695..8dce2462a2 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -625,7 +625,7 @@ pub const UserInfo = struct { /// POSIX function which gets a uid from username. pub fn getUserInfo(name: []const u8) !UserInfo { return switch (builtin.os.tag) { - .linux, .macos, .watchos, .tvos, .ios, .freebsd, .netbsd, .openbsd, .haiku => posixGetUserInfo(name), + .linux, .macos, .watchos, .tvos, .ios, .freebsd, .netbsd, .openbsd, .haiku, .solaris => posixGetUserInfo(name), else => @compileError("Unsupported OS"), }; } @@ -753,6 +753,7 @@ pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0] .netbsd, .dragonfly, .openbsd, + .solaris, => { var paths = List.init(allocator); errdefer { diff --git a/lib/std/target.zig b/lib/std/target.zig index c94b7a4386..65c9b91839 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -235,7 +235,6 @@ pub const Target = struct { .fuchsia, .kfreebsd, .lv2, - .solaris, .zos, .haiku, .minix, @@ -310,6 +309,12 @@ pub const Target = struct { .max = .{ .major = 6, .minor = 0 }, }, }, + .solaris => return .{ + .semver = .{ + .min = .{ .major = 5, .minor = 11 }, + .max = .{ .major = 5, .minor = 11 }, + }, + }, .linux => return .{ .linux = .{ @@ -353,6 +358,7 @@ pub const Target = struct { .netbsd, .openbsd, .dragonfly, + .solaris, => return TaggedVersionRange{ .semver = self.version_range.semver }, else => return .none, @@ -385,6 +391,7 @@ pub const Target = struct { .dragonfly, .openbsd, .haiku, + .solaris, => true, .linux, @@ -395,7 +402,6 @@ pub const Target = struct { .fuchsia, .kfreebsd, .lv2, - .solaris, .zos, .minix, .rtems, @@ -1516,6 +1522,7 @@ pub const Target = struct { .netbsd => return copy(&result, "/libexec/ld.elf_so"), .openbsd => return copy(&result, "/usr/libexec/ld.so"), .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"), + .solaris => return copy(&result, "/lib/64/ld.so.1"), .linux => switch (self.cpu.arch) { .i386, .sparc, @@ -1634,7 +1641,6 @@ pub const Target = struct { .fuchsia, .kfreebsd, .lv2, - .solaris, .zos, .minix, .rtems, diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index da4057d6e1..a86d6a2d45 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -101,6 +101,17 @@ pub const NativePaths = struct { return self; } + if (comptime native_target.os.tag == .solaris) { + try self.addLibDir("/usr/lib/64"); + try self.addLibDir("/usr/local/lib/64"); + try self.addLibDir("/lib/64"); + + try self.addIncludeDir("/usr/include"); + try self.addIncludeDir("/usr/local/include"); + + return self; + } + if (native_target.os.tag != .windows) { const triple = try native_target.linuxTriple(allocator); const qual = native_target.cpu.arch.ptrBitWidth(); @@ -243,6 +254,18 @@ pub const NativeTargetInfo = struct { error.InvalidVersion => {}, } }, + .solaris => { + const uts = std.os.uname(); + const release = mem.spanZ(&uts.release); + if (std.builtin.Version.parse(release)) |ver| { + os.version_range.semver.min = ver; + os.version_range.semver.max = ver; + } else |err| switch (err) { + error.Overflow => {}, + error.InvalidCharacter => {}, + error.InvalidVersion => {}, + } + }, .windows => { const detected_version = windows.detectRuntimeVersion(); os.version_range.windows.min = detected_version; diff --git a/src/libc_installation.zig b/src/libc_installation.zig index 62174930f8..d54af71415 100644 --- a/src/libc_installation.zig +++ b/src/libc_installation.zig @@ -221,6 +221,7 @@ pub const LibCInstallation = struct { batch.add(&async self.findNativeIncludeDirPosix(args)); switch (Target.current.os.tag) { .freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"), + .solaris => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib/64"), .linux => batch.add(&async self.findNativeCrtDirPosix(args)), else => {}, } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ec047ced35..6c3220d39e 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3446,6 +3446,15 @@ const CsuObjects = struct { .static_pie => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ), // zig fmt: on }, + .solaris => switch (mode) { + // zig fmt: off + .dynamic_lib => result.set( null, "crti.o", null, null, "crtn.o" ), + .dynamic_exe, + .dynamic_pie => result.set( "crt1.o", "crti.o", null, null, "crtn.o" ), + .static_exe, + .static_pie => result.set( null, null, null, null, null ), + // zig fmt: on + }, else => {}, } } diff --git a/src/stage1/os.hpp b/src/stage1/os.hpp index f1022778d4..6d086c8901 100644 --- a/src/stage1/os.hpp +++ b/src/stage1/os.hpp @@ -33,6 +33,8 @@ #define ZIG_OS_OPENBSD #elif defined(__HAIKU__) #define ZIG_OS_HAIKU +#elif defined(__sun) +#define ZIG_OS_SOLARIS #else #define ZIG_OS_UNKNOWN #endif diff --git a/src/stage1/target.cpp b/src/stage1/target.cpp index 8415b1934e..4da19e4c36 100644 --- a/src/stage1/target.cpp +++ b/src/stage1/target.cpp @@ -399,6 +399,9 @@ Error target_parse_os(Os *out_os, const char *os_ptr, size_t os_len) { #elif defined(ZIG_OS_HAIKU) *out_os = OsHaiku; return ErrorNone; +#elif defined(ZIG_OS_SOLARIS) + *out_os = OsSolaris; + return ErrorNone; #else zig_panic("stage1 is unable to detect native target for this OS"); #endif @@ -670,6 +673,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case OsOpenBSD: case OsWASI: case OsHaiku: + case OsSolaris: case OsEmscripten: case OsPlan9: switch (id) { @@ -728,7 +732,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { case OsCloudABI: case OsKFreeBSD: case OsLv2: - case OsSolaris: case OsZOS: case OsMinix: case OsRTEMS: diff --git a/src/target.zig b/src/target.zig index 09e65ff909..621335209c 100644 --- a/src/target.zig +++ b/src/target.zig @@ -433,6 +433,13 @@ pub fn libcFullLinkFlags(target: std.Target) []const []const u8 { "-lc", "-lutil", }, + .solaris => &[_][]const u8{ + "-lm", + "-lsocket", + "-lnsl", + // Solaris releases after 10 merged the threading libraries into libc. + "-lc", + }, .haiku => &[_][]const u8{ "-lm", "-lroot", diff --git a/src/type.zig b/src/type.zig index 4a0f2a0536..a2da252f61 100644 --- a/src/type.zig +++ b/src/type.zig @@ -3800,6 +3800,7 @@ pub const CType = enum { .wasi, .emscripten, .plan9, + .solaris, => switch (self) { .short, .ushort, @@ -3851,7 +3852,6 @@ pub const CType = enum { .fuchsia, .kfreebsd, .lv2, - .solaris, .zos, .haiku, .minix,