[libc-commits] [libc] 096481d - [libc] Add getpwent, setpwent, and endpwent entrypoints (#213076)
via libc-commits
libc-commits at lists.llvm.org
Fri Aug 7 02:09:21 PDT 2026
Author: Jeff Bailey
Date: 2026-08-07T10:09:15+01:00
New Revision: 096481ddc5aa696f26ae4fd704adb28ce31babc6
URL: https://github.com/llvm/llvm-project/commit/096481ddc5aa696f26ae4fd704adb28ce31babc6
DIFF: https://github.com/llvm/llvm-project/commit/096481ddc5aa696f26ae4fd704adb28ce31babc6.diff
LOG: [libc] Add getpwent, setpwent, and endpwent entrypoints (#213076)
Added getpwent, setpwent, and endpwent functions using the internal
pwd_utils line parser.
* Implemented getpwent.cpp, setpwent.cpp, and endpwent.cpp entrypoints
* Added database iteration state and helpers (open, close, read_next)
under namespace passwd in pwd_utils
* Registered entrypoints in config/linux/*/entrypoints.txt
* Added CMake target guards for File and platform_file to support
overlay builds and cross-platform targets
* Added unit tests in libc/test/src/pwd/getpwent_test.cpp
Assisted-by: Automated tooling, human reviewed.
Added:
libc/src/pwd/endpwent.cpp
libc/src/pwd/endpwent.h
libc/src/pwd/getpwent.cpp
libc/src/pwd/getpwent.h
libc/src/pwd/setpwent.cpp
libc/src/pwd/setpwent.h
libc/test/src/pwd/getpwent_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/src/CMakeLists.txt
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 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..4cde157adf673 100644
--- a/libc/src/pwd/CMakeLists.txt
+++ b/libc/src/pwd/CMakeLists.txt
@@ -1,3 +1,47 @@
+if(NOT TARGET libc.src.__support.File.file OR NOT TARGET libc.src.__support.File.platform_file)
+ return()
+endif()
+
+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
+ .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
+ .pwd_utils
+)
+
+add_entrypoint_object(
+ endpwent
+ SRCS
+ endpwent.cpp
+ HDRS
+ endpwent.h
+ DEPENDS
+ libc.src.errno.errno
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ .pwd_utils
+)
+
add_object_library(
pwd_utils
HDRS
@@ -6,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
new file mode 100644
index 0000000000000..e5edde36d0d2d
--- /dev/null
+++ b/libc/src/pwd/endpwent.cpp
@@ -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
+/// Implementation of endpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/endpwent.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(void, endpwent, ()) {
+ auto res = passwd::close();
+ 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..ab0f8d05f2794
--- /dev/null
+++ b/libc/src/pwd/getpwent.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwent, ()) {
+ 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
new file mode 100644
index 0000000000000..dcafd7bdba32e
--- /dev/null
+++ b/libc/src/pwd/getpwent.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 getpwent function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_GETPWENT_H
+#define LLVM_LIBC_SRC_PWD_GETPWENT_H
+
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// 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/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
new file mode 100644
index 0000000000000..effedd493caf7
--- /dev/null
+++ b/libc/src/pwd/setpwent.cpp
@@ -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
+/// Implementation of setpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/setpwent.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(void, setpwent, ()) {
+ auto res = passwd::open();
+ 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..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
@@ -11,3 +15,22 @@ 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
+ libc.src.string.string_utils
+)
diff --git a/libc/test/src/pwd/getpwent_test.cpp b/libc/test/src/pwd/getpwent_test.cpp
new file mode 100644
index 0000000000000..5fca34d9b3b2b
--- /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 "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
+// files.
+class HermeticFile {
+ char path[256];
+
+public:
+ HermeticFile(const char *file_path, const char *content) {
+ 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 = LIBC_NAMESPACE::internal::string_length(content);
+ f->write(content, len);
+ f->close();
+ }
+ }
+
+ ~HermeticFile() { LIBC_NAMESPACE::remove(path); }
+
+ const char *get_path() const { return path; }
+};
+
+class LlvmLibcPwdTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {};
+
+} // namespace
+
+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::passwd::TESTONLY_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_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::passwd::TESTONLY_set_passwd_path(test_file.get_path());
+ LIBC_NAMESPACE::setpwent();
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd == nullptr);
+ ASSERT_ERRNO_EQ(EINVAL);
+
+ LIBC_NAMESPACE::endpwent();
+}
+
+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::passwd::TESTONLY_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_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::passwd::TESTONLY_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_F(LlvmLibcPwdTest, FileOpenFailure) {
+ LIBC_NAMESPACE::passwd::TESTONLY_set_passwd_path(
+ "/nonexistent_directory/nonexistent_file");
+ LIBC_NAMESPACE::endpwent(); // Force close any existing file
+
+ struct passwd *pwd = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pwd == nullptr);
+ ASSERT_ERRNO_EQ(ENOENT);
+}
More information about the libc-commits
mailing list