[libc-commits] [libc] 14f097e - [libc] Add getpwnam and getpwuid entrypoints (#221169)
via libc-commits
libc-commits at lists.llvm.org
Fri Sep 4 08:00:56 PDT 2026
Author: Jeff Bailey
Date: 2026-09-04T16:00:51+01:00
New Revision: 14f097ec3f2bef83e852d9ded7b117fcf2f4e103
URL: https://github.com/llvm/llvm-project/commit/14f097ec3f2bef83e852d9ded7b117fcf2f4e103
DIFF: https://github.com/llvm/llvm-project/commit/14f097ec3f2bef83e852d9ded7b117fcf2f4e103.diff
LOG: [libc] Add getpwnam and getpwuid entrypoints (#221169)
Added non-reentrant getpwnam and getpwuid functions using the shared
process-global buffer.
* Implemented getpwnam and getpwuid entrypoints
* Added non-reentrant find_by_name and find_by_uid lookups
* Added function specifications to include/pwd.yaml
* Registered entrypoints in config/linux/*/entrypoints.txt
* Added unit tests in libc/test/src/pwd/getpwnam_test.cpp and
libc/test/src/pwd/getpwuid_test.cpp
Assisted-by: Automated tooling, human reviewed.
Added:
libc/src/pwd/getpwnam.cpp
libc/src/pwd/getpwnam.h
libc/src/pwd/getpwuid.cpp
libc/src/pwd/getpwuid.h
libc/test/src/pwd/getpwnam_test.cpp
libc/test/src/pwd/getpwuid_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/arm/entrypoints.txt
libc/config/linux/i386/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/pwd.yaml
libc/src/pwd/CMakeLists.txt
libc/src/pwd/pwd_utils.cpp
libc/src/pwd/pwd_utils.h
libc/test/src/pwd/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index cf6a6c2815a7b..cc0cb0eb56d12 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -48,7 +48,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# pwd.h entrypoints
libc.src.pwd.endpwent
libc.src.pwd.getpwent
+ libc.src.pwd.getpwnam
libc.src.pwd.getpwnam_r
+ libc.src.pwd.getpwuid
libc.src.pwd.getpwuid_r
libc.src.pwd.setpwent
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 79b674fd99e9f..7d2daae7a89c7 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -36,7 +36,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# pwd.h entrypoints
libc.src.pwd.endpwent
libc.src.pwd.getpwent
+ libc.src.pwd.getpwnam
libc.src.pwd.getpwnam_r
+ libc.src.pwd.getpwuid
libc.src.pwd.getpwuid_r
libc.src.pwd.setpwent
diff --git a/libc/config/linux/i386/entrypoints.txt b/libc/config/linux/i386/entrypoints.txt
index 1b84b0e7a0519..4766ea1522cae 100644
--- a/libc/config/linux/i386/entrypoints.txt
+++ b/libc/config/linux/i386/entrypoints.txt
@@ -5,7 +5,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# pwd.h entrypoints
libc.src.pwd.endpwent
libc.src.pwd.getpwent
+ libc.src.pwd.getpwnam
libc.src.pwd.getpwnam_r
+ libc.src.pwd.getpwuid
libc.src.pwd.getpwuid_r
libc.src.pwd.setpwent
)
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 9272a670d35d6..f574a225c092f 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -67,7 +67,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# pwd.h entrypoints
libc.src.pwd.endpwent
libc.src.pwd.getpwent
+ libc.src.pwd.getpwnam
libc.src.pwd.getpwnam_r
+ libc.src.pwd.getpwuid
libc.src.pwd.getpwuid_r
libc.src.pwd.setpwent
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 28f2b9a480ef3..4de6a291fef66 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -67,7 +67,9 @@ set(TARGET_LIBC_ENTRYPOINTS
# pwd.h entrypoints
libc.src.pwd.endpwent
libc.src.pwd.getpwent
+ libc.src.pwd.getpwnam
libc.src.pwd.getpwnam_r
+ libc.src.pwd.getpwuid
libc.src.pwd.getpwuid_r
libc.src.pwd.setpwent
diff --git a/libc/include/pwd.yaml b/libc/include/pwd.yaml
index ef3656f3a1042..9301307d22d3a 100644
--- a/libc/include/pwd.yaml
+++ b/libc/include/pwd.yaml
@@ -24,6 +24,12 @@ functions:
- posix
return_type: void
arguments: []
+ - name: getpwnam
+ standards:
+ - posix
+ return_type: struct passwd *
+ arguments:
+ - type: const char *
- name: getpwnam_r
standards:
- posix
@@ -34,6 +40,12 @@ functions:
- type: char *
- type: size_t
- type: struct passwd **
+ - name: getpwuid
+ standards:
+ - posix
+ return_type: struct passwd *
+ arguments:
+ - type: uid_t
- name: getpwuid_r
standards:
- posix
diff --git a/libc/src/pwd/CMakeLists.txt b/libc/src/pwd/CMakeLists.txt
index 0a5aaca358cd0..c2b86dab45db8 100644
--- a/libc/src/pwd/CMakeLists.txt
+++ b/libc/src/pwd/CMakeLists.txt
@@ -42,6 +42,21 @@ add_entrypoint_object(
.pwd_utils
)
+add_entrypoint_object(
+ getpwnam
+ SRCS
+ getpwnam.cpp
+ HDRS
+ getpwnam.h
+ DEPENDS
+ libc.hdr.types.struct_passwd
+ libc.src.errno.errno
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ .pwd_utils
+)
+
add_entrypoint_object(
getpwnam_r
SRCS
@@ -59,6 +74,21 @@ add_entrypoint_object(
.pwd_utils
)
+add_entrypoint_object(
+ getpwuid
+ SRCS
+ getpwuid.cpp
+ HDRS
+ getpwuid.h
+ DEPENDS
+ libc.hdr.types.struct_passwd
+ libc.hdr.types.uid_t
+ libc.src.errno.errno
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ .pwd_utils
+)
+
add_entrypoint_object(
getpwuid_r
SRCS
diff --git a/libc/src/pwd/getpwnam.cpp b/libc/src/pwd/getpwnam.cpp
new file mode 100644
index 0000000000000..d57589ced2a7b
--- /dev/null
+++ b/libc/src/pwd/getpwnam.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of getpwnam.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/getpwnam.h"
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/null_check.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwnam, (const char *name)) {
+ LIBC_CRASH_ON_NULLPTR(name);
+
+ auto res = pwd::find_by_name(name);
+ if (!res.has_value()) {
+ libc_errno = res.error();
+ return nullptr;
+ }
+ return res.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/getpwnam.h b/libc/src/pwd/getpwnam.h
new file mode 100644
index 0000000000000..3e07b6eafbcc4
--- /dev/null
+++ b/libc/src/pwd/getpwnam.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header file for getpwnam function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_GETPWNAM_H
+#define LLVM_LIBC_SRC_PWD_GETPWNAM_H
+
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Searches the password database for an entry with the matching username.
+struct passwd *getpwnam(const char *name);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_GETPWNAM_H
diff --git a/libc/src/pwd/getpwuid.cpp b/libc/src/pwd/getpwuid.cpp
new file mode 100644
index 0000000000000..61d527856ff2b
--- /dev/null
+++ b/libc/src/pwd/getpwuid.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of getpwuid.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/getpwuid.h"
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwuid, (uid_t uid)) {
+ auto res = pwd::find_by_uid(uid);
+ if (!res.has_value()) {
+ libc_errno = res.error();
+ return nullptr;
+ }
+ return res.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/getpwuid.h b/libc/src/pwd/getpwuid.h
new file mode 100644
index 0000000000000..26ce10430794b
--- /dev/null
+++ b/libc/src/pwd/getpwuid.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header file for getpwuid function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_GETPWUID_H
+#define LLVM_LIBC_SRC_PWD_GETPWUID_H
+
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Searches the password database for an entry with the matching user ID.
+struct passwd *getpwuid(uid_t uid);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_GETPWUID_H
diff --git a/libc/src/pwd/pwd_utils.cpp b/libc/src/pwd/pwd_utils.cpp
index cc10a21bef021..c9134d3f4c962 100644
--- a/libc/src/pwd/pwd_utils.cpp
+++ b/libc/src/pwd/pwd_utils.cpp
@@ -93,5 +93,25 @@ ErrorOr<bool> find_by_uid(uid_t uid, struct passwd *pwd, cpp::span<char> buffer,
return local_db.lookup(matcher, pwd, buffer);
}
+ErrorOr<struct passwd *> find_by_name(cpp::string_view name) {
+ auto res = find_by_name(name, &pwd_entry, line_buffer);
+ if (!res.has_value())
+ return Error(res.error());
+ bool found = res.value();
+ if (!found)
+ return nullptr;
+ return &pwd_entry;
+}
+
+ErrorOr<struct passwd *> find_by_uid(uid_t uid) {
+ auto res = find_by_uid(uid, &pwd_entry, line_buffer);
+ if (!res.has_value())
+ return Error(res.error());
+ bool found = res.value();
+ if (!found)
+ return nullptr;
+ return &pwd_entry;
+}
+
} // namespace pwd
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/pwd_utils.h b/libc/src/pwd/pwd_utils.h
index 249de89e258d2..75c6fbe389570 100644
--- a/libc/src/pwd/pwd_utils.h
+++ b/libc/src/pwd/pwd_utils.h
@@ -107,6 +107,14 @@ ErrorOr<void> close();
// Reads the next entry from the password database.
ErrorOr<struct passwd *> read_next();
+// Searches for a password entry matching the given username using the
+// static process-global buffer.
+ErrorOr<struct passwd *> find_by_name(cpp::string_view name);
+
+// Searches for a password entry matching the given user ID using the
+// static process-global buffer.
+ErrorOr<struct passwd *> find_by_uid(uid_t uid);
+
// Searches for a password entry matching the given username.
// The optional path parameter allows unit tests to direct lookups to hermetic
// test database files without mutating global state.
diff --git a/libc/test/src/pwd/CMakeLists.txt b/libc/test/src/pwd/CMakeLists.txt
index fe063ebdaf068..043ba44ceb6e9 100644
--- a/libc/test/src/pwd/CMakeLists.txt
+++ b/libc/test/src/pwd/CMakeLists.txt
@@ -65,6 +65,29 @@ add_libc_test(
libc.src.string.string_utils
)
+add_libc_test(
+ getpwnam_test
+ SUITE
+ libc_pwd_unittests
+ HDRS
+ pwd_test_utils.h
+ SRCS
+ getpwnam_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.types.gid_t
+ libc.hdr.types.size_t
+ libc.hdr.types.struct_passwd
+ libc.hdr.types.uid_t
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
+ libc.src.errno.errno
+ libc.src.pwd.getpwnam
+ libc.src.pwd.pwd_utils
+ libc.src.stdio.remove
+ libc.src.string.string_utils
+)
+
add_libc_test(
getpwnam_r_test
SUITE
@@ -87,6 +110,29 @@ add_libc_test(
libc.src.string.string_utils
)
+add_libc_test(
+ getpwuid_test
+ SUITE
+ libc_pwd_unittests
+ HDRS
+ pwd_test_utils.h
+ SRCS
+ getpwuid_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.types.gid_t
+ libc.hdr.types.size_t
+ libc.hdr.types.struct_passwd
+ libc.hdr.types.uid_t
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
+ libc.src.errno.errno
+ libc.src.pwd.getpwuid
+ libc.src.pwd.pwd_utils
+ libc.src.stdio.remove
+ libc.src.string.string_utils
+)
+
add_libc_test(
getpwuid_r_test
SUITE
diff --git a/libc/test/src/pwd/getpwnam_test.cpp b/libc/test/src/pwd/getpwnam_test.cpp
new file mode 100644
index 0000000000000..17b70b9215ebd
--- /dev/null
+++ b/libc/test/src/pwd/getpwnam_test.cpp
@@ -0,0 +1,118 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for getpwnam.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/gid_t.h"
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "pwd_test_utils.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/getpwnam.h"
+#include "src/pwd/pwd_utils.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcGetpwnamTest = LlvmLibcPwdTest;
+
+TEST_F(LlvmLibcGetpwnamTest, Success) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+ "bin:x:1:1:bin:/bin:/sbin/nologin\n"
+ "daemon:x:2:2:daemon:/sbin:/sbin/nologin\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_success.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwnam("bin");
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "bin");
+ ASSERT_STREQ(pwd->pw_passwd, "x");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+ ASSERT_EQ(pwd->pw_gid, static_cast<gid_t>(1));
+ ASSERT_STREQ(pwd->pw_gecos, "bin");
+ ASSERT_STREQ(pwd->pw_dir, "/bin");
+ ASSERT_STREQ(pwd->pw_shell, "/sbin/nologin");
+}
+
+TEST_F(LlvmLibcGetpwnamTest, FirstAndLastEntries) {
+ const char *content = "first:x:100:100:first:/home/first:/bin/sh\n"
+ "middle:x:101:101:middle:/home/middle:/bin/sh\n"
+ "last:x:102:102:last:/home/last:/bin/sh\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_boundary.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwnam("first");
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "first");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(100));
+
+ pwd = LIBC_NAMESPACE::getpwnam("last");
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "last");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(102));
+}
+
+TEST_F(LlvmLibcGetpwnamTest, NotFound) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_notfound.test"),
+ content);
+
+ // POSIX specifies that errno must not be changed when an entry is not found.
+ // Pre-set errno to confirm it remains untouched across the call.
+ LIBC_NAMESPACE::libc_errno = ENOENT;
+ struct passwd *pwd = LIBC_NAMESPACE::getpwnam("nonexistent");
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_EQ(ENOENT);
+
+ // When errno is initially zero, it remains zero.
+ pwd = LIBC_NAMESPACE::getpwnam("nonexistent");
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcGetpwnamTest, BlankLines) {
+ const char *content = "\nroot:x:0:0:root:/root:/bin/bash\n\n\n"
+ "bin:x:1:1:bin:/bin:/sbin/nologin\n\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_blank.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwnam("bin");
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "bin");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+}
+
+TEST_F(LlvmLibcGetpwnamTest, FileOpenFailure) {
+ LIBC_NAMESPACE::pwd::TESTONLY_set_passwd_path(
+ "/nonexistent_directory/nonexistent_file");
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwnam("root");
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_EQ(ENOENT);
+}
+
+TEST_F(LlvmLibcGetpwnamTest, BufferTooSmall) {
+ // A line exceeding line_buffer (1024 bytes) triggers ERANGE.
+ char content[1100];
+ LIBC_NAMESPACE::internal::strlcpy(content,
+ "longuser:x:1000:1000:", sizeof(content));
+ size_t cur = LIBC_NAMESPACE::internal::string_length(content);
+ for (; cur < 1050; ++cur)
+ content[cur] = 'a';
+ LIBC_NAMESPACE::internal::strlcpy(content + cur, ":/home/longuser:/bin/sh\n",
+ sizeof(content) - cur);
+
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_toosmall.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwnam("longuser");
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_EQ(ERANGE);
+}
diff --git a/libc/test/src/pwd/getpwuid_test.cpp b/libc/test/src/pwd/getpwuid_test.cpp
new file mode 100644
index 0000000000000..ac12e78a762fc
--- /dev/null
+++ b/libc/test/src/pwd/getpwuid_test.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for getpwuid.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/gid_t.h"
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "pwd_test_utils.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/getpwuid.h"
+#include "src/pwd/pwd_utils.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcGetpwuidTest = LlvmLibcPwdTest;
+
+TEST_F(LlvmLibcGetpwuidTest, Success) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+ "bin:x:1:1:bin:/bin:/sbin/nologin\n"
+ "daemon:x:2:2:daemon:/sbin:/sbin/nologin\n"
+ "nobody:x:65534:65534:nobody:/nonexistent:/bin/false\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_success.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwuid(1);
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "bin");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+ ASSERT_EQ(pwd->pw_gid, static_cast<gid_t>(1));
+ ASSERT_STREQ(pwd->pw_dir, "/bin");
+ ASSERT_STREQ(pwd->pw_shell, "/sbin/nologin");
+
+ // Lookup high UID (nobody)
+ pwd = LIBC_NAMESPACE::getpwuid(65534);
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "nobody");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(65534));
+}
+
+TEST_F(LlvmLibcGetpwuidTest, RootUidZero) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+ "bin:x:1:1:bin:/bin:/sbin/nologin\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_zero.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwuid(0);
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "root");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(0));
+}
+
+TEST_F(LlvmLibcGetpwuidTest, NotFound) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_notfound.test"),
+ content);
+
+ // POSIX specifies that errno must not be changed when an entry is not found.
+ // Pre-set errno to confirm it remains untouched across the call.
+ LIBC_NAMESPACE::libc_errno = ENOENT;
+ struct passwd *pwd = LIBC_NAMESPACE::getpwuid(999);
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_EQ(ENOENT);
+
+ // When errno is initially zero, it remains zero.
+ pwd = LIBC_NAMESPACE::getpwuid(999);
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcGetpwuidTest, BlankLines) {
+ const char *content = "\nroot:x:0:0:root:/root:/bin/bash\n\n\n"
+ "bin:x:1:1:bin:/bin:/sbin/nologin\n\n";
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_blank.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwuid(1);
+ ASSERT_NE(pwd, nullptr);
+ ASSERT_STREQ(pwd->pw_name, "bin");
+ ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+}
+
+TEST_F(LlvmLibcGetpwuidTest, FileOpenFailure) {
+ LIBC_NAMESPACE::pwd::TESTONLY_set_passwd_path(
+ "/nonexistent_directory/nonexistent_file");
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwuid(0);
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_EQ(ENOENT);
+}
+
+TEST_F(LlvmLibcGetpwuidTest, BufferTooSmall) {
+ // A line exceeding line_buffer (1024 bytes) triggers ERANGE.
+ char content[1100];
+ LIBC_NAMESPACE::internal::strlcpy(content,
+ "longuser:x:1000:1000:", sizeof(content));
+ size_t cur = LIBC_NAMESPACE::internal::string_length(content);
+ for (; cur < 1050; ++cur)
+ content[cur] = 'a';
+ LIBC_NAMESPACE::internal::strlcpy(content + cur, ":/home/longuser:/bin/sh\n",
+ sizeof(content) - cur);
+
+ ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_toosmall.test"),
+ content);
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwuid(1000);
+ ASSERT_EQ(pwd, nullptr);
+ ASSERT_ERRNO_EQ(ERANGE);
+}
More information about the libc-commits
mailing list