[libc-commits] [libc] [libc] Add getpwent, setpwent, and endpwent entrypoints (PR #213076)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Fri Aug 7 00:08:52 PDT 2026
https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/213076
>From 1a550cf2a8525509461bfbc06d402dbaceb9e432 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Tue, 28 Jul 2026 09:10:24 +0100
Subject: [PATCH 1/2] [libc] Add getpwent, setpwent, and endpwent entrypoints
Added getpwent, setpwent, and endpwent functions using the internal
pwd_utils line parser.
* Implemented getpwent.cpp, setpwent.cpp, and endpwent.cpp
* Added internal file management helpers set_passwd_path, setpwent_impl,
and endpwent_impl returning ErrorOr<int> in getpwent.h
* Registered entrypoints in config/linux/*/entrypoints.txt
* Moved add_subdirectory(pwd) into linux OS block in libc/src/CMakeLists.txt
to support overlay builds
* Added unit tests in libc/test/src/pwd/getpwent_test.cpp
Assisted-by: Automated tooling, human reviewed.
---
libc/config/linux/aarch64/entrypoints.txt | 5 +
libc/config/linux/arm/entrypoints.txt | 5 +
libc/config/linux/i386/entrypoints.txt | 5 +
libc/config/linux/riscv/entrypoints.txt | 5 +
libc/config/linux/x86_64/entrypoints.txt | 5 +
libc/src/CMakeLists.txt | 2 +-
libc/src/pwd/CMakeLists.txt | 43 ++++++
libc/src/pwd/endpwent.cpp | 29 ++++
libc/src/pwd/endpwent.h | 26 ++++
libc/src/pwd/getpwent.cpp | 170 ++++++++++++++++++++++
libc/src/pwd/getpwent.h | 40 +++++
libc/src/pwd/setpwent.cpp | 29 ++++
libc/src/pwd/setpwent.h | 26 ++++
libc/test/src/pwd/CMakeLists.txt | 18 +++
libc/test/src/pwd/getpwent_test.cpp | 152 +++++++++++++++++++
15 files changed, 559 insertions(+), 1 deletion(-)
create mode 100644 libc/src/pwd/endpwent.cpp
create mode 100644 libc/src/pwd/endpwent.h
create mode 100644 libc/src/pwd/getpwent.cpp
create mode 100644 libc/src/pwd/getpwent.h
create mode 100644 libc/src/pwd/setpwent.cpp
create mode 100644 libc/src/pwd/setpwent.h
create mode 100644 libc/test/src/pwd/getpwent_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 1d5244b9c443e..5686c6e095254 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -45,6 +45,11 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# sched.h entrypoints
libc.src.sched.sched_get_priority_max
libc.src.sched.sched_get_priority_min
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 1986d6a5347dc..f80a0acaf7c10 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -33,6 +33,11 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# string.h entrypoints
libc.src.string.memccpy
libc.src.string.memchr
diff --git a/libc/config/linux/i386/entrypoints.txt b/libc/config/linux/i386/entrypoints.txt
index 6548c9b816c93..3942289a2e5b2 100644
--- a/libc/config/linux/i386/entrypoints.txt
+++ b/libc/config/linux/i386/entrypoints.txt
@@ -1,6 +1,11 @@
set(TARGET_LIBC_ENTRYPOINTS
# errno.h entrypoints
libc.src.errno.errno
+
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
)
set(TARGET_LIBM_ENTRYPOINTS "")
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 0f7822b36a761..f95cfd3820708 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -64,6 +64,11 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# sched.h entrypoints
libc.src.sched.getcpu
libc.src.sched.sched_get_priority_max
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 7a9e741310c6a..e257bc19b2920 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -64,6 +64,11 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# sched.h entrypoints
libc.src.sched.getcpu
libc.src.sched.sched_get_priority_max
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 05944b582b5f8..4e7aaa1112ed7 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -31,6 +31,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
add_subdirectory(fcntl)
add_subdirectory(poll)
add_subdirectory(pthread)
+ add_subdirectory(pwd)
add_subdirectory(sched)
add_subdirectory(semaphore)
add_subdirectory(sys)
@@ -56,4 +57,3 @@ add_subdirectory(signal)
add_subdirectory(spawn)
add_subdirectory(threads)
add_subdirectory(ucontext)
-add_subdirectory(pwd)
diff --git a/libc/src/pwd/CMakeLists.txt b/libc/src/pwd/CMakeLists.txt
index f8498b27eaa54..96d58c68359c0 100644
--- a/libc/src/pwd/CMakeLists.txt
+++ b/libc/src/pwd/CMakeLists.txt
@@ -1,3 +1,46 @@
+add_entrypoint_object(
+ getpwent
+ SRCS
+ getpwent.cpp
+ HDRS
+ getpwent.h
+ DEPENDS
+ libc.hdr.types.struct_passwd
+ libc.src.errno.errno
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
+ libc.hdr.stdio_macros
+ .pwd_utils
+)
+
+add_entrypoint_object(
+ setpwent
+ SRCS
+ setpwent.cpp
+ HDRS
+ setpwent.h
+ DEPENDS
+ libc.src.errno.errno
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ .getpwent
+)
+
+add_entrypoint_object(
+ endpwent
+ SRCS
+ endpwent.cpp
+ HDRS
+ endpwent.h
+ DEPENDS
+ libc.src.errno.errno
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ .getpwent
+)
+
add_object_library(
pwd_utils
HDRS
diff --git a/libc/src/pwd/endpwent.cpp b/libc/src/pwd/endpwent.cpp
new file mode 100644
index 0000000000000..c0e920e475ad2
--- /dev/null
+++ b/libc/src/pwd/endpwent.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 endpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/endpwent.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/getpwent.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, endpwent, ()) {
+ // endpwent_impl closes the password file. If an error occurs,
+ // it returns an Error with an errno value which is set here.
+ auto res = endpwent_impl();
+ if (!res.has_value())
+ libc_errno = res.error();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/endpwent.h b/libc/src/pwd/endpwent.h
new file mode 100644
index 0000000000000..e23ef3ea6dadf
--- /dev/null
+++ b/libc/src/pwd/endpwent.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 endpwent function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_ENDPWENT_H
+#define LLVM_LIBC_SRC_PWD_ENDPWENT_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Closes the password database stream and releases associated resources.
+void endpwent();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_ENDPWENT_H
diff --git a/libc/src/pwd/getpwent.cpp b/libc/src/pwd/getpwent.cpp
new file mode 100644
index 0000000000000..6a69f92b71694
--- /dev/null
+++ b/libc/src/pwd/getpwent.cpp
@@ -0,0 +1,170 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 getpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/getpwent.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/File/file.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/pwd/pwd_utils.h"
+
+#include "hdr/stdio_macros.h"
+
+#ifndef LIBC_COPT_PWD_FILE_PATH
+#define LIBC_COPT_PWD_FILE_PATH "/etc/passwd"
+#endif
+
+namespace LIBC_NAMESPACE_DECL {
+
+static File *pwd_file = nullptr;
+static const char *pwd_file_path = LIBC_COPT_PWD_FILE_PATH;
+// Note: These static buffers are process-global and NOT protected by a mutex
+// at this stage. POSIX getpwent is non-reentrant.
+static char line_buffer[1024];
+static struct passwd pwd_entry;
+
+namespace internal {
+void set_passwd_path(const char *path) {
+ if (!path)
+ return;
+ if (pwd_file) {
+ pwd_file->close();
+ pwd_file = nullptr;
+ }
+ pwd_file_path = path;
+}
+} // namespace internal
+
+ErrorOr<int> setpwent_impl() {
+ if (!pwd_file) {
+ auto result = openfile(pwd_file_path, "r");
+ if (!result.has_value())
+ return Error(result.error());
+ pwd_file = result.value();
+ } else {
+ auto result = pwd_file->seek(0, SEEK_SET);
+ if (!result.has_value())
+ return Error(result.error());
+ }
+ return 0;
+}
+
+ErrorOr<int> endpwent_impl() {
+ if (pwd_file) {
+ int result = pwd_file->close();
+ pwd_file = nullptr;
+ if (result != 0)
+ return Error(result);
+ }
+ return 0;
+}
+
+struct ReadLineResult {
+ size_t bytes_read;
+ bool truncated;
+};
+
+// Reads a line from the given file into buf.
+static ErrorOr<ReadLineResult> read_line(File *f, cpp::span<char> buf) {
+ if (!f || buf.empty())
+ return Error(EINVAL);
+
+ f->lock();
+ size_t bytes_read = 0;
+ FileIOResult result(0);
+ bool truncated = false;
+
+ for (char &ch : buf.first(buf.size() - 1)) {
+ result = f->read_unlocked(&ch, 1);
+ if (result.has_error()) {
+ f->unlock();
+ return Error(result.error);
+ }
+ if (result.value != 1)
+ break;
+ ++bytes_read;
+ if (ch == '\n')
+ break;
+ }
+
+ if (result.value == 1 && bytes_read > 0 && buf[bytes_read - 1] != '\n') {
+ truncated = true;
+ char c = '\0';
+ while (true) {
+ result = f->read_unlocked(&c, 1);
+ if (result.has_error()) {
+ f->unlock();
+ return Error(result.error);
+ }
+ if (result.value != 1 || c == '\n')
+ break;
+ }
+ }
+
+ bool has_error = f->error_unlocked();
+ bool has_eof = f->iseof_unlocked();
+ f->unlock();
+
+ if (has_error)
+ return Error(EIO);
+
+ if (bytes_read == 0 && has_eof)
+ return ReadLineResult{0, false};
+
+ buf[bytes_read] = '\0';
+ return ReadLineResult{bytes_read, truncated};
+}
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwent, ()) {
+ if (!pwd_file) {
+ auto result = openfile(pwd_file_path, "r");
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return nullptr;
+ }
+ pwd_file = result.value();
+ }
+
+ while (true) {
+ auto result = read_line(pwd_file, line_buffer);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return nullptr;
+ }
+
+ ReadLineResult res = result.value();
+ if (res.bytes_read == 0)
+ return nullptr;
+
+ if (res.truncated) {
+ libc_errno = EINVAL;
+ return nullptr;
+ }
+
+ size_t len = res.bytes_read;
+ if (len > 0 && line_buffer[len - 1] == '\n')
+ line_buffer[len - 1] = '\0';
+
+ auto passwd_or = internal::parse_passwd_line(line_buffer);
+ if (!passwd_or.has_value()) {
+ libc_errno = passwd_or.error();
+ return nullptr;
+ }
+
+ pwd_entry = passwd_or.value();
+ return &pwd_entry;
+ }
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/getpwent.h b/libc/src/pwd/getpwent.h
new file mode 100644
index 0000000000000..d116ee0376433
--- /dev/null
+++ b/libc/src/pwd/getpwent.h
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 getpwent function and internal helpers.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_GETPWENT_H
+#define LLVM_LIBC_SRC_PWD_GETPWENT_H
+
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+// Overrides the default password file path for testing purposes.
+void set_passwd_path(const char *path);
+
+} // namespace internal
+
+// Internal helper function to open or rewind the password file.
+ErrorOr<int> setpwent_impl();
+
+// Internal helper function to close the password file.
+ErrorOr<int> endpwent_impl();
+
+// Reads the next entry from the password database.
+struct passwd *getpwent();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_GETPWENT_H
diff --git a/libc/src/pwd/setpwent.cpp b/libc/src/pwd/setpwent.cpp
new file mode 100644
index 0000000000000..c5817482591ef
--- /dev/null
+++ b/libc/src/pwd/setpwent.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 setpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/setpwent.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/getpwent.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, setpwent, ()) {
+ // setpwent_impl opens or rewinds the password file. If an error occurs,
+ // it returns an Error with an errno value which is set here.
+ auto res = setpwent_impl();
+ if (!res.has_value())
+ libc_errno = res.error();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/setpwent.h b/libc/src/pwd/setpwent.h
new file mode 100644
index 0000000000000..90dda5f9c7c2b
--- /dev/null
+++ b/libc/src/pwd/setpwent.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 setpwent function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_SETPWENT_H
+#define LLVM_LIBC_SRC_PWD_SETPWENT_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Rewinds the password database stream to the beginning.
+void setpwent();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_SETPWENT_H
diff --git a/libc/test/src/pwd/CMakeLists.txt b/libc/test/src/pwd/CMakeLists.txt
index eb6c96f2f296f..254d740bc05ee 100644
--- a/libc/test/src/pwd/CMakeLists.txt
+++ b/libc/test/src/pwd/CMakeLists.txt
@@ -11,3 +11,21 @@ add_libc_unittest(
libc.hdr.types.struct_passwd
libc.src.pwd.pwd_utils
)
+
+add_libc_unittest(
+ getpwent_test
+ SUITE
+ libc_pwd_unittests
+ SRCS
+ getpwent_test.cpp
+ DEPENDS
+ libc.hdr.types.struct_passwd
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
+ libc.src.errno.errno
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.pwd_utils
+ libc.src.pwd.setpwent
+ libc.src.stdio.remove
+)
diff --git a/libc/test/src/pwd/getpwent_test.cpp b/libc/test/src/pwd/getpwent_test.cpp
new file mode 100644
index 0000000000000..67c7bb19508a1
--- /dev/null
+++ b/libc/test/src/pwd/getpwent_test.cpp
@@ -0,0 +1,152 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 getpwent, setpwent, and endpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/File/file.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/endpwent.h"
+#include "src/pwd/getpwent.h"
+#include "src/pwd/pwd_utils.h"
+#include "src/pwd/setpwent.h"
+#include "src/stdio/remove.h"
+#include "test/UnitTest/Test.h"
+
+namespace {
+
+// RAII helper class for creating and automatically removing temporary test
+// files.
+class HermeticFile {
+ char path[256];
+
+public:
+ HermeticFile(const char *file_path, const char *content) {
+ size_t i = 0;
+ for (; file_path[i] && i < sizeof(path) - 1; ++i)
+ path[i] = file_path[i];
+ path[i] = '\0';
+
+ auto file_or = LIBC_NAMESPACE::openfile(path, "w");
+ if (file_or.has_value()) {
+ auto *f = file_or.value();
+ size_t len = 0;
+ for (const char *p = content; *p; ++p)
+ ++len;
+ f->write(content, len);
+ f->close();
+ }
+ }
+
+ ~HermeticFile() { LIBC_NAMESPACE::remove(path); }
+
+ const char *get_path() const { return path; }
+};
+
+} // namespace
+
+TEST(LlvmLibcPwdTest, GetPwentTestSuccess) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+ "bin:x:1:1:bin:/bin:/sbin/nologin\n";
+ HermeticFile test_file(libc_make_test_file_path("getpwent_success.test"),
+ content);
+
+ LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::setpwent();
+
+ struct passwd *pwd1 = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd1 != nullptr);
+ ASSERT_STREQ(pwd1->pw_name, "root");
+ ASSERT_EQ(pwd1->pw_uid, 0u);
+
+ struct passwd *pwd2 = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd2 != nullptr);
+ ASSERT_STREQ(pwd2->pw_name, "bin");
+ ASSERT_EQ(pwd2->pw_uid, 1u);
+
+ struct passwd *pwd3 = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd3 == nullptr);
+
+ LIBC_NAMESPACE::endpwent();
+}
+
+TEST(LlvmLibcPwdTest, GetPwentTestFailure) {
+ const char *content = "invalid_line_without_enough_fields\n";
+ HermeticFile test_file(libc_make_test_file_path("getpwent_fail.test"),
+ content);
+
+ LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::setpwent();
+
+ libc_errno = 0;
+ struct passwd *pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd == nullptr);
+ ASSERT_EQ(static_cast<int>(libc_errno), EINVAL);
+
+ LIBC_NAMESPACE::endpwent();
+}
+
+TEST(LlvmLibcPwdTest, SetPwentTestHermetic) {
+ const char *content = "user1:x:1000:1000:User One:/home/user1:/bin/bash\n"
+ "user2:x:1001:1001:User Two:/home/user2:/bin/bash\n";
+ HermeticFile test_file(libc_make_test_file_path("setpwent_hermetic.test"),
+ content);
+
+ LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd != nullptr);
+ ASSERT_STREQ(pwd->pw_name, "user1");
+
+ pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd != nullptr);
+ ASSERT_STREQ(pwd->pw_name, "user2");
+
+ // Reset iteration
+ LIBC_NAMESPACE::setpwent();
+
+ pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd != nullptr);
+ ASSERT_STREQ(pwd->pw_name, "user1");
+
+ LIBC_NAMESPACE::endpwent();
+}
+
+TEST(LlvmLibcPwdTest, ReopenAfterEndpwent) {
+ const char *content = "root:x:0:0:root:/root:/bin/bash\n";
+ HermeticFile test_file(libc_make_test_file_path("reopen_endpwent.test"),
+ content);
+
+ LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd != nullptr);
+ ASSERT_STREQ(pwd->pw_name, "root");
+
+ LIBC_NAMESPACE::endpwent();
+
+ pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd != nullptr);
+ ASSERT_STREQ(pwd->pw_name, "root");
+
+ LIBC_NAMESPACE::endpwent();
+}
+
+TEST(LlvmLibcPwdTest, FileOpenFailure) {
+ LIBC_NAMESPACE::internal::set_passwd_path(
+ "/nonexistent_directory/nonexistent_file");
+ LIBC_NAMESPACE::endpwent(); // Force close any existing file
+
+ libc_errno = 0;
+ struct passwd *pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd == nullptr);
+ ASSERT_EQ(static_cast<int>(libc_errno), ENOENT);
+}
>From bb6fda5d5574bc7fc58290e6fa99332a07f69c66 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Mon, 3 Aug 2026 21:07:03 +0100
Subject: [PATCH 2/2] [libc] Refactor pwd database state into passwd namespace
Moved password database file state (pwd_file, line_buffer, pwd_entry)
and reading/rewinding/closing logic into namespace passwd in pwd_utils.h / pwd_utils.cpp
* Decoupled setpwent and endpwent from depending on getpwent in CMake
* Added target guards for File and platform_file in src/pwd and test/src/pwd CMakeLists.txt
* Reused open() in read_next() and simplified read_line return
* Updated getpwent_test to use ErrnoCheckingTest, ASSERT_ERRNO_EQ,
internal::strlcpy, and passwd::TESTONLY_set_passwd_path
Assisted-by: Automated tooling, human reviewed.
---
libc/src/pwd/CMakeLists.txt | 15 ++-
libc/src/pwd/endpwent.cpp | 6 +-
libc/src/pwd/getpwent.cpp | 150 +---------------------------
libc/src/pwd/getpwent.h | 15 +--
libc/src/pwd/pwd_utils.cpp | 136 +++++++++++++++++++++++++
libc/src/pwd/pwd_utils.h | 16 +++
libc/src/pwd/setpwent.cpp | 6 +-
libc/test/src/pwd/CMakeLists.txt | 5 +
libc/test/src/pwd/getpwent_test.cpp | 42 ++++----
9 files changed, 198 insertions(+), 193 deletions(-)
diff --git a/libc/src/pwd/CMakeLists.txt b/libc/src/pwd/CMakeLists.txt
index 96d58c68359c0..4cde157adf673 100644
--- a/libc/src/pwd/CMakeLists.txt
+++ b/libc/src/pwd/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(NOT TARGET libc.src.__support.File.file OR NOT TARGET libc.src.__support.File.platform_file)
+ return()
+endif()
+
add_entrypoint_object(
getpwent
SRCS
@@ -9,9 +13,6 @@ add_entrypoint_object(
libc.src.errno.errno
libc.src.__support.common
libc.src.__support.macros.config
- libc.src.__support.File.file
- libc.src.__support.File.platform_file
- libc.hdr.stdio_macros
.pwd_utils
)
@@ -25,7 +26,7 @@ add_entrypoint_object(
libc.src.errno.errno
libc.src.__support.common
libc.src.__support.macros.config
- .getpwent
+ .pwd_utils
)
add_entrypoint_object(
@@ -38,7 +39,7 @@ add_entrypoint_object(
libc.src.errno.errno
libc.src.__support.common
libc.src.__support.macros.config
- .getpwent
+ .pwd_utils
)
add_object_library(
@@ -49,8 +50,12 @@ add_object_library(
pwd_utils.cpp
DEPENDS
libc.hdr.errno_macros
+ libc.hdr.stdio_macros
libc.hdr.types.struct_passwd
libc.src.string.string_utils
+ libc.src.__support.CPP.span
+ libc.src.__support.File.file
+ libc.src.__support.File.platform_file
libc.src.__support.ctype_utils
libc.src.__support.error_or
libc.src.__support.str_to_integer
diff --git a/libc/src/pwd/endpwent.cpp b/libc/src/pwd/endpwent.cpp
index c0e920e475ad2..e5edde36d0d2d 100644
--- a/libc/src/pwd/endpwent.cpp
+++ b/libc/src/pwd/endpwent.cpp
@@ -14,14 +14,12 @@
#include "src/pwd/endpwent.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
-#include "src/pwd/getpwent.h"
+#include "src/pwd/pwd_utils.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(void, endpwent, ()) {
- // endpwent_impl closes the password file. If an error occurs,
- // it returns an Error with an errno value which is set here.
- auto res = endpwent_impl();
+ auto res = passwd::close();
if (!res.has_value())
libc_errno = res.error();
}
diff --git a/libc/src/pwd/getpwent.cpp b/libc/src/pwd/getpwent.cpp
index 6a69f92b71694..ab0f8d05f2794 100644
--- a/libc/src/pwd/getpwent.cpp
+++ b/libc/src/pwd/getpwent.cpp
@@ -12,159 +12,19 @@
//===----------------------------------------------------------------------===//
#include "src/pwd/getpwent.h"
-#include "src/__support/CPP/span.h"
-#include "src/__support/File/file.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
-#include "src/__support/macros/config.h"
#include "src/pwd/pwd_utils.h"
-#include "hdr/stdio_macros.h"
-
-#ifndef LIBC_COPT_PWD_FILE_PATH
-#define LIBC_COPT_PWD_FILE_PATH "/etc/passwd"
-#endif
-
namespace LIBC_NAMESPACE_DECL {
-static File *pwd_file = nullptr;
-static const char *pwd_file_path = LIBC_COPT_PWD_FILE_PATH;
-// Note: These static buffers are process-global and NOT protected by a mutex
-// at this stage. POSIX getpwent is non-reentrant.
-static char line_buffer[1024];
-static struct passwd pwd_entry;
-
-namespace internal {
-void set_passwd_path(const char *path) {
- if (!path)
- return;
- if (pwd_file) {
- pwd_file->close();
- pwd_file = nullptr;
- }
- pwd_file_path = path;
-}
-} // namespace internal
-
-ErrorOr<int> setpwent_impl() {
- if (!pwd_file) {
- auto result = openfile(pwd_file_path, "r");
- if (!result.has_value())
- return Error(result.error());
- pwd_file = result.value();
- } else {
- auto result = pwd_file->seek(0, SEEK_SET);
- if (!result.has_value())
- return Error(result.error());
- }
- return 0;
-}
-
-ErrorOr<int> endpwent_impl() {
- if (pwd_file) {
- int result = pwd_file->close();
- pwd_file = nullptr;
- if (result != 0)
- return Error(result);
- }
- return 0;
-}
-
-struct ReadLineResult {
- size_t bytes_read;
- bool truncated;
-};
-
-// Reads a line from the given file into buf.
-static ErrorOr<ReadLineResult> read_line(File *f, cpp::span<char> buf) {
- if (!f || buf.empty())
- return Error(EINVAL);
-
- f->lock();
- size_t bytes_read = 0;
- FileIOResult result(0);
- bool truncated = false;
-
- for (char &ch : buf.first(buf.size() - 1)) {
- result = f->read_unlocked(&ch, 1);
- if (result.has_error()) {
- f->unlock();
- return Error(result.error);
- }
- if (result.value != 1)
- break;
- ++bytes_read;
- if (ch == '\n')
- break;
- }
-
- if (result.value == 1 && bytes_read > 0 && buf[bytes_read - 1] != '\n') {
- truncated = true;
- char c = '\0';
- while (true) {
- result = f->read_unlocked(&c, 1);
- if (result.has_error()) {
- f->unlock();
- return Error(result.error);
- }
- if (result.value != 1 || c == '\n')
- break;
- }
- }
-
- bool has_error = f->error_unlocked();
- bool has_eof = f->iseof_unlocked();
- f->unlock();
-
- if (has_error)
- return Error(EIO);
-
- if (bytes_read == 0 && has_eof)
- return ReadLineResult{0, false};
-
- buf[bytes_read] = '\0';
- return ReadLineResult{bytes_read, truncated};
-}
-
LLVM_LIBC_FUNCTION(struct passwd *, getpwent, ()) {
- if (!pwd_file) {
- auto result = openfile(pwd_file_path, "r");
- if (!result.has_value()) {
- libc_errno = result.error();
- return nullptr;
- }
- pwd_file = result.value();
- }
-
- while (true) {
- auto result = read_line(pwd_file, line_buffer);
- if (!result.has_value()) {
- libc_errno = result.error();
- return nullptr;
- }
-
- ReadLineResult res = result.value();
- if (res.bytes_read == 0)
- return nullptr;
-
- if (res.truncated) {
- libc_errno = EINVAL;
- return nullptr;
- }
-
- size_t len = res.bytes_read;
- if (len > 0 && line_buffer[len - 1] == '\n')
- line_buffer[len - 1] = '\0';
-
- auto passwd_or = internal::parse_passwd_line(line_buffer);
- if (!passwd_or.has_value()) {
- libc_errno = passwd_or.error();
- return nullptr;
- }
-
- pwd_entry = passwd_or.value();
- return &pwd_entry;
+ auto res = passwd::read_next();
+ if (!res.has_value()) {
+ libc_errno = res.error();
+ return nullptr;
}
+ return res.value();
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/getpwent.h b/libc/src/pwd/getpwent.h
index d116ee0376433..dcafd7bdba32e 100644
--- a/libc/src/pwd/getpwent.h
+++ b/libc/src/pwd/getpwent.h
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// Header file for getpwent function and internal helpers.
+/// Header file for getpwent function.
///
//===----------------------------------------------------------------------===//
@@ -15,22 +15,9 @@
#define LLVM_LIBC_SRC_PWD_GETPWENT_H
#include "hdr/types/struct_passwd.h"
-#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
-namespace internal {
-
-// Overrides the default password file path for testing purposes.
-void set_passwd_path(const char *path);
-
-} // namespace internal
-
-// Internal helper function to open or rewind the password file.
-ErrorOr<int> setpwent_impl();
-
-// Internal helper function to close the password file.
-ErrorOr<int> endpwent_impl();
// Reads the next entry from the password database.
struct passwd *getpwent();
diff --git a/libc/src/pwd/pwd_utils.cpp b/libc/src/pwd/pwd_utils.cpp
index f56e6118328e8..aaf0faf37e4ea 100644
--- a/libc/src/pwd/pwd_utils.cpp
+++ b/libc/src/pwd/pwd_utils.cpp
@@ -13,11 +13,18 @@
#include "src/pwd/pwd_utils.h"
#include "hdr/errno_macros.h"
+#include "hdr/stdio_macros.h"
#include "hdr/types/struct_passwd.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/File/file.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/str_to_integer.h"
#include "src/string/string_utils.h"
+#ifndef LIBC_COPT_PWD_FILE_PATH
+#define LIBC_COPT_PWD_FILE_PATH "/etc/passwd"
+#endif
+
namespace LIBC_NAMESPACE_DECL {
namespace internal {
@@ -70,4 +77,133 @@ ErrorOr<struct passwd> parse_passwd_line(char *line) {
}
} // namespace internal
+
+namespace passwd {
+
+static File *pwd_file = nullptr;
+static const char *pwd_file_path = LIBC_COPT_PWD_FILE_PATH;
+// Note: These static buffers are process-global and NOT protected by a mutex
+// at this stage. POSIX getpwent is non-reentrant.
+static char line_buffer[1024];
+static struct passwd pwd_entry;
+
+void TESTONLY_set_passwd_path(const char *path) {
+ if (!path)
+ return;
+ if (pwd_file) {
+ pwd_file->close();
+ pwd_file = nullptr;
+ }
+ pwd_file_path = path;
+}
+
+ErrorOr<int> open() {
+ if (!pwd_file) {
+ auto result = openfile(pwd_file_path, "r");
+ if (!result.has_value())
+ return Error(result.error());
+ pwd_file = result.value();
+ } else {
+ auto result = pwd_file->seek(0, SEEK_SET);
+ if (!result.has_value())
+ return Error(result.error());
+ }
+ return 0;
+}
+
+ErrorOr<int> close() {
+ if (pwd_file) {
+ int result = pwd_file->close();
+ pwd_file = nullptr;
+ if (result != 0)
+ return Error(result);
+ }
+ return 0;
+}
+
+struct ReadLineResult {
+ size_t bytes_read;
+ bool truncated;
+};
+
+// Reads a line from the given file into buf.
+static ErrorOr<ReadLineResult> read_line(File *f, cpp::span<char> buf) {
+ if (!f || buf.empty())
+ return Error(EINVAL);
+
+ f->lock();
+ size_t bytes_read = 0;
+ FileIOResult result(0);
+ bool truncated = false;
+
+ for (char &ch : buf.first(buf.size() - 1)) {
+ result = f->read_unlocked(&ch, 1);
+ if (result.has_error()) {
+ f->unlock();
+ return Error(result.error);
+ }
+ if (result.value != 1)
+ break;
+ ++bytes_read;
+ if (ch == '\n')
+ break;
+ }
+
+ if (result.value == 1 && bytes_read > 0 && buf[bytes_read - 1] != '\n') {
+ truncated = true;
+ char c = '\0';
+ while (true) {
+ result = f->read_unlocked(&c, 1);
+ if (result.has_error()) {
+ f->unlock();
+ return Error(result.error);
+ }
+ if (result.value != 1 || c == '\n')
+ break;
+ }
+ }
+
+ bool has_error = f->error_unlocked();
+ f->unlock();
+
+ if (has_error)
+ return Error(EIO);
+
+ buf[bytes_read] = '\0';
+ return ReadLineResult{bytes_read, truncated};
+}
+
+ErrorOr<struct passwd *> read_next() {
+ if (!pwd_file) {
+ auto result = open();
+ if (!result.has_value())
+ return Error(result.error());
+ }
+
+ while (true) {
+ auto result = read_line(pwd_file, line_buffer);
+ if (!result.has_value())
+ return Error(result.error());
+
+ ReadLineResult res = result.value();
+ if (res.bytes_read == 0)
+ return nullptr;
+
+ if (res.truncated)
+ return Error(EINVAL);
+
+ size_t len = res.bytes_read;
+ if (len > 0 && line_buffer[len - 1] == '\n')
+ line_buffer[len - 1] = '\0';
+
+ auto passwd_or = internal::parse_passwd_line(line_buffer);
+ if (!passwd_or.has_value())
+ return Error(passwd_or.error());
+
+ pwd_entry = passwd_or.value();
+ return &pwd_entry;
+ }
+}
+
+} // namespace passwd
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/pwd_utils.h b/libc/src/pwd/pwd_utils.h
index fe3b48179c54e..7b48b2cabc8f5 100644
--- a/libc/src/pwd/pwd_utils.h
+++ b/libc/src/pwd/pwd_utils.h
@@ -25,6 +25,22 @@ namespace internal {
ErrorOr<struct passwd> parse_passwd_line(char *line);
} // namespace internal
+
+namespace passwd {
+
+// Overrides the default password file path for testing purposes.
+void TESTONLY_set_passwd_path(const char *path);
+
+// Opens or rewinds the password file.
+ErrorOr<int> open();
+
+// Closes the password file.
+ErrorOr<int> close();
+
+// Reads the next entry from the password database.
+ErrorOr<struct passwd *> read_next();
+
+} // namespace passwd
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_PWD_PWD_UTILS_H
diff --git a/libc/src/pwd/setpwent.cpp b/libc/src/pwd/setpwent.cpp
index c5817482591ef..effedd493caf7 100644
--- a/libc/src/pwd/setpwent.cpp
+++ b/libc/src/pwd/setpwent.cpp
@@ -14,14 +14,12 @@
#include "src/pwd/setpwent.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
-#include "src/pwd/getpwent.h"
+#include "src/pwd/pwd_utils.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(void, setpwent, ()) {
- // setpwent_impl opens or rewinds the password file. If an error occurs,
- // it returns an Error with an errno value which is set here.
- auto res = setpwent_impl();
+ auto res = passwd::open();
if (!res.has_value())
libc_errno = res.error();
}
diff --git a/libc/test/src/pwd/CMakeLists.txt b/libc/test/src/pwd/CMakeLists.txt
index 254d740bc05ee..06b7d59febe11 100644
--- a/libc/test/src/pwd/CMakeLists.txt
+++ b/libc/test/src/pwd/CMakeLists.txt
@@ -1,5 +1,9 @@
add_custom_target(libc_pwd_unittests)
+if(NOT TARGET libc.src.pwd.pwd_utils)
+ return()
+endif()
+
add_libc_unittest(
pwd_utils_test
SUITE
@@ -28,4 +32,5 @@ add_libc_unittest(
libc.src.pwd.pwd_utils
libc.src.pwd.setpwent
libc.src.stdio.remove
+ libc.src.string.string_utils
)
diff --git a/libc/test/src/pwd/getpwent_test.cpp b/libc/test/src/pwd/getpwent_test.cpp
index 67c7bb19508a1..5fca34d9b3b2b 100644
--- a/libc/test/src/pwd/getpwent_test.cpp
+++ b/libc/test/src/pwd/getpwent_test.cpp
@@ -19,8 +19,13 @@
#include "src/pwd/pwd_utils.h"
#include "src/pwd/setpwent.h"
#include "src/stdio/remove.h"
+#include "src/string/string_utils.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/Test.h"
+using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
+
namespace {
// RAII helper class for creating and automatically removing temporary test
@@ -30,17 +35,12 @@ class HermeticFile {
public:
HermeticFile(const char *file_path, const char *content) {
- size_t i = 0;
- for (; file_path[i] && i < sizeof(path) - 1; ++i)
- path[i] = file_path[i];
- path[i] = '\0';
+ LIBC_NAMESPACE::internal::strlcpy(path, file_path, sizeof(path));
auto file_or = LIBC_NAMESPACE::openfile(path, "w");
if (file_or.has_value()) {
auto *f = file_or.value();
- size_t len = 0;
- for (const char *p = content; *p; ++p)
- ++len;
+ size_t len = LIBC_NAMESPACE::internal::string_length(content);
f->write(content, len);
f->close();
}
@@ -51,15 +51,17 @@ class HermeticFile {
const char *get_path() const { return path; }
};
+class LlvmLibcPwdTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {};
+
} // namespace
-TEST(LlvmLibcPwdTest, GetPwentTestSuccess) {
+TEST_F(LlvmLibcPwdTest, GetPwentTestSuccess) {
const char *content = "root:x:0:0:root:/root:/bin/bash\n"
"bin:x:1:1:bin:/bin:/sbin/nologin\n";
HermeticFile test_file(libc_make_test_file_path("getpwent_success.test"),
content);
- LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::passwd::TESTONLY_set_passwd_path(test_file.get_path());
LIBC_NAMESPACE::setpwent();
struct passwd *pwd1 = LIBC_NAMESPACE::getpwent();
@@ -78,29 +80,28 @@ TEST(LlvmLibcPwdTest, GetPwentTestSuccess) {
LIBC_NAMESPACE::endpwent();
}
-TEST(LlvmLibcPwdTest, GetPwentTestFailure) {
+TEST_F(LlvmLibcPwdTest, GetPwentTestFailure) {
const char *content = "invalid_line_without_enough_fields\n";
HermeticFile test_file(libc_make_test_file_path("getpwent_fail.test"),
content);
- LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::passwd::TESTONLY_set_passwd_path(test_file.get_path());
LIBC_NAMESPACE::setpwent();
- libc_errno = 0;
struct passwd *pwd = LIBC_NAMESPACE::getpwent();
ASSERT_TRUE(pwd == nullptr);
- ASSERT_EQ(static_cast<int>(libc_errno), EINVAL);
+ ASSERT_ERRNO_EQ(EINVAL);
LIBC_NAMESPACE::endpwent();
}
-TEST(LlvmLibcPwdTest, SetPwentTestHermetic) {
+TEST_F(LlvmLibcPwdTest, SetPwentTestHermetic) {
const char *content = "user1:x:1000:1000:User One:/home/user1:/bin/bash\n"
"user2:x:1001:1001:User Two:/home/user2:/bin/bash\n";
HermeticFile test_file(libc_make_test_file_path("setpwent_hermetic.test"),
content);
- LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::passwd::TESTONLY_set_passwd_path(test_file.get_path());
struct passwd *pwd = LIBC_NAMESPACE::getpwent();
ASSERT_TRUE(pwd != nullptr);
@@ -120,12 +121,12 @@ TEST(LlvmLibcPwdTest, SetPwentTestHermetic) {
LIBC_NAMESPACE::endpwent();
}
-TEST(LlvmLibcPwdTest, ReopenAfterEndpwent) {
+TEST_F(LlvmLibcPwdTest, ReopenAfterEndpwent) {
const char *content = "root:x:0:0:root:/root:/bin/bash\n";
HermeticFile test_file(libc_make_test_file_path("reopen_endpwent.test"),
content);
- LIBC_NAMESPACE::internal::set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::passwd::TESTONLY_set_passwd_path(test_file.get_path());
struct passwd *pwd = LIBC_NAMESPACE::getpwent();
ASSERT_TRUE(pwd != nullptr);
@@ -140,13 +141,12 @@ TEST(LlvmLibcPwdTest, ReopenAfterEndpwent) {
LIBC_NAMESPACE::endpwent();
}
-TEST(LlvmLibcPwdTest, FileOpenFailure) {
- LIBC_NAMESPACE::internal::set_passwd_path(
+TEST_F(LlvmLibcPwdTest, FileOpenFailure) {
+ LIBC_NAMESPACE::passwd::TESTONLY_set_passwd_path(
"/nonexistent_directory/nonexistent_file");
LIBC_NAMESPACE::endpwent(); // Force close any existing file
- libc_errno = 0;
struct passwd *pwd = LIBC_NAMESPACE::getpwent();
ASSERT_TRUE(pwd == nullptr);
- ASSERT_EQ(static_cast<int>(libc_errno), ENOENT);
+ ASSERT_ERRNO_EQ(ENOENT);
}
More information about the libc-commits
mailing list