Commit f33a610c84

Sébastien Marie <semarie@online.fr>
2020-10-11 10:23:36
add minimal openbsd support
1 parent a31b70c
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,
+};
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,
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;
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"),
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;
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 {},
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");
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;
     }
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 {
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,
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,
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.
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,
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);
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 {
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,
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));
         }
     }
 
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 <link.h>
 #endif
 
@@ -67,7 +67,7 @@ typedef SSIZE_T ssize_t;
 #include <sys/auxv.h>
 #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 <sys/sysctl.h>
 #endif
 
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
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 => {},
                 }
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.