From 397e6547a9b1745df520a65ca615934b8c0a02d2 Mon Sep 17 00:00:00 2001 From: Kim SHrier Date: Mon, 11 Jul 2022 13:54:40 -0600 Subject: [PATCH] add FreeBSD support to std.os.getFdPath This implementation uses the F_KINFO fcntl command added in FreeBSD 13 release. FreeBSD 12 users get a compile error. Co-authored-by: Stephen Gregoratto --- lib/std/c/freebsd.zig | 170 +++++++++++++++++++++++++++++++++++++++++- lib/std/os.zig | 20 ++++- 2 files changed, 187 insertions(+), 3 deletions(-) diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig index 5a12b5e136..dac239094e 100644 --- a/lib/std/c/freebsd.zig +++ b/lib/std/c/freebsd.zig @@ -19,6 +19,8 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int; pub extern "c" fn malloc_usable_size(?*const anyopaque) usize; +pub extern "c" fn getpid() pid_t; + pub const sf_hdtr = extern struct { headers: [*]const iovec_const, hdr_cnt: c_int, @@ -397,6 +399,127 @@ pub const sockaddr = extern struct { }; }; +pub const CAP_RIGHTS_VERSION = 0; + +pub const cap_rights = extern struct { + rights: [CAP_RIGHTS_VERSION + 2]u64, +}; + +pub const kinfo_file = extern struct { + /// Size of this record. + /// A zero value is for the sentinel record at the end of an array. + structsize: c_int, + /// Descriptor type. + @"type": c_int, + /// Array index. + fd: fd_t, + /// Reference count. + ref_count: c_int, + /// Flags. + flags: c_int, + // 64bit padding. + _pad0: c_int, + /// Seek location. + offset: i64, + un: extern union { + socket: extern struct { + /// Sendq size. + sendq: u32, + /// Socket domain. + domain: c_int, + /// Socket type. + @"type": c_int, + /// Socket protocol. + protocol: c_int, + /// Socket address. + address: sockaddr.storage, + /// Peer address. + peer: sockaddr.storage, + /// Address of so_pcb. + pcb: u64, + /// Address of inp_ppcb. + inpcb: u64, + /// Address of unp_conn. + unpconn: u64, + /// Send buffer state. + snd_sb_state: u16, + /// Receive buffer state. + rcv_sb_state: u16, + /// Recvq size. + recvq: u32, + }, + file: extern struct { + /// Vnode type. + @"type": i32, + // Reserved for future use + _spare1: [3]i32, + _spare2: [30]u64, + /// Vnode filesystem id. + fsid: u64, + /// File device. + rdev: u64, + /// Global file id. + fileid: u64, + /// File size. + size: u64, + /// fsid compat for FreeBSD 11. + fsid_freebsd11: u32, + /// rdev compat for FreeBSD 11. + rdev_freebsd11: u32, + /// File mode. + mode: u16, + // 64bit padding. + _pad0: u16, + _pad1: u32, + }, + sem: extern struct { + _spare0: [4]u32, + _spare1: [32]u64, + /// Semaphore value. + value: u32, + /// Semaphore mode. + mode: u16, + }, + pipe: extern struct { + _spare1: [4]u32, + _spare2: [32]u64, + addr: u64, + peer: u64, + buffer_cnt: u32, + // 64bit padding. + kf_pipe_pad0: [3]u32, + }, + proc: extern struct { + _spare1: [4]u32, + _spare2: [32]u64, + pid: pid_t, + }, + eventfd: extern struct { + value: u64, + flags: u32, + }, + }, + /// Status flags. + status: u16, + // 32-bit alignment padding. + _pad1: u16, + // Reserved for future use. + _spare: c_int, + /// Capability rights. + cap_rights: cap_rights, + /// Reserved for future cap_rights + _cap_spare: u64, + /// Path to file, if any. + path: [PATH_MAX - 1:0]u8, +}; + +pub const KINFO_FILE_SIZE = 1392; + +comptime { + std.debug.assert(@sizeOf(kinfo_file) == KINFO_FILE_SIZE); + std.debug.assert(@alignOf(kinfo_file) == @sizeOf(u64)); +} + pub const CTL = struct { pub const KERN = 1; pub const DEBUG = 5; @@ -405,6 +528,7 @@ pub const CTL = struct { pub const KERN = struct { pub const PROC = 14; // struct: process entries pub const PROC_PATHNAME = 12; // path to executable + pub const PROC_FILEDESC = 33; // file descriptors for process pub const IOV_MAX = 35; }; @@ -613,23 +737,67 @@ pub const O = struct { pub const NDELAY = NONBLOCK; }; +/// Command flags for fcntl(2). pub const F = struct { + /// Duplicate file descriptor. pub const DUPFD = 0; + /// Get file descriptor flags. pub const GETFD = 1; + /// Set file descriptor flags. pub const SETFD = 2; + /// Get file status flags. pub const GETFL = 3; + /// Set file status flags. pub const SETFL = 4; + /// Get SIGIO/SIGURG proc/pgrrp. pub const GETOWN = 5; + /// Set SIGIO/SIGURG proc/pgrrp. pub const SETOWN = 6; + /// Get record locking information. pub const GETLK = 11; + /// Set record locking information. pub const SETLK = 12; + /// Set record locking information and wait if blocked. pub const SETLKW = 13; + /// Debugging support for remote locks. + pub const SETLK_REMOTE = 14; + /// Read ahead. + pub const READAHEAD = 15; + + /// DUPFD with FD_CLOEXEC set. + pub const DUPFD_CLOEXEC = 17; + /// DUP2FD with FD_CLOEXEC set. + pub const DUP2FD_CLOEXEC = 18; + + pub const ADD_SEALS = 19; + pub const GET_SEALS = 20; + /// Return `kinfo_file` for a file descriptor. + pub const KINFO = 22; + + // Seals (ADD_SEALS, GET_SEALS) + /// Prevent adding sealings. + pub const SEAL_SEAL = 0x0001; + /// May not shrink + pub const SEAL_SHRINK = 0x0002; + /// May not grow. + pub const SEAL_GROW = 0x0004; + /// May not write. + pub const SEAL_WRITE = 0x0008; + + // Record locking flags (GETLK, SETLK, SETLKW). + /// Shared or read lock. pub const RDLCK = 1; - pub const WRLCK = 3; + /// Unlock. pub const UNLCK = 2; + /// Exclusive or write lock. + pub const WRLCK = 3; + /// Purge locks for a given system ID. + pub const UNLCKSYS = 4; + /// Cancel an async lock request. + pub const CANCEL = 5; pub const SETOWN_EX = 15; pub const GETOWN_EX = 16; diff --git a/lib/std/os.zig b/lib/std/os.zig index 8b760668a3..3209331721 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -5167,8 +5167,8 @@ pub fn realpathW(pathname: []const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPat /// Return canonical path of handle `fd`. /// This function is very host-specific and is not universally supported by all hosts. -/// For example, while it generally works on Linux, macOS or Windows, it is unsupported -/// on FreeBSD, or WASI. +/// For example, while it generally works on Linux, macOS, FreeBSD or Windows, it is +/// unsupported on WASI. pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { switch (builtin.os.tag) { .windows => { @@ -5217,6 +5217,22 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { }; return target; }, + .freebsd => { + comptime if (builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .lt) + @compileError("querying for canonical path of a handle is unsupported on FreeBSD 12 and below"); + + var kfile: system.kinfo_file = undefined; + kfile.structsize = system.KINFO_FILE_SIZE; + switch (errno(system.fcntl(fd, system.F.KINFO, @ptrToInt(&kfile)))) { + .SUCCESS => {}, + .BADF => return error.FileNotFound, + else => |err| return unexpectedErrno(err), + } + + const len = mem.indexOfScalar(u8, &kfile.path, 0) orelse MAX_PATH_BYTES; + mem.copy(u8, out_buffer, kfile.path[0..len]); + return out_buffer[0..len]; + }, else => @compileError("querying for canonical path of a handle is unsupported on this host"), } }