Skip to content

Commit 99a7b6a

Browse files
committed
Fix getUserInfo on MacOS
Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
1 parent cab6d75 commit 99a7b6a

File tree

1 file changed

+33
-3
lines changed

1 file changed

+33
-3
lines changed

lib/std/process.zig

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,7 +1526,7 @@ pub const UserInfo = struct {
15261526
gid: posix.gid_t,
15271527
};
15281528

1529-
/// POSIX function which gets a uid from username.
1529+
/// POSIX function which gets a uid and gid from username.
15301530
pub fn getUserInfo(name: []const u8) !UserInfo {
15311531
return switch (native_os) {
15321532
.linux,
@@ -1547,9 +1547,27 @@ pub fn getUserInfo(name: []const u8) !UserInfo {
15471547
};
15481548
}
15491549

1550-
/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
1551-
/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
1550+
/// POSIX function to fetch uid and gid from username.
1551+
///
1552+
/// Uses the `getpwnam` when linking against libc, otherwise reads from `/etc/passwd`.
15521553
pub fn posixGetUserInfo(name: []const u8) !UserInfo {
1554+
// Prefer getpwnam when linking against libc, as it looks not only in /etc/passwd,
1555+
// but also in other sources like NIS, LDAP, Directory Services on MacOS, etc.
1556+
// See https://man7.org/linux/man-pages/man3/getpwnam.3.html
1557+
if (builtin.link_libc) {
1558+
// Make \0 terminated string.
1559+
// 256 is a safe buffer size to cover all modern systems.
1560+
var name_buf: [256]u8 = undefined;
1561+
const name_z = try std.fmt.bufPrintZ(&name_buf, "{s}", .{name});
1562+
1563+
const passwd = std.c.getpwnam(name_z) orelse return error.UserNotFound;
1564+
1565+
return UserInfo{
1566+
.uid = passwd.uid,
1567+
.gid = passwd.gid,
1568+
};
1569+
}
1570+
15531571
const file = try std.fs.openFileAbsolute("/etc/passwd", .{});
15541572
defer file.close();
15551573

@@ -1651,6 +1669,18 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
16511669
}
16521670
}
16531671

1672+
test posixGetUserInfo {
1673+
if (!builtin.link_libc) return error.SkipZigTest;
1674+
1675+
const nobody = try posixGetUserInfo("nobody");
1676+
try testing.expect(nobody.uid != 0);
1677+
try testing.expect(nobody.gid != 0);
1678+
1679+
// Test with a non-existing user.
1680+
const err = posixGetUserInfo("non_existing_user");
1681+
try testing.expectError(error.UserNotFound, err);
1682+
}
1683+
16541684
pub fn getBaseAddress() usize {
16551685
switch (native_os) {
16561686
.linux => {

0 commit comments

Comments
 (0)