const std = @import("std"); const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const ArenaAllocator = std.heap.ArenaAllocator; const log = std.log.scoped(.passwd); /// Used to determine the default shell and directory on Unixes. const c = @cImport({ @cInclude("sys/types.h"); @cInclude("unistd.h"); @cInclude("pwd.h"); }); // Entry that is retrieved from the passwd API. This only contains the fields // we care about. pub const Entry = struct { shell: ?[]const u8 = null, home: ?[]const u8 = null, }; /// Get the passwd entry for the currently executing user. pub fn get(alloc: Allocator) !Entry { var buf: [1024]u8 = undefined; var pw: c.struct_passwd = undefined; var pw_ptr: ?*c.struct_passwd = null; const res = c.getpwuid_r(c.getuid(), &pw, &buf, buf.len, &pw_ptr); if (res != 0) { log.warn("error retrieving pw entry code={d}", .{res}); return Entry{}; } if (pw_ptr == null) { // Future: let's check if a better shell is available like zsh log.warn("no pw entry to detect default shell, will default to 'sh'", .{}); return Entry{}; } var result: Entry = .{}; if (pw.pw_shell) |ptr| { const source = std.mem.sliceTo(ptr, 0); const sh = try alloc.alloc(u8, source.len); std.mem.copy(u8, sh, source); result.shell = sh; } if (pw.pw_dir) |ptr| { const source = std.mem.sliceTo(ptr, 0); const dir = try alloc.alloc(u8, source.len); std.mem.copy(u8, dir, source); result.home = dir; } return result; } test { const testing = std.testing; var arena = ArenaAllocator.init(testing.allocator); defer arena.deinit(); const alloc = arena.allocator(); // We should be able to get an entry const entry = try get(alloc); try testing.expect(entry.shell != null); try testing.expect(entry.home != null); }