[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