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 <dev@sgregoratto.me>
This commit is contained in:
Kim SHrier
2022-07-11 13:54:40 -06:00
committed by Veikka Tuominen
parent 4c7fe74b2c
commit 397e6547a9
2 changed files with 187 additions and 3 deletions

View File

@@ -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;

View File

@@ -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"),
}
}