Commit 537624734c

Michael Dusan <michael.dusan@gmail.com>
2023-01-03 01:18:32
freebsd: getFdPath: < 13.1 fallback impl
1 parent 4cdbde5
Changed files (2)
lib/std/c/freebsd.zig
@@ -21,6 +21,8 @@ pub extern "c" fn malloc_usable_size(?*const anyopaque) usize;
 
 pub extern "c" fn getpid() pid_t;
 
+pub extern "c" fn kinfo_getfile(pid: pid_t, cntp: *c_int) ?[*]kinfo_file;
+
 pub const sf_hdtr = extern struct {
     headers: [*]const iovec_const,
     hdr_cnt: c_int,
lib/std/os.zig
@@ -5131,20 +5131,54 @@ 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),
+            if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .gt) {
+                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 {
+                // This fallback implementation reimplements libutil's `kinfo_getfile()`.
+                // The motivation is to avoid linking -lutil when building zig or general
+                // user executables.
+                var mib = [4]c_int{ CTL.KERN, KERN.PROC, KERN.PROC_FILEDESC, system.getpid() };
+                var len: usize = undefined;
+                sysctl(&mib, null, &len, null, 0) catch |err| switch (err) {
+                    error.PermissionDenied => unreachable,
+                    error.SystemResources => return error.SystemResources,
+                    error.NameTooLong => unreachable,
+                    error.UnknownName => unreachable,
+                    else => return error.Unexpected,
+                };
+                len = len * 4 / 3;
+                const buf = std.heap.c_allocator.alloc(u8, len) catch return error.SystemResources;
+                defer std.heap.c_allocator.free(buf);
+                len = buf.len;
+                sysctl(&mib, &buf[0], &len, null, 0) catch |err| switch (err) {
+                    error.PermissionDenied => unreachable,
+                    error.SystemResources => return error.SystemResources,
+                    error.NameTooLong => unreachable,
+                    error.UnknownName => unreachable,
+                    else => return error.Unexpected,
+                };
+                var i: usize = 0;
+                while (i < len) {
+                    const kf: *align(1) system.kinfo_file = @ptrCast(*align(1) system.kinfo_file, &buf[i]);
+                    if (kf.fd == fd) {
+                        len = mem.indexOfScalar(u8, &kf.path, 0) orelse MAX_PATH_BYTES;
+                        if (len == 0) return error.NameTooLong;
+                        mem.copy(u8, out_buffer, kf.path[0..len]);
+                        return out_buffer[0..len];
+                    }
+                    i += @intCast(usize, kf.structsize);
+                }
+                return error.InvalidHandle;
             }
-
-            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"),
     }