From f33a610c84313255477cc04d930b02ad984118ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 08:23:36 +0000 Subject: [PATCH 1/8] add minimal openbsd support --- lib/std/c.zig | 2 +- lib/std/c/openbsd.zig | 23 + lib/std/debug.zig | 3 +- lib/std/dynamic_library.zig | 4 +- lib/std/event/loop.zig | 23 +- lib/std/fs.zig | 62 +- lib/std/fs/get_app_data_dir.zig | 2 +- lib/std/fs/watch.zig | 8 +- lib/std/os.zig | 7 + lib/std/os/bits.zig | 1 + lib/std/os/bits/openbsd.zig | 1052 +++++++++++++++++++++++++++++++ lib/std/os/openbsd.zig | 8 + lib/std/packed_int_array.zig | 4 +- lib/std/process.zig | 3 +- lib/std/target.zig | 6 +- lib/std/zig/cross_target.zig | 4 + src/libc_installation.zig | 2 +- src/link/Elf.zig | 26 +- src/stage1/os.cpp | 4 +- src/stage1/os.hpp | 2 + src/target.zig | 4 +- 21 files changed, 1208 insertions(+), 42 deletions(-) create mode 100644 lib/std/os/bits/openbsd.zig create mode 100644 lib/std/os/openbsd.zig diff --git a/lib/std/c.zig b/lib/std/c.zig index a75fcaa84..fa86e9ef5 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -249,7 +249,7 @@ pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void; pub extern "c" fn malloc(usize) ?*c_void; pub usingnamespace switch (builtin.os.tag) { - .linux, .freebsd, .kfreebsd, .netbsd, .openbsd => struct { + .linux, .freebsd, .kfreebsd, .netbsd => struct { pub extern "c" fn malloc_usable_size(?*const c_void) usize; }, .macosx, .ios, .watchos, .tvos => struct { diff --git a/lib/std/c/openbsd.zig b/lib/std/c/openbsd.zig index 8a6439fc8..f31ab71ee 100644 --- a/lib/std/c/openbsd.zig +++ b/lib/std/c/openbsd.zig @@ -3,9 +3,32 @@ // This file is part of [zig](https://ziglang.org/), which is MIT licensed. // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. +const std = @import("../std.zig"); +const builtin = std.builtin; + +usingnamespace std.c; + +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 arc4random_buf(buf: [*]u8, len: usize) void; + +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 const pthread_mutex_t = extern struct { inner: ?*c_void = null, }; pub const pthread_cond_t = extern struct { inner: ?*c_void = null, }; +pub const pthread_spinlock_t = extern struct { + inner: ?*c_void = null, +}; + +pub const pthread_attr_t = extern struct { + inner: ?*c_void = null, +}; diff --git a/lib/std/debug.zig b/lib/std/debug.zig index be57c0b2f..65300a31b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -654,6 +654,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { .freebsd, .netbsd, .dragonfly, + .openbsd, .macosx, .windows, => return DebugInfo.init(allocator), @@ -1640,7 +1641,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) { }; } }, - .linux, .netbsd, .freebsd, .dragonfly => struct { + .linux, .netbsd, .freebsd, .dragonfly, .openbsd => struct { base_address: usize, dwarf: DW.DwarfInfo, mapped_memory: []const u8, diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 238854f07..0c7d98e00 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -19,7 +19,7 @@ const max = std.math.max; pub const DynLib = switch (builtin.os.tag) { .linux => if (builtin.link_libc) DlDynlib else ElfDynLib, .windows => WindowsDynLib, - .macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib, + .macosx, .tvos, .watchos, .ios, .freebsd, .openbsd => DlDynlib, else => void, }; @@ -402,7 +402,7 @@ pub const DlDynlib = struct { test "dynamic_library" { const libname = switch (builtin.os.tag) { - .linux, .freebsd => "invalid_so.so", + .linux, .freebsd, .openbsd => "invalid_so.so", .windows => "invalid_dll.dll", .macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib", else => return error.SkipZigTest, diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index a064f711e..7fa6fee39 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -66,7 +66,7 @@ pub const Loop = struct { }; pub const EventFd = switch (builtin.os.tag) { - .macosx, .freebsd, .netbsd, .dragonfly => KEventFd, + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => KEventFd, .linux => struct { base: ResumeNode, epoll_op: u32, @@ -85,7 +85,7 @@ pub const Loop = struct { }; pub const Basic = switch (builtin.os.tag) { - .macosx, .freebsd, .netbsd, .dragonfly => KEventBasic, + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => KEventBasic, .linux => struct { base: ResumeNode, }, @@ -259,7 +259,7 @@ pub const Loop = struct { self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun); } }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { self.os_data.kqfd = try os.kqueue(); errdefer os.close(self.os_data.kqfd); @@ -384,7 +384,7 @@ pub const Loop = struct { while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd); os.close(self.os_data.epollfd); }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { os.close(self.os_data.kqfd); }, .windows => { @@ -478,7 +478,7 @@ pub const Loop = struct { .linux => { self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLIN); }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT); }, else => @compileError("Unsupported OS"), @@ -490,7 +490,7 @@ pub const Loop = struct { .linux => { self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT); }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_WRITE, os.EV_ONESHOT); }, else => @compileError("Unsupported OS"), @@ -502,7 +502,7 @@ pub const Loop = struct { .linux => { self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN); }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT); self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_WRITE, os.EV_ONESHOT); }, @@ -571,7 +571,7 @@ pub const Loop = struct { const eventfd_node = &resume_stack_node.data; eventfd_node.base.handle = next_tick_node.data; switch (builtin.os.tag) { - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { const kevent_array = @as(*const [1]os.Kevent, &eventfd_node.kevent); const empty_kevs = &[0]os.Kevent{}; _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { @@ -637,6 +637,7 @@ pub const Loop = struct { .freebsd, .netbsd, .dragonfly, + .openbsd, => self.fs_thread.wait(), else => {}, } @@ -725,7 +726,7 @@ pub const Loop = struct { } return; }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { const final_kevent = @as(*const [1]os.Kevent, &self.os_data.final_kevent); const empty_kevs = &[0]os.Kevent{}; // cannot fail because we already added it and this just enables it @@ -1218,7 +1219,7 @@ pub const Loop = struct { } } }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { var eventlist: [1]os.Kevent = undefined; const empty_kevs = &[0]os.Kevent{}; const count = os.kevent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable; @@ -1344,7 +1345,7 @@ pub const Loop = struct { const OsData = switch (builtin.os.tag) { .linux => LinuxOsData, - .macosx, .freebsd, .netbsd, .dragonfly => KEventData, + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => KEventData, .windows => struct { io_port: windows.HANDLE, extra_thread_count: usize, diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 0f8c6e0d2..6e0b9b43e 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -39,7 +39,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, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, + .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly, .openbsd => 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. @@ -303,7 +303,7 @@ pub const Dir = struct { const IteratorError = error{AccessDenied} || os.UnexpectedError; pub const Iterator = switch (builtin.os.tag) { - .macosx, .ios, .freebsd, .netbsd, .dragonfly => struct { + .macosx, .ios, .freebsd, .netbsd, .dragonfly, .openbsd => struct { dir: Dir, seek: i64, buf: [8192]u8, // TODO align(@alignOf(os.dirent)), @@ -319,7 +319,7 @@ pub const Dir = struct { pub fn next(self: *Self) Error!?Entry { switch (builtin.os.tag) { .macosx, .ios => return self.nextDarwin(), - .freebsd, .netbsd, .dragonfly => return self.nextBsd(), + .freebsd, .netbsd, .dragonfly, .openbsd => return self.nextBsd(), else => @compileError("unimplemented"), } } @@ -615,7 +615,7 @@ pub const Dir = struct { pub fn iterate(self: Dir) Iterator { switch (builtin.os.tag) { - .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{ + .macosx, .ios, .freebsd, .netbsd, .dragonfly, .openbsd => return Iterator{ .dir = self, .seek = 0, .index = 0, @@ -1302,7 +1302,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 - .macosx, .ios, .freebsd, .netbsd, .dragonfly => { + .macosx, .ios, .freebsd, .netbsd, .dragonfly, .openbsd => { // 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; @@ -2177,6 +2177,14 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathError; +fn str_containsZ(s: [*:0]const u8, c: u8) bool { + var i: usize = 0; + while (s[i] != '\x00' and s[i] != c) { + i += 1; + } + return (s[i] == '/'); +} + /// `selfExePath` except allocates the result on the heap. /// Caller owns returned memory. pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { @@ -2232,6 +2240,50 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { // TODO could this slice from 0 to out_len instead? return mem.spanZ(@ptrCast([*:0]u8, out_buffer)); }, + .openbsd => { + // OpenBSD doesn't support getting the path of a running process, so try to guess it + if (os.argv.len >= 1) { + if (str_containsZ(os.argv[0], '/')) { + // argv[0] is a path (relative or absolute): use realpath(3) directly + var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; + const real_path = try os.realpathZ(os.argv[0], &real_path_buf); + if (real_path.len > out_buffer.len) + return error.NameTooLong; + mem.copy(u8, out_buffer, real_path); + return out_buffer[0..real_path.len]; + + } else if (os.argv[0][0] != '\x00') { + // argv[0] is not empty (and not a path): search it inside PATH + const paths = std.os.getenv("PATH") orelse ""; + var path_it = mem.split(paths, ":"); + while (path_it.next()) |a_path| { + var resolved_path_buf: [MAX_PATH_BYTES:0]u8 = undefined; + const resolved_path = std.fmt.bufPrint(&resolved_path_buf, "{}/{}\x00", .{ + a_path, + os.argv[0], + }) catch ""; + + var real_path_buf: [MAX_PATH_BYTES:0]u8 = undefined; + if (os.realpathZ(&resolved_path_buf, &real_path_buf) catch null) |real_path| { + // found a file, and hope it is the right file + if (real_path.len > out_buffer.len) + return error.NameTooLong; + mem.copy(u8, out_buffer, real_path); + return out_buffer[0..real_path.len]; + } + } + } + } + + if (os.getenv("_")) |sh_exefile| { + // sh (or bash) sets "_" environment variable + mem.copy(u8, out_buffer, sh_exefile); + return out_buffer[0..sh_exefile.len]; + } + + // sorry, we don't find it + return error.FileNotFound; + }, .windows => { const utf16le_slice = selfExePathW(); // Trust that Windows gives us valid UTF-16LE. diff --git a/lib/std/fs/get_app_data_dir.zig b/lib/std/fs/get_app_data_dir.zig index 17d365f68..afee04c08 100644 --- a/lib/std/fs/get_app_data_dir.zig +++ b/lib/std/fs/get_app_data_dir.zig @@ -49,7 +49,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 => { + .linux, .freebsd, .netbsd, .dragonfly, .openbsd => { const home_dir = os.getenv("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig index 269cdec6d..447ea5f54 100644 --- a/lib/std/fs/watch.zig +++ b/lib/std/fs/watch.zig @@ -49,7 +49,7 @@ pub fn Watch(comptime V: type) type { const OsData = switch (builtin.os.tag) { // TODO https://github.com/ziglang/zig/issues/3778 - .macosx, .freebsd, .netbsd, .dragonfly => KqOsData, + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => KqOsData, .linux => LinuxOsData, .windows => WindowsOsData, @@ -160,7 +160,7 @@ pub fn Watch(comptime V: type) type { return self; }, - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { self.* = Self{ .allocator = allocator, .channel = channel, @@ -178,7 +178,7 @@ pub fn Watch(comptime V: type) type { /// All addFile calls and removeFile calls must have completed. pub fn deinit(self: *Self) void { switch (builtin.os.tag) { - .macosx, .freebsd, .netbsd, .dragonfly => { + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => { // TODO we need to cancel the frames before destroying the lock self.os_data.table_lock.deinit(); var it = self.os_data.file_table.iterator(); @@ -229,7 +229,7 @@ pub fn Watch(comptime V: type) type { pub fn addFile(self: *Self, file_path: []const u8, value: V) !?V { switch (builtin.os.tag) { - .macosx, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value), + .macosx, .freebsd, .netbsd, .dragonfly, .openbsd => return addFileKEvent(self, file_path, value), .linux => return addFileLinux(self, file_path, value), .windows => return addFileWindows(self, file_path, value), else => @compileError("Unsupported OS"), diff --git a/lib/std/os.zig b/lib/std/os.zig index 9f6c01209..7558e7947 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -33,6 +33,7 @@ pub const darwin = @import("os/darwin.zig"); pub const dragonfly = @import("os/dragonfly.zig"); pub const freebsd = @import("os/freebsd.zig"); pub const netbsd = @import("os/netbsd.zig"); +pub const openbsd = @import("os/openbsd.zig"); pub const linux = @import("os/linux.zig"); pub const uefi = @import("os/uefi.zig"); pub const wasi = @import("os/wasi.zig"); @@ -47,6 +48,7 @@ test "" { _ = freebsd; _ = linux; _ = netbsd; + _ = openbsd; _ = uefi; _ = wasi; _ = windows; @@ -66,6 +68,7 @@ else switch (builtin.os.tag) { .freebsd => freebsd, .linux => linux, .netbsd => netbsd, + .openbsd => openbsd, .dragonfly => dragonfly, .wasi => wasi, .windows => windows, @@ -165,6 +168,10 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { netbsd.arc4random_buf(buffer.ptr, buffer.len); return; } + if (builtin.os.tag == .openbsd) { + openbsd.arc4random_buf(buffer.ptr, buffer.len); + return; + } if (builtin.os.tag == .wasi) { switch (wasi.random_get(buffer.ptr, buffer.len)) { 0 => return, diff --git a/lib/std/os/bits.zig b/lib/std/os/bits.zig index 177b7daad..ef0fc6ec4 100644 --- a/lib/std/os/bits.zig +++ b/lib/std/os/bits.zig @@ -17,6 +17,7 @@ pub usingnamespace switch (std.Target.current.os.tag) { .freebsd => @import("bits/freebsd.zig"), .linux => @import("bits/linux.zig"), .netbsd => @import("bits/netbsd.zig"), + .openbsd => @import("bits/openbsd.zig"), .wasi => @import("bits/wasi.zig"), .windows => @import("bits/windows.zig"), else => struct {}, diff --git a/lib/std/os/bits/openbsd.zig b/lib/std/os/bits/openbsd.zig new file mode 100644 index 000000000..a972ea097 --- /dev/null +++ b/lib/std/os/bits/openbsd.zig @@ -0,0 +1,1052 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../../std.zig"); +const builtin = std.builtin; +const maxInt = std.math.maxInt; + +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 uid_t = u32; + +/// Renamed from `kevent` to `Kevent` to avoid conflict with function name. +pub const Kevent = extern struct { + ident: usize, + filter: c_short, + flags: u16, + fflags: c_uint, + data: i64, + udata: usize, +}; + +pub const dl_phdr_info = extern struct { + dlpi_addr: usize, + dlpi_name: ?[*:0]const u8, + dlpi_phdr: [*]std.elf.Phdr, + dlpi_phnum: u16, +}; + +pub const Flock = extern struct { + l_start: off_t, + l_len: off_t, + l_pid: pid_t, + l_type: i16, + l_whence: i16, +}; + +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 = extern enum(c_int) { + /// address family for hostname not supported + ADDRFAMILY = -9, + + /// name could not be resolved at this time + AGAIN = -3, + + /// flags parameter had an invalid value + BADFLAGS = -1, + + /// non-recoverable failure in name resolution + FAIL = -4, + + /// address family not recognized + FAMILY = -6, + + /// memory allocation failure + MEMORY = -10, + + /// no address associated with hostname + NODATA = -5, + + /// name does not resolve + NONAME = -2, + + /// service not recognized for socket type + SERVICE = -8, + + /// intended socket type was not recognized + SOCKTYPE = -7, + + /// system error returned in errno + SYSTEM = -11, + + /// invalid value for hints + BADHINTS = -12, + + /// resolved protocol is unknown + PROTOCOL = -13, + + /// argument buffer overflow + OVERFLOW = -14, + + _, +}; + +pub const EAI_MAX = 15; + +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, +}; + +/// Renamed to Stat to not conflict with the stat function. +/// atime, mtime, and ctime have functions to return `timespec`, +/// because although this is a POSIX API, the layout and names of +/// the structs are inconsistent across operating systems, and +/// in C, macros are used to hide the differences. Here we use +/// methods to accomplish this. +pub const Stat = extern struct { + mode: mode_t, + dev: dev_t, + ino: ino_t, + nlink: nlink_t, + uid: uid_t, + gid: gid_t, + rdev: dev_t, + atim: timespec, + mtim: timespec, + ctim: timespec, + size: off_t, + blocks: blkcnt_t, + blksize: blksize_t, + flags: u32, + gen: u32, + birthtim: timespec, + + pub fn atime(self: Stat) timespec { + return self.atim; + } + + pub fn mtime(self: Stat) timespec { + return self.mtim; + } + + pub fn ctime(self: Stat) timespec { + return self.ctim; + } +}; + +pub const timespec = extern struct { + tv_sec: time_t, + tv_nsec: isize, +}; + +pub const MAXNAMLEN = 255; + +pub const dirent = extern struct { + d_fileno: ino_t, + d_off: off_t, + d_reclen: u16, + d_type: u8, + d_namlen: u8, + __d_padding: [4]u8, + d_name: [MAXNAMLEN+1]u8, + + pub fn reclen(self: dirent) u16 { + return self.d_reclen; + } +}; + +pub const in_port_t = u16; +pub const sa_family_t = u8; + +pub const sockaddr = extern struct { + /// total length + len: u8, + + /// address family + family: sa_family_t, + + /// actually longer; address value + data: [14]u8, +}; + +pub const sockaddr_in = extern struct { + len: u8 = @sizeOf(sockaddr_in), + 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 sockaddr_in6 = extern struct { + len: u8 = @sizeOf(sockaddr_in6), + family: sa_family_t = AF_INET6, + port: in_port_t, + flowinfo: u32, + addr: [16]u8, + scope_id: u32, +}; + +/// Definitions for UNIX IPC domain. +pub const sockaddr_un = extern struct { + /// total sockaddr length + len: u8 = @sizeOf(sockaddr_un), + + /// AF_LOCAL + family: sa_family_t = AF_LOCAL, + + /// path name + path: [104]u8, +}; + +/// get address to use bind() +pub const AI_PASSIVE = 1; + +/// fill ai_canonname +pub const AI_CANONNAME = 2; + +/// prevent host name resolution +pub const AI_NUMERICHOST = 4; + +/// prevent service name resolution +pub const AI_NUMERICSERV = 16; + +/// only if any address is assigned +pub const AI_ADDRCONFIG = 64; + +pub const CTL_KERN = 1; +pub const CTL_DEBUG = 5; + +pub const KERN_PROC_ARGS = 55; +pub const KERN_PROC_ARGV = 1; + +pub const PATH_MAX = 1024; + +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +pub const PROT_NONE = 0; +pub const PROT_READ = 1; +pub const PROT_WRITE = 2; +pub const PROT_EXEC = 4; + +pub const CLOCK_REALTIME = 0; +pub const CLOCK_PROCESS_CPUTIME_ID = 2; +pub const CLOCK_MONOTONIC = 3; +pub const CLOCK_THREAD_CPUTIME_ID = 4; + +pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); +pub const MAP_SHARED = 0x0001; +pub const MAP_PRIVATE = 0x0002; +pub const MAP_FIXED = 0x0010; +pub const MAP_RENAME = 0; +pub const MAP_NORESERVE = 0; +pub const MAP_INHERIT = 0; +pub const MAP_HASSEMAPHORE = 0; +pub const MAP_TRYFIXED = 0; + +pub const MAP_FILE = 0; +pub const MAP_ANON = 0x1000; +pub const MAP_ANONYMOUS = MAP_ANON; +pub const MAP_STACK = 0x4000; +pub const MAP_CONCEAL = 0x8000; + +pub const WNOHANG = 1; +pub const WUNTRACED = 2; +pub const WCONTINUED = 8; + +pub const SA_ONSTACK = 0x0001; +pub const SA_RESTART = 0x0002; +pub const SA_RESETHAND = 0x0004; +pub const SA_NOCLDSTOP = 0x0008; +pub const SA_NODEFER = 0x0010; +pub const SA_NOCLDWAIT = 0x0020; +pub const SA_SIGINFO = 0x0040; + +pub const SIGHUP = 1; +pub const SIGINT = 2; +pub const SIGQUIT = 3; +pub const SIGILL = 4; +pub const SIGTRAP = 5; +pub const SIGABRT = 6; +pub const SIGIOT = SIGABRT; +pub const SIGEMT = 7; +pub const SIGFPE = 8; +pub const SIGKILL = 9; +pub const SIGBUS = 10; +pub const SIGSEGV = 11; +pub const SIGSYS = 12; +pub const SIGPIPE = 13; +pub const SIGALRM = 14; +pub const SIGTERM = 15; +pub const SIGURG = 16; +pub const SIGSTOP = 17; +pub const SIGTSTP = 18; +pub const SIGCONT = 19; +pub const SIGCHLD = 20; +pub const SIGTTIN = 21; +pub const SIGTTOU = 22; +pub const SIGIO = 23; +pub const SIGXCPU = 24; +pub const SIGXFSZ = 25; +pub const SIGVTALRM = 26; +pub const SIGPROF = 27; +pub const SIGWINCH = 28; +pub const SIGINFO = 29; +pub const SIGUSR1 = 30; +pub const SIGUSR2 = 31; +pub const SIGPWR = 32; + +// 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 + +/// open for reading only +pub const O_RDONLY = 0x00000000; + +/// open for writing only +pub const O_WRONLY = 0x00000001; + +/// open for reading and writing +pub const O_RDWR = 0x00000002; + +/// mask for above modes +pub const O_ACCMODE = 0x00000003; + +/// no delay +pub const O_NONBLOCK = 0x00000004; + +/// set append mode +pub const O_APPEND = 0x00000008; + +/// open with shared file lock +pub const O_SHLOCK = 0x00000010; + +/// open with exclusive file lock +pub const O_EXLOCK = 0x00000020; + +/// signal pgrp when data ready +pub const O_ASYNC = 0x00000040; + +/// synchronous writes +pub const O_SYNC = 0x00000080; + +/// don't follow symlinks on the last +pub const O_NOFOLLOW = 0x00000100; + +/// create if nonexistent +pub const O_CREAT = 0x00000200; + +/// truncate to zero length +pub const O_TRUNC = 0x00000400; + +/// error if already exists +pub const O_EXCL = 0x00000800; + +/// don't assign controlling terminal +pub const O_NOCTTY = 0x00008000; + +/// write: I/O data completion +pub const O_DSYNC = O_SYNC; + +/// read: I/O completion as for write +pub const O_RSYNC = O_SYNC; + +/// fail if not a directory +pub const O_DIRECTORY = 0x20000; + +/// set close on exec +pub const O_CLOEXEC = 0x10000; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_GETOWN = 5; +pub const F_SETOWN = 6; + +pub const F_GETLK = 7; +pub const F_SETLK = 8; +pub const F_SETLKW = 9; + +pub const F_RDLCK = 1; +pub const F_UNLCK = 2; +pub const F_WRLCK = 3; + +pub const LOCK_SH = 0x01; +pub const LOCK_EX = 0x02; +pub const LOCK_NB = 0x04; +pub const LOCK_UN = 0x08; + +pub const FD_CLOEXEC = 1; + +pub const SEEK_SET = 0; +pub const SEEK_CUR = 1; +pub const SEEK_END = 2; + +pub const SIG_BLOCK = 1; +pub const SIG_UNBLOCK = 2; +pub const SIG_SETMASK = 3; + +pub const SOCK_STREAM = 1; +pub const SOCK_DGRAM = 2; +pub const SOCK_RAW = 3; +pub const SOCK_RDM = 4; +pub const SOCK_SEQPACKET = 5; + +pub const SOCK_CLOEXEC = 0x8000; +pub const SOCK_NONBLOCK = 0x4000; + +pub const PF_UNSPEC = AF_UNSPEC; +pub const PF_LOCAL = AF_LOCAL; +pub const PF_UNIX = AF_UNIX; +pub const PF_INET = AF_INET; +pub const PF_APPLETALK = AF_APPLETALK; +pub const PF_INET6 = AF_INET6; +pub const PF_DECnet = AF_DECnet; +pub const PF_KEY = AF_KEY; +pub const PF_ROUTE = AF_ROUTE; +pub const PF_SNA = AF_SNA; +pub const PF_MPLS = AF_MPLS; +pub const PF_BLUETOOTH = AF_BLUETOOTH; +pub const PF_ISDN = AF_ISDN; +pub const PF_MAX = AF_MAX; + +pub const AF_UNSPEC = 0; +pub const AF_UNIX = 1; +pub const AF_LOCAL = AF_UNIX; +pub const AF_INET = 2; +pub const AF_APPLETALK = 16; +pub const AF_INET6 = 24; +pub const AF_KEY = 30; +pub const AF_ROUTE = 17; +pub const AF_SNA = 11; +pub const AF_MPLS = 33; +pub const AF_BLUETOOTH = 32; +pub const AF_ISDN = 26; +pub const AF_MAX = 36; + +pub const DT_UNKNOWN = 0; +pub const DT_FIFO = 1; +pub const DT_CHR = 2; +pub const DT_DIR = 4; +pub const DT_BLK = 6; +pub const DT_REG = 8; +pub const DT_LNK = 10; +pub const DT_SOCK = 12; +pub const DT_WHT = 14; // XXX + +/// add event to kq (implies enable) +pub const EV_ADD = 0x0001; + +/// delete event from kq +pub const EV_DELETE = 0x0002; + +/// enable event +pub const EV_ENABLE = 0x0004; + +/// disable event (not reported) +pub const EV_DISABLE = 0x0008; + +/// only report one occurrence +pub const EV_ONESHOT = 0x0010; + +/// clear event state after reporting +pub const EV_CLEAR = 0x0020; + +/// force immediate event output +/// ... with or without EV_ERROR +/// ... use KEVENT_FLAG_ERROR_EVENTS +/// on syscalls supporting flags +pub const EV_RECEIPT = 0x0040; + +/// disable event after reporting +pub const EV_DISPATCH = 0x0080; + +pub const EVFILT_READ = -1; +pub const EVFILT_WRITE = -2; + +/// attached to aio requests +pub const EVFILT_AIO = -3; + +/// attached to vnodes +pub const EVFILT_VNODE = -4; + +/// attached to struct proc +pub const EVFILT_PROC = -5; + +/// attached to struct proc +pub const EVFILT_SIGNAL = -6; + +/// timers +pub const EVFILT_TIMER = -7; + +/// devices +pub const EVFILT_DEVICE = -8; + +/// low water mark +pub const NOTE_LOWAT = 0x0001; + +/// return on EOF +pub const NOTE_EOF = 0x0002; + +/// vnode was removed +pub const NOTE_DELETE = 0x0001; + +/// data contents changed +pub const NOTE_WRITE = 0x0002; + +/// size increased +pub const NOTE_EXTEND = 0x0004; + +/// attributes changed +pub const NOTE_ATTRIB = 0x0008; + +/// link count changed +pub const NOTE_LINK = 0x0010; + +/// vnode was renamed +pub const NOTE_RENAME = 0x0020; + +/// vnode access was revoked +pub const NOTE_REVOKE = 0x0040; + +/// process exited +pub const NOTE_EXIT = 0x80000000; + +/// process forked +pub const NOTE_FORK = 0x40000000; + +/// process exec'd +pub const NOTE_EXEC = 0x20000000; + +/// mask for signal & exit status +pub const NOTE_PDATAMASK = 0x000fffff; +pub const NOTE_PCTRLMASK = 0xf0000000; + +pub const TIOCCBRK = 0x2000747a; +pub const TIOCCDTR = 0x20007478; +pub const TIOCCONS = 0x80047462; +pub const TIOCDCDTIMESTAMP = 0x40107458; +pub const TIOCDRAIN = 0x2000745e; +pub const TIOCEXCL = 0x2000740d; +pub const TIOCEXT = 0x80047460; +pub const TIOCFLAG_CDTRCTS = 0x10; +pub const TIOCFLAG_CLOCAL = 0x2; +pub const TIOCFLAG_CRTSCTS = 0x4; +pub const TIOCFLAG_MDMBUF = 0x8; +pub const TIOCFLAG_SOFTCAR = 0x1; +pub const TIOCFLUSH = 0x80047410; +pub const TIOCGETA = 0x402c7413; +pub const TIOCGETD = 0x4004741a; +pub const TIOCGFLAGS = 0x4004745d; +pub const TIOCGLINED = 0x40207442; +pub const TIOCGPGRP = 0x40047477; +pub const TIOCGQSIZE = 0x40047481; +pub const TIOCGRANTPT = 0x20007447; +pub const TIOCGSID = 0x40047463; +pub const TIOCGSIZE = 0x40087468; +pub const TIOCGWINSZ = 0x40087468; +pub const TIOCMBIC = 0x8004746b; +pub const TIOCMBIS = 0x8004746c; +pub const TIOCMGET = 0x4004746a; +pub const TIOCMSET = 0x8004746d; +pub const TIOCM_CAR = 0x40; +pub const TIOCM_CD = 0x40; +pub const TIOCM_CTS = 0x20; +pub const TIOCM_DSR = 0x100; +pub const TIOCM_DTR = 0x2; +pub const TIOCM_LE = 0x1; +pub const TIOCM_RI = 0x80; +pub const TIOCM_RNG = 0x80; +pub const TIOCM_RTS = 0x4; +pub const TIOCM_SR = 0x10; +pub const TIOCM_ST = 0x8; +pub const TIOCNOTTY = 0x20007471; +pub const TIOCNXCL = 0x2000740e; +pub const TIOCOUTQ = 0x40047473; +pub const TIOCPKT = 0x80047470; +pub const TIOCPKT_DATA = 0x0; +pub const TIOCPKT_DOSTOP = 0x20; +pub const TIOCPKT_FLUSHREAD = 0x1; +pub const TIOCPKT_FLUSHWRITE = 0x2; +pub const TIOCPKT_IOCTL = 0x40; +pub const TIOCPKT_NOSTOP = 0x10; +pub const TIOCPKT_START = 0x8; +pub const TIOCPKT_STOP = 0x4; +pub const TIOCPTMGET = 0x40287446; +pub const TIOCPTSNAME = 0x40287448; +pub const TIOCRCVFRAME = 0x80087445; +pub const TIOCREMOTE = 0x80047469; +pub const TIOCSBRK = 0x2000747b; +pub const TIOCSCTTY = 0x20007461; +pub const TIOCSDTR = 0x20007479; +pub const TIOCSETA = 0x802c7414; +pub const TIOCSETAF = 0x802c7416; +pub const TIOCSETAW = 0x802c7415; +pub const TIOCSETD = 0x8004741b; +pub const TIOCSFLAGS = 0x8004745c; +pub const TIOCSIG = 0x2000745f; +pub const TIOCSLINED = 0x80207443; +pub const TIOCSPGRP = 0x80047476; +pub const TIOCSQSIZE = 0x80047480; +pub const TIOCSSIZE = 0x80087467; +pub const TIOCSTART = 0x2000746e; +pub const TIOCSTAT = 0x80047465; +pub const TIOCSTI = 0x80017472; +pub const TIOCSTOP = 0x2000746f; +pub const TIOCSWINSZ = 0x80087467; +pub const TIOCUCNTL = 0x80047466; +pub const TIOCXMTFRAME = 0x80087444; + +pub fn WEXITSTATUS(s: u32) u32 { + return (s >> 8) & 0xff; +} +pub fn WTERMSIG(s: u32) u32 { + return (s & 0x7f); +} +pub fn WSTOPSIG(s: u32) u32 { + return WEXITSTATUS(s); +} +pub fn WIFEXITED(s: u32) bool { + return WTERMSIG(s) == 0; +} + +pub fn WIFCONTINUED(s: u32) bool { + return ((s & 0o177777) == 0o177777); +} + +pub fn WIFSTOPPED(s: u32) bool { + return (s & 0xff == 0o177); +} + +pub fn WIFSIGNALED(s: u32) bool { + return (((s) & 0o177) != 0o177) and (((s) & 0o177) != 0); +} + +pub const winsize = extern struct { + ws_row: u16, + ws_col: u16, + ws_xpixel: u16, + ws_ypixel: u16, +}; + +const NSIG = 33; + +pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); +pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0); +pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1); + +/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. +pub const Sigaction = extern struct { + pub const sigaction_fn = fn (c_int, *siginfo_t, ?*c_void) callconv(.C) void; + /// signal handler + sigaction: ?sigaction_fn, + /// signal mask to apply + mask: sigset_t, + /// signal options + flags: c_int, +}; + +pub const sigval = extern union { + int: c_int, + ptr: ?*c_void, +}; + +pub const siginfo_t = extern union { + pad: [128]u8, + info: _ksiginfo, +}; + +pub const _ksiginfo = extern struct { + signo: c_int, + code: c_int, + errno: c_int, + data: extern union { + proc: extern struct { + pid: pid_t, + uid: uid_t, + value: sigval, + utime: clock_t, + stime: clock_t, + status: c_int, + }, + fault: extern struct { + addr: ?*c_void, + trapno: c_int, + }, + } align(@sizeOf(usize)), +}; + +pub const sigset_t = c_uint; +pub const empty_sigset = sigset_t(0); + +pub const EPERM = 1; // Operation not permitted +pub const ENOENT = 2; // No such file or directory +pub const ESRCH = 3; // No such process +pub const EINTR = 4; // Interrupted system call +pub const EIO = 5; // Input/output error +pub const ENXIO = 6; // Device not configured +pub const E2BIG = 7; // Argument list too long +pub const ENOEXEC = 8; // Exec format error +pub const EBADF = 9; // Bad file descriptor +pub const ECHILD = 10; // No child processes +pub const EDEADLK = 11; // Resource deadlock avoided +// 11 was EAGAIN +pub const ENOMEM = 12; // Cannot allocate memory +pub const EACCES = 13; // Permission denied +pub const EFAULT = 14; // Bad address +pub const ENOTBLK = 15; // Block device required +pub const EBUSY = 16; // Device busy +pub const EEXIST = 17; // File exists +pub const EXDEV = 18; // Cross-device link +pub const ENODEV = 19; // Operation not supported by device +pub const ENOTDIR = 20; // Not a directory +pub const EISDIR = 21; // Is a directory +pub const EINVAL = 22; // Invalid argument +pub const ENFILE = 23; // Too many open files in system +pub const EMFILE = 24; // Too many open files +pub const ENOTTY = 25; // Inappropriate ioctl for device +pub const ETXTBSY = 26; // Text file busy +pub const EFBIG = 27; // File too large +pub const ENOSPC = 28; // No space left on device +pub const ESPIPE = 29; // Illegal seek +pub const EROFS = 30; // Read-only file system +pub const EMLINK = 31; // Too many links +pub const EPIPE = 32; // Broken pipe + +// math software +pub const EDOM = 33; // Numerical argument out of domain +pub const ERANGE = 34; // Result too large or too small + +// non-blocking and interrupt i/o +pub const EAGAIN = 35; // Resource temporarily unavailable +pub const EWOULDBLOCK = EAGAIN; // Operation would block +pub const EINPROGRESS = 36; // Operation now in progress +pub const EALREADY = 37; // Operation already in progress + +// ipc/network software -- argument errors +pub const ENOTSOCK = 38; // Socket operation on non-socket +pub const EDESTADDRREQ = 39; // Destination address required +pub const EMSGSIZE = 40; // Message too long +pub const EPROTOTYPE = 41; // Protocol wrong type for socket +pub const ENOPROTOOPT = 42; // Protocol option not available +pub const EPROTONOSUPPORT = 43; // Protocol not supported +pub const ESOCKTNOSUPPORT = 44; // Socket type not supported +pub const EOPNOTSUPP = 45; // Operation not supported +pub const EPFNOSUPPORT = 46; // Protocol family not supported +pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family +pub const EADDRINUSE = 48; // Address already in use +pub const EADDRNOTAVAIL = 49; // Can't assign requested address + +// ipc/network software -- operational errors +pub const ENETDOWN = 50; // Network is down +pub const ENETUNREACH = 51; // Network is unreachable +pub const ENETRESET = 52; // Network dropped connection on reset +pub const ECONNABORTED = 53; // Software caused connection abort +pub const ECONNRESET = 54; // Connection reset by peer +pub const ENOBUFS = 55; // No buffer space available +pub const EISCONN = 56; // Socket is already connected +pub const ENOTCONN = 57; // Socket is not connected +pub const ESHUTDOWN = 58; // Can't send after socket shutdown +pub const ETOOMANYREFS = 59; // Too many references: can't splice +pub const ETIMEDOUT = 60; // Operation timed out +pub const ECONNREFUSED = 61; // Connection refused + +pub const ELOOP = 62; // Too many levels of symbolic links +pub const ENAMETOOLONG = 63; // File name too long + +// should be rearranged +pub const EHOSTDOWN = 64; // Host is down +pub const EHOSTUNREACH = 65; // No route to host +pub const ENOTEMPTY = 66; // Directory not empty + +// quotas & mush +pub const EPROCLIM = 67; // Too many processes +pub const EUSERS = 68; // Too many users +pub const EDQUOT = 69; // Disc quota exceeded + +// Network File System +pub const ESTALE = 70; // Stale NFS file handle +pub const EREMOTE = 71; // Too many levels of remote in path +pub const EBADRPC = 72; // RPC struct is bad +pub const ERPCMISMATCH = 73; // RPC version wrong +pub const EPROGUNAVAIL = 74; // RPC prog. not avail +pub const EPROGMISMATCH = 75; // Program version wrong +pub const EPROCUNAVAIL = 76; // Bad procedure for program + +pub const ENOLCK = 77; // No locks available +pub const ENOSYS = 78; // Function not implemented + +pub const EFTYPE = 79; // Inappropriate file type or format +pub const EAUTH = 80; // Authentication error +pub const ENEEDAUTH = 81; // Need authenticator +pub const EIPSEC = 82; // IPsec processing failure +pub const ENOATTR = 83; // Attribute not found + +// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 +pub const EILSEQ = 84; // Illegal byte sequence + +pub const ENOMEDIUM = 85; // No medium found +pub const EMEDIUMTYPE = 86; // Wrong medium type +pub const EOVERFLOW = 87; // Value too large to be stored in data type +pub const ECANCELED = 88; // Operation canceled +pub const EIDRM = 89; // Identifier removed +pub const ENOMSG = 90; // No message of desired type +pub const ENOTSUP = 91; // Not supported +pub const EBADMSG = 92; // Bad or Corrupt message +pub const ENOTRECOVERABLE = 93; // State not recoverable +pub const EOWNERDEAD = 94; // Previous owner died +pub const EPROTO = 95; // Protocol error + +pub const ELAST = 95; // Must equal largest errno + +const _MAX_PAGE_SHIFT = switch (builtin.arch) { + .i386 => 12, + .sparcv9 => 13, +}; +pub const MINSIGSTKSZ = 1 << _MAX_PAGE_SHIFT; +pub const SIGSTKSZ = MINSIGSTKSZ + (1 << _MAX_PAGE_SHIFT) * 4; + +pub const SS_ONSTACK = 0x0001; +pub const SS_DISABLE = 0x0004; + +pub const stack_t = extern struct { + ss_sp: [*]u8, + ss_size: usize, + ss_flags: c_int, +}; + +pub const S_IFMT = 0o170000; + +pub const S_IFIFO = 0o010000; +pub const S_IFCHR = 0o020000; +pub const S_IFDIR = 0o040000; +pub const S_IFBLK = 0o060000; +pub const S_IFREG = 0o100000; +pub const S_IFLNK = 0o120000; +pub const S_IFSOCK = 0o140000; + +pub const S_ISUID = 0o4000; +pub const S_ISGID = 0o2000; +pub const S_ISVTX = 0o1000; +pub const S_IRWXU = 0o700; +pub const S_IRUSR = 0o400; +pub const S_IWUSR = 0o200; +pub const S_IXUSR = 0o100; +pub const S_IRWXG = 0o070; +pub const S_IRGRP = 0o040; +pub const S_IWGRP = 0o020; +pub const S_IXGRP = 0o010; +pub const S_IRWXO = 0o007; +pub const S_IROTH = 0o004; +pub const S_IWOTH = 0o002; +pub const S_IXOTH = 0o001; + +pub fn S_ISFIFO(m: u32) bool { + return m & S_IFMT == S_IFIFO; +} + +pub fn S_ISCHR(m: u32) bool { + return m & S_IFMT == S_IFCHR; +} + +pub fn S_ISDIR(m: u32) bool { + return m & S_IFMT == S_IFDIR; +} + +pub fn S_ISBLK(m: u32) bool { + return m & S_IFMT == S_IFBLK; +} + +pub fn S_ISREG(m: u32) bool { + return m & S_IFMT == S_IFREG; +} + +pub fn S_ISLNK(m: u32) bool { + return m & S_IFMT == S_IFLNK; +} + +pub fn S_ISSOCK(m: u32) bool { + return m & S_IFMT == S_IFSOCK; +} + +/// 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 AT_FDCWD = -100; + +/// Check access using effective user and group ID +pub const AT_EACCESS = 0x01; + +/// Do not follow symbolic links +pub const AT_SYMLINK_NOFOLLOW = 0x02; + +/// Follow symbolic link +pub const AT_SYMLINK_FOLLOW = 0x04; + +/// Remove directory instead of file +pub const AT_REMOVEDIR = 0x08; + +pub const HOST_NAME_MAX = 255; + +/// dummy for IP +pub const IPPROTO_IP = 0; + +/// IP6 hop-by-hop options +pub const IPPROTO_HOPOPTS = IPPROTO_IP; + +/// control message protocol +pub const IPPROTO_ICMP = 1; + +/// group mgmt protocol +pub const IPPROTO_IGMP = 2; + +/// gateway^2 (deprecated) +pub const IPPROTO_GGP = 3; + +/// IP header +pub const IPPROTO_IPV4 = IPPROTO_IPIP; + +/// IP inside IP +pub const IPPROTO_IPIP = 4; + +/// tcp +pub const IPPROTO_TCP = 6; + +/// exterior gateway protocol +pub const IPPROTO_EGP = 8; + +/// pup +pub const IPPROTO_PUP = 12; + +/// user datagram protocol +pub const IPPROTO_UDP = 17; + +/// xns idp +pub const IPPROTO_IDP = 22; + +/// tp-4 w/ class negotiation +pub const IPPROTO_TP = 29; + +/// IP6 header +pub const IPPROTO_IPV6 = 41; + +/// IP6 routing header +pub const IPPROTO_ROUTING = 43; + +/// IP6 fragmentation header +pub const IPPROTO_FRAGMENT = 44; + +/// resource reservation +pub const IPPROTO_RSVP = 46; + +/// GRE encaps RFC 1701 +pub const IPPROTO_GRE = 47; + +/// encap. security payload +pub const IPPROTO_ESP = 50; + +/// authentication header +pub const IPPROTO_AH = 51; + +/// IP Mobility RFC 2004 +pub const IPPROTO_MOBILE = 55; + +/// IPv6 ICMP +pub const IPPROTO_IPV6_ICMP = 58; + +/// ICMP6 +pub const IPPROTO_ICMPV6 = 58; + +/// IP6 no next header +pub const IPPROTO_NONE = 59; + +/// IP6 destination option +pub const IPPROTO_DSTOPTS = 60; + +/// ISO cnlp +pub const IPPROTO_EON = 80; + +/// Ethernet-in-IP +pub const IPPROTO_ETHERIP = 97; + +/// encapsulation header +pub const IPPROTO_ENCAP = 98; + +/// Protocol indep. multicast +pub const IPPROTO_PIM = 103; + +/// IP Payload Comp. Protocol +pub const IPPROTO_IPCOMP = 108; + +/// VRRP RFC 2338 +pub const IPPROTO_VRRP = 112; + +/// Common Address Resolution Protocol +pub const IPPROTO_CARP = 112; + +/// PFSYNC +pub const IPPROTO_PFSYNC = 240; + +/// raw IP packet +pub const IPPROTO_RAW = 255; diff --git a/lib/std/os/openbsd.zig b/lib/std/os/openbsd.zig new file mode 100644 index 000000000..a713a009a --- /dev/null +++ b/lib/std/os/openbsd.zig @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../std.zig"); +pub usingnamespace std.c; +pub usingnamespace @import("bits.zig"); diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig index f25ff0b1b..b185f5cfe 100644 --- a/lib/std/packed_int_array.zig +++ b/lib/std/packed_int_array.zig @@ -618,7 +618,7 @@ test "PackedIntArray at end of available memory" { if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; switch (builtin.os.tag) { - .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {}, + .linux, .macosx, .ios, .freebsd, .netbsd, .openbsd, .windows => {}, else => return, } const PackedArray = PackedIntArray(u3, 8); @@ -639,7 +639,7 @@ test "PackedIntSlice at end of available memory" { if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; switch (builtin.os.tag) { - .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {}, + .linux, .macosx, .ios, .freebsd, .netbsd, .openbsd, .windows => {}, else => return, } const PackedSlice = PackedIntSlice(u11); diff --git a/lib/std/process.zig b/lib/std/process.zig index 2813d8cba..f635e44f5 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -585,7 +585,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, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name), + .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd, .openbsd => posixGetUserInfo(name), else => @compileError("Unsupported OS"), }; } @@ -712,6 +712,7 @@ pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0] .freebsd, .netbsd, .dragonfly, + .openbsd, => { var paths = List.init(allocator); errdefer { diff --git a/lib/std/target.zig b/lib/std/target.zig index 99617c6d0..983f0d63b 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -266,8 +266,8 @@ pub const Target = struct { }, .openbsd => return .{ .semver = .{ - .min = .{ .major = 6, .minor = 6 }, - .max = .{ .major = 6, .minor = 6 }, + .min = .{ .major = 6, .minor = 8 }, + .max = .{ .major = 6, .minor = 8 }, }, }, .dragonfly => return .{ @@ -1358,6 +1358,7 @@ pub const Target = struct { switch (self.os.tag) { .freebsd => return copy(&result, "/libexec/ld-elf.so.1"), .netbsd => return copy(&result, "/libexec/ld.elf_so"), + .openbsd => return copy(&result, "/libexec/ld.so"), .dragonfly => return copy(&result, "/libexec/ld-elf.so.2"), .linux => switch (self.cpu.arch) { .i386, @@ -1465,7 +1466,6 @@ pub const Target = struct { .fuchsia, .kfreebsd, .lv2, - .openbsd, .solaris, .haiku, .minix, diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig index f1ae3457a..863929d6a 100644 --- a/lib/std/zig/cross_target.zig +++ b/lib/std/zig/cross_target.zig @@ -449,6 +449,10 @@ pub const CrossTarget = struct { return self.getOsTag() == .netbsd; } + pub fn isOpenBSD(self: CrossTarget) bool { + return self.getOsTag() == .openbsd; + } + pub fn isUefi(self: CrossTarget) bool { return self.getOsTag() == .uefi; } diff --git a/src/libc_installation.zig b/src/libc_installation.zig index 535892ce7..b016589f4 100644 --- a/src/libc_installation.zig +++ b/src/libc_installation.zig @@ -196,7 +196,7 @@ pub const LibCInstallation = struct { errdefer batch.wait() catch {}; batch.add(&async self.findNativeIncludeDirPosix(args)); switch (Target.current.os.tag) { - .freebsd, .netbsd => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"), + .freebsd, .netbsd, .openbsd => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"), .linux, .dragonfly => batch.add(&async self.findNativeCrtDirPosix(args)), else => {}, } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 9c4029b3c..3d5481ce4 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1432,7 +1432,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { if (link_in_crt) { const crt1o: []const u8 = o: { - if (target.os.tag == .netbsd) { + if (target.os.tag == .netbsd or target.os.tag == .openbsd) { break :o "crt0.o"; } else if (target.isAndroid()) { if (self.base.options.link_mode == .Dynamic) { @@ -1448,7 +1448,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { }; try argv.append(try comp.get_libc_crt_file(arena, crt1o)); if (target_util.libc_needs_crti_crtn(target)) { - try argv.append(try comp.get_libc_crt_file(arena, "crti.o")); + const crtio: []const u8 = o: { + if (target.os.tag == .openbsd) { + break :o "crtbegin.o"; + } else { + break :o "crti.o"; + } + }; + try argv.append(try comp.get_libc_crt_file(arena, crtio)); } } @@ -1592,10 +1599,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // crt end if (link_in_crt) { - if (target.isAndroid()) { - try argv.append(try comp.get_libc_crt_file(arena, "crtend_android.o")); - } else if (target_util.libc_needs_crti_crtn(target)) { - try argv.append(try comp.get_libc_crt_file(arena, "crtn.o")); + if (target_util.libc_needs_crti_crtn(target)) { + const crtno: []const u8 = o: { + if (target.os.tag == .openbsd) { + break :o "crtend.o"; + } else if (target.isAndroid()) { + break :o "crtend_android.o"; + } else { + break :o "crtn.o"; + } + }; + try argv.append(try comp.get_libc_crt_file(arena, crtno)); } } diff --git a/src/stage1/os.cpp b/src/stage1/os.cpp index c8e4a5130..c9dd49071 100644 --- a/src/stage1/os.cpp +++ b/src/stage1/os.cpp @@ -59,7 +59,7 @@ typedef SSIZE_T ssize_t; #endif -#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) +#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) || defined(ZIG_OS_OPENBSD) #include #endif @@ -67,7 +67,7 @@ typedef SSIZE_T ssize_t; #include #endif -#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) +#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) || defined(ZIG_OS_OPENBSD) #include #endif diff --git a/src/stage1/os.hpp b/src/stage1/os.hpp index 9564e6380..4f38403a9 100644 --- a/src/stage1/os.hpp +++ b/src/stage1/os.hpp @@ -29,6 +29,8 @@ #define ZIG_OS_NETBSD #elif defined(__DragonFly__) #define ZIG_OS_DRAGONFLY +#elif defined(__OpenBSD__) +#define ZIG_OS_OPENBSD #else #define ZIG_OS_UNKNOWN #endif diff --git a/src/target.zig b/src/target.zig index d009cf855..8af6ef9d9 100644 --- a/src/target.zig +++ b/src/target.zig @@ -123,7 +123,7 @@ pub fn cannotDynamicLink(target: std.Target) bool { /// since this is the stable syscall interface. pub fn osRequiresLibC(target: std.Target) bool { return switch (target.os.tag) { - .freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true, + .freebsd, .netbsd, .dragonfly, .openbsd, .macosx, .ios, .watchos, .tvos => true, else => false, }; } @@ -143,7 +143,7 @@ pub fn libcNeedsLibUnwind(target: std.Target) bool { } pub fn requiresPIE(target: std.Target) bool { - return target.isAndroid() or target.isDarwin(); + return target.isAndroid() or target.isDarwin() or target.os.tag == .openbsd; } /// This function returns whether non-pic code is completely invalid on the given target. From 78a7543056112a1df8951712a746b9adb59787af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 08:23:37 +0000 Subject: [PATCH 2/8] openbsd: use mem.span() + mem.indexOf() instead of defining custom function --- lib/std/fs.zig | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 6e0b9b43e..9c28d87e6 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2177,14 +2177,6 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathError; -fn str_containsZ(s: [*:0]const u8, c: u8) bool { - var i: usize = 0; - while (s[i] != '\x00' and s[i] != c) { - i += 1; - } - return (s[i] == '/'); -} - /// `selfExePath` except allocates the result on the heap. /// Caller owns returned memory. pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { @@ -2243,7 +2235,8 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { .openbsd => { // OpenBSD doesn't support getting the path of a running process, so try to guess it if (os.argv.len >= 1) { - if (str_containsZ(os.argv[0], '/')) { + const argv0 = mem.span(os.argv[0]); + if (mem.indexOf(u8, argv0, "/") != null) { // argv[0] is a path (relative or absolute): use realpath(3) directly var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; const real_path = try os.realpathZ(os.argv[0], &real_path_buf); From 97ec9fdd7929880699179f5024b8bb93ac424ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 08:23:37 +0000 Subject: [PATCH 3/8] opensd: selfExePath: do not rely on environment as it could be inherited --- lib/std/fs.zig | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 9c28d87e6..5aef64afc 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2268,12 +2268,6 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { } } - if (os.getenv("_")) |sh_exefile| { - // sh (or bash) sets "_" environment variable - mem.copy(u8, out_buffer, sh_exefile); - return out_buffer[0..sh_exefile.len]; - } - // sorry, we don't find it return error.FileNotFound; }, From 9ff51f22b46d083dbd80e427a00a7f392c467f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 10:12:40 +0000 Subject: [PATCH 4/8] openbsd: address link/Elf.zig comments - restore correct behaviour on Android target for appending "crtend_android.o" - some nits --- src/link/Elf.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 3d5481ce4..f111ad920 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1448,14 +1448,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { }; try argv.append(try comp.get_libc_crt_file(arena, crt1o)); if (target_util.libc_needs_crti_crtn(target)) { - const crtio: []const u8 = o: { + const crti_o = o: { if (target.os.tag == .openbsd) { break :o "crtbegin.o"; } else { break :o "crti.o"; } }; - try argv.append(try comp.get_libc_crt_file(arena, crtio)); + try argv.append(try comp.get_libc_crt_file(arena, crti_o)); } } @@ -1599,8 +1599,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // crt end if (link_in_crt) { - if (target_util.libc_needs_crti_crtn(target)) { - const crtno: []const u8 = o: { + if (target.isAndroid() or target_util.libc_needs_crti_crtn(target)) { + const crtn_o = o: { if (target.os.tag == .openbsd) { break :o "crtend.o"; } else if (target.isAndroid()) { @@ -1609,7 +1609,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { break :o "crtn.o"; } }; - try argv.append(try comp.get_libc_crt_file(arena, crtno)); + try argv.append(try comp.get_libc_crt_file(arena, crtn_o)); } } From 4c4211ea8e7c553c78ed25f52b60000f1f066503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 10:22:28 +0000 Subject: [PATCH 5/8] merge netbsd and openbsd cases --- lib/std/os.zig | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 7558e7947..936d31a00 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -164,12 +164,8 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { } return; } - if (builtin.os.tag == .netbsd) { - netbsd.arc4random_buf(buffer.ptr, buffer.len); - return; - } - if (builtin.os.tag == .openbsd) { - openbsd.arc4random_buf(buffer.ptr, buffer.len); + if (builtin.os.tag == .netbsd or builtin.os.tag == .openbsd) { + system.arc4random_buf(buffer.ptr, buffer.len); return; } if (builtin.os.tag == .wasi) { From a6dc2b7fcc2e1e73130eb0e762cac4ab884d20c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 12:23:52 +0000 Subject: [PATCH 6/8] openbsd: selfExePath adjustements --- lib/std/fs.zig | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 5aef64afc..cd75b3bc4 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2244,19 +2244,18 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { return error.NameTooLong; mem.copy(u8, out_buffer, real_path); return out_buffer[0..real_path.len]; - - } else if (os.argv[0][0] != '\x00') { + } else if (argv0.len != 0) { // argv[0] is not empty (and not a path): search it inside PATH - const paths = std.os.getenv("PATH") orelse ""; - var path_it = mem.split(paths, ":"); + const PATH = std.os.getenv("PATH") orelse ""; + var path_it = mem.tokenize(PATH, &[_]u8{path.delimiter}); while (path_it.next()) |a_path| { - var resolved_path_buf: [MAX_PATH_BYTES:0]u8 = undefined; + var resolved_path_buf: [MAX_PATH_BYTES-1:0]u8 = undefined; const resolved_path = std.fmt.bufPrint(&resolved_path_buf, "{}/{}\x00", .{ a_path, os.argv[0], }) catch ""; - var real_path_buf: [MAX_PATH_BYTES:0]u8 = undefined; + var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; if (os.realpathZ(&resolved_path_buf, &real_path_buf) catch null) |real_path| { // found a file, and hope it is the right file if (real_path.len > out_buffer.len) From 161eb4a000923c28d152781dcc8a080905c7ad32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Sun, 11 Oct 2020 12:25:16 +0000 Subject: [PATCH 7/8] initialize std.os.argv in stage1 compiler. it is needed for selfExePath under OpenBSD --- src/stage1.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/stage1.zig b/src/stage1.zig index f26622ee8..7214ae21b 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -25,7 +25,9 @@ comptime { pub const log = stage2.log; pub const log_level = stage2.log_level; -pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int { +pub export fn main(argc: c_int, argv: [*][*:0]u8) c_int { + std.os.argv = argv[0.. @intCast(usize, argc)]; + std.debug.maybeEnableSegfaultHandler(); zig_stage1_os_init(); From 05b1a7414e2737fd987071a03a3fc8387b4fd268 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 17 Oct 2020 17:52:09 -0700 Subject: [PATCH 8/8] code cleanups * in selfExePath, return errors instead of defaulting to bogus data * less invasive edits to the logic of link/Elf.zig * less indentation --- lib/std/fs.zig | 61 ++++++++++++++++++------------------- lib/std/os/bits/openbsd.zig | 4 +-- src/link/Elf.zig | 29 ++++++------------ src/stage1.zig | 4 +-- src/target.zig | 2 +- 5 files changed, 45 insertions(+), 55 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index ffec9e0fa..b4da2e0a5 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2234,40 +2234,39 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { }, .openbsd => { // OpenBSD doesn't support getting the path of a running process, so try to guess it - if (os.argv.len >= 1) { - const argv0 = mem.span(os.argv[0]); - if (mem.indexOf(u8, argv0, "/") != null) { - // argv[0] is a path (relative or absolute): use realpath(3) directly - var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const real_path = try os.realpathZ(os.argv[0], &real_path_buf); - if (real_path.len > out_buffer.len) - return error.NameTooLong; - mem.copy(u8, out_buffer, real_path); - return out_buffer[0..real_path.len]; - } else if (argv0.len != 0) { - // argv[0] is not empty (and not a path): search it inside PATH - const PATH = std.os.getenv("PATH") orelse ""; - var path_it = mem.tokenize(PATH, &[_]u8{path.delimiter}); - while (path_it.next()) |a_path| { - var resolved_path_buf: [MAX_PATH_BYTES-1:0]u8 = undefined; - const resolved_path = std.fmt.bufPrint(&resolved_path_buf, "{}/{}\x00", .{ - a_path, - os.argv[0], - }) catch ""; + if (os.argv.len == 0) + return error.FileNotFound; - var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; - if (os.realpathZ(&resolved_path_buf, &real_path_buf) catch null) |real_path| { - // found a file, and hope it is the right file - if (real_path.len > out_buffer.len) - return error.NameTooLong; - mem.copy(u8, out_buffer, real_path); - return out_buffer[0..real_path.len]; - } - } + const argv0 = mem.span(os.argv[0]); + if (mem.indexOf(u8, argv0, "/") != null) { + // argv[0] is a path (relative or absolute): use realpath(3) directly + var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; + const real_path = try os.realpathZ(os.argv[0], &real_path_buf); + if (real_path.len > out_buffer.len) + return error.NameTooLong; + mem.copy(u8, out_buffer, real_path); + return out_buffer[0..real_path.len]; + } else if (argv0.len != 0) { + // argv[0] is not empty (and not a path): search it inside PATH + const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound; + var path_it = mem.tokenize(PATH, &[_]u8{path.delimiter}); + while (path_it.next()) |a_path| { + var resolved_path_buf: [MAX_PATH_BYTES]u8 = undefined; + const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{ + a_path, + os.argv[0], + }) catch continue; + + var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; + if (os.realpathZ(&resolved_path_buf, &real_path_buf)) |real_path| { + // found a file, and hope it is the right file + if (real_path.len > out_buffer.len) + return error.NameTooLong; + mem.copy(u8, out_buffer, real_path); + return out_buffer[0..real_path.len]; + } else |_| continue; } } - - // sorry, we don't find it return error.FileNotFound; }, .windows => { diff --git a/lib/std/os/bits/openbsd.zig b/lib/std/os/bits/openbsd.zig index a972ea097..1419e7f27 100644 --- a/lib/std/os/bits/openbsd.zig +++ b/lib/std/os/bits/openbsd.zig @@ -174,7 +174,7 @@ pub const Stat = extern struct { blksize: blksize_t, flags: u32, gen: u32, - birthtim: timespec, + birthtim: timespec, pub fn atime(self: Stat) timespec { return self.atim; @@ -203,7 +203,7 @@ pub const dirent = extern struct { d_type: u8, d_namlen: u8, __d_padding: [4]u8, - d_name: [MAXNAMLEN+1]u8, + d_name: [MAXNAMLEN + 1]u8, pub fn reclen(self: dirent) u16 { return self.d_reclen; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f111ad920..b7e540483 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1448,14 +1448,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { }; try argv.append(try comp.get_libc_crt_file(arena, crt1o)); if (target_util.libc_needs_crti_crtn(target)) { - const crti_o = o: { - if (target.os.tag == .openbsd) { - break :o "crtbegin.o"; - } else { - break :o "crti.o"; - } - }; - try argv.append(try comp.get_libc_crt_file(arena, crti_o)); + try argv.append(try comp.get_libc_crt_file(arena, "crti.o")); + } + if (target.os.tag == .openbsd) { + try argv.append(try comp.get_libc_crt_file(arena, "crtbegin.o")); } } @@ -1599,17 +1595,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { // crt end if (link_in_crt) { - if (target.isAndroid() or target_util.libc_needs_crti_crtn(target)) { - const crtn_o = o: { - if (target.os.tag == .openbsd) { - break :o "crtend.o"; - } else if (target.isAndroid()) { - break :o "crtend_android.o"; - } else { - break :o "crtn.o"; - } - }; - try argv.append(try comp.get_libc_crt_file(arena, crtn_o)); + if (target.isAndroid()) { + try argv.append(try comp.get_libc_crt_file(arena, "crtend_android.o")); + } else if (target.os.tag == .openbsd) { + try argv.append(try comp.get_libc_crt_file(arena, "crtend.o")); + } else if (target_util.libc_needs_crti_crtn(target)) { + try argv.append(try comp.get_libc_crt_file(arena, "crtn.o")); } } diff --git a/src/stage1.zig b/src/stage1.zig index 7214ae21b..d07a1c199 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -26,8 +26,8 @@ pub const log = stage2.log; pub const log_level = stage2.log_level; pub export fn main(argc: c_int, argv: [*][*:0]u8) c_int { - std.os.argv = argv[0.. @intCast(usize, argc)]; - + std.os.argv = argv[0..@intCast(usize, argc)]; + std.debug.maybeEnableSegfaultHandler(); zig_stage1_os_init(); diff --git a/src/target.zig b/src/target.zig index 7ed040c36..9415ddaf7 100644 --- a/src/target.zig +++ b/src/target.zig @@ -161,7 +161,7 @@ pub fn supports_fpic(target: std.Target) bool { } pub fn libc_needs_crti_crtn(target: std.Target) bool { - return !(target.cpu.arch.isRISCV() or target.isAndroid()); + return !(target.cpu.arch.isRISCV() or target.isAndroid() or target.os.tag == .openbsd); } pub fn isSingleThreaded(target: std.Target) bool {