[libc-commits] [libc] [libc] Add getpwent, setpwent, and endpwent functions (PR #206064)
Jeff Bailey via libc-commits
libc-commits at lists.llvm.org
Fri Jun 26 06:52:07 PDT 2026
https://github.com/kaladron created https://github.com/llvm/llvm-project/pull/206064
Implemented `getpwent`, `setpwent`, and `endpwent` functions for accessing the password database.
* Added `struct passwd` definition in `llvm-libc-types`.
* Added `pwd.yaml` interface definition with POSIX standards.
* Implemented `getpwent`, `setpwent`, and `endpwent` entrypoints.
* Extracted in-place passwd line parsing into an internal helper `parse_passwd_line` in `pwd_utils`.
* Used `strtointeger` for robust parsing of UID and GID fields.
* Added `struct_passwd` proxy header to avoid direct system includes.
* Improved `getpwent` robustness by looping to skip malformed lines.
* Centrally declared internal implementation helpers in `pwd_utils.h`.
* Added unit tests for `getpwent` and `setpwent` / `endpwent` behaviour.
Assisted-by: Automated tooling, human reviewed.
>From 0780e8a65bbe9f7cc3f1f061f4419e4a6ca31c6b Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Fri, 26 Jun 2026 12:42:06 +0100
Subject: [PATCH] [libc] Add getpwent, setpwent, and endpwent functions
Implemented `getpwent`, `setpwent`, and `endpwent` functions for
accessing the password database.
* Added `struct passwd` definition in `llvm-libc-types`.
* Added `pwd.yaml` interface definition with POSIX standards.
* Implemented `getpwent`, `setpwent`, and `endpwent` entrypoints.
* Extracted in-place passwd line parsing into an internal helper
`parse_passwd_line` in `pwd_utils`.
* Used `strtointeger` for robust parsing of UID and GID fields.
* Added `struct_passwd` proxy header to avoid direct system includes.
* Improved `getpwent` robustness by looping to skip malformed lines.
* Centrally declared internal implementation helpers in `pwd_utils.h`.
* Added unit tests for `getpwent` and `setpwent` / `endpwent` behaviour.
Assisted-by: Automated tooling, human reviewed.
---
libc/config/linux/aarch64/entrypoints.txt | 5 ++
libc/config/linux/arm/entrypoints.txt | 5 ++
libc/config/linux/riscv/entrypoints.txt | 5 ++
libc/config/linux/x86_64/entrypoints.txt | 6 ++
libc/hdr/types/CMakeLists.txt | 9 +++
libc/hdr/types/struct_passwd.h | 27 ++++++++
libc/include/CMakeLists.txt | 12 ++++
libc/include/llvm-libc-types/CMakeLists.txt | 5 ++
libc/include/llvm-libc-types/struct_passwd.h | 30 +++++++++
libc/include/pwd.yaml | 27 ++++++++
libc/src/CMakeLists.txt | 1 +
libc/src/pwd/CMakeLists.txt | 62 ++++++++++++++++++
libc/src/pwd/endpwent.cpp | 25 +++++++
libc/src/pwd/endpwent.h | 25 +++++++
libc/src/pwd/getpwent.cpp | 65 +++++++++++++++++++
libc/src/pwd/getpwent.h | 26 ++++++++
libc/src/pwd/pwd_utils.cpp | 68 ++++++++++++++++++++
libc/src/pwd/pwd_utils.h | 32 +++++++++
libc/src/pwd/setpwent.cpp | 25 +++++++
libc/src/pwd/setpwent.h | 25 +++++++
libc/test/src/CMakeLists.txt | 1 +
libc/test/src/pwd/CMakeLists.txt | 22 +++++++
libc/test/src/pwd/getpwent_test.cpp | 66 +++++++++++++++++++
23 files changed, 574 insertions(+)
create mode 100644 libc/hdr/types/struct_passwd.h
create mode 100644 libc/include/llvm-libc-types/struct_passwd.h
create mode 100644 libc/include/pwd.yaml
create mode 100644 libc/src/pwd/CMakeLists.txt
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/pwd_utils.cpp
create mode 100644 libc/src/pwd/pwd_utils.h
create mode 100644 libc/src/pwd/setpwent.cpp
create mode 100644 libc/src/pwd/setpwent.h
create mode 100644 libc/test/src/pwd/CMakeLists.txt
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 970c825bbfc96..91d69e4c522aa 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -35,6 +35,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 f04ac40145d3a..d88070fcc1ee7 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -23,6 +23,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/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 7baf4de9d8a5b..44db1e375d536 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -35,6 +35,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/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 9399b284fa2da..b13ebcf5c8fe5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -36,6 +36,12 @@ 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/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 433c47b174766..6eab9fae93df2 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -487,3 +487,12 @@ add_proxy_header_library(
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.gid_t
)
+
+add_proxy_header_library(
+ struct_passwd
+ HDRS
+ struct_passwd.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.struct_passwd
+)
+
diff --git a/libc/hdr/types/struct_passwd.h b/libc/hdr/types/struct_passwd.h
new file mode 100644
index 0000000000000..e55667e7172d2
--- /dev/null
+++ b/libc/hdr/types/struct_passwd.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
+/// Proxy for struct passwd.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_PASSWD_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_PASSWD_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_passwd.h"
+
+#else
+
+#include <pwd.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_PASSWD_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 96c3a88f3fcc8..c4c2d99a35fb1 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -793,6 +793,18 @@ add_header_macro(
.llvm-libc-types.nl_catd
)
+add_header_macro(
+ pwd
+ ../libc/include/pwd.yaml
+ pwd.h
+ DEPENDS
+ .llvm_libc_common_h
+ .llvm-libc-types.struct_passwd
+ .llvm-libc-types.uid_t
+ .llvm-libc-types.gid_t
+ .llvm-libc-types.size_t
+)
+
# UEFI spec references "Uefi.h" so we use that name for compatibility
add_header_macro(
uefi
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index fcd0e1245a4a8..2e44fdaf16ff0 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -101,6 +101,11 @@ add_header(
.dev_t .ino_t .mode_t .nlink_t .uid_t .gid_t .off_t .struct_timespec
.blksize_t .blkcnt_t
)
+add_header(
+ struct_passwd
+ HDR struct_passwd.h
+ DEPENDS .gid_t .uid_t
+)
add_header(struct_tm HDR struct_tm.h)
add_header(struct_utsname HDR struct_utsname.h)
add_header(thrd_start_t HDR thrd_start_t.h)
diff --git a/libc/include/llvm-libc-types/struct_passwd.h b/libc/include/llvm-libc-types/struct_passwd.h
new file mode 100644
index 0000000000000..7b41be6edbbe0
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_passwd.h
@@ -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
+/// Definition of struct passwd.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef __LLVM_LIBC_TYPES_STRUCT_PASSWD_H__
+#define __LLVM_LIBC_TYPES_STRUCT_PASSWD_H__
+
+#include "gid_t.h"
+#include "uid_t.h"
+
+struct passwd {
+ char *pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+};
+
+#endif // __LLVM_LIBC_TYPES_STRUCT_PASSWD_H__
diff --git a/libc/include/pwd.yaml b/libc/include/pwd.yaml
new file mode 100644
index 0000000000000..f8a9500937ed1
--- /dev/null
+++ b/libc/include/pwd.yaml
@@ -0,0 +1,27 @@
+header: pwd.h
+standards:
+ - posix
+macros: []
+types:
+ - type_name: struct_passwd
+ - type_name: uid_t
+ - type_name: gid_t
+ - type_name: size_t
+enums: []
+objects: []
+functions:
+ - name: getpwent
+ standards:
+ - posix
+ return_type: struct passwd *
+ arguments: []
+ - name: setpwent
+ standards:
+ - posix
+ return_type: void
+ arguments: []
+ - name: endpwent
+ standards:
+ - posix
+ return_type: void
+ arguments: []
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index b2afe0a33acee..1081abfd370dc 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -23,6 +23,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
add_subdirectory(dirent)
add_subdirectory(fcntl)
add_subdirectory(poll)
+ add_subdirectory(pwd)
add_subdirectory(pthread)
add_subdirectory(sched)
add_subdirectory(sys)
diff --git a/libc/src/pwd/CMakeLists.txt b/libc/src/pwd/CMakeLists.txt
new file mode 100644
index 0000000000000..b808f59492e11
--- /dev/null
+++ b/libc/src/pwd/CMakeLists.txt
@@ -0,0 +1,62 @@
+#===-- CMakeLists.txt ----------------------------------------------------===#
+#
+# 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
+#
+#===----------------------------------------------------------------------===#
+
+add_object_library(
+ pwd_utils
+ SRCS
+ pwd_utils.cpp
+ HDRS
+ pwd_utils.h
+ DEPENDS
+ libc.hdr.types.struct_passwd
+ libc.src.__support.str_to_integer
+ libc.src.string.string_utils
+)
+
+add_entrypoint_object(
+ getpwent
+ SRCS
+ getpwent.cpp
+ HDRS
+ getpwent.h
+ DEPENDS
+ libc.include.pwd
+ libc.hdr.types.struct_passwd
+ libc.src.errno.errno
+ libc.src.stdio.fopen
+ libc.src.stdio.fclose
+ libc.src.stdio.fgets
+ libc.src.stdio.fseek
+ libc.src.string.string_utils
+ libc.hdr.stdio_macros
+ .pwd_utils
+)
+
+add_entrypoint_object(
+ setpwent
+ SRCS
+ setpwent.cpp
+ HDRS
+ setpwent.h
+ DEPENDS
+ libc.include.pwd
+ .getpwent
+ .pwd_utils
+)
+
+add_entrypoint_object(
+ endpwent
+ SRCS
+ endpwent.cpp
+ HDRS
+ endpwent.h
+ DEPENDS
+ libc.include.pwd
+ .getpwent
+ .pwd_utils
+)
diff --git a/libc/src/pwd/endpwent.cpp b/libc/src/pwd/endpwent.cpp
new file mode 100644
index 0000000000000..e15757275e3c2
--- /dev/null
+++ b/libc/src/pwd/endpwent.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/macros/config.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, endpwent, ()) {
+ endpwent_impl();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/endpwent.h b/libc/src/pwd/endpwent.h
new file mode 100644
index 0000000000000..b5a8262cc7d33
--- /dev/null
+++ b/libc/src/pwd/endpwent.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Declarations of endpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_ENDPWENT_H
+#define LLVM_LIBC_SRC_PWD_ENDPWENT_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+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..4c07e0a708849
--- /dev/null
+++ b/libc/src/pwd/getpwent.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/macros/config.h"
+#include "src/__support/libc_errno.h"
+#include "src/stdio/fclose.h"
+#include "src/stdio/fgets.h"
+#include "src/stdio/fopen.h"
+#include "src/string/string_utils.h"
+#include "src/pwd/pwd_utils.h"
+
+#include "src/stdio/fseek.h"
+#include "hdr/stdio_macros.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static FILE *pwd_file = nullptr;
+static char line_buffer[1024];
+static struct passwd pwd_entry;
+
+void setpwent_impl() {
+ if (pwd_file)
+ LIBC_NAMESPACE::fseek(pwd_file, 0, SEEK_SET);
+}
+
+void endpwent_impl() {
+ if (pwd_file) {
+ LIBC_NAMESPACE::fclose(pwd_file);
+ pwd_file = nullptr;
+ }
+}
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwent, ()) {
+ if (!pwd_file) {
+ pwd_file = LIBC_NAMESPACE::fopen("/etc/passwd", "r");
+ if (!pwd_file)
+ return nullptr;
+ }
+
+ while (LIBC_NAMESPACE::fgets(line_buffer, sizeof(line_buffer), pwd_file)) {
+ // Remove newline
+ size_t len = LIBC_NAMESPACE::internal::string_length(line_buffer);
+ if (len > 0 && line_buffer[len - 1] == '\n')
+ line_buffer[len - 1] = '\0';
+
+ if (internal::parse_passwd_line(line_buffer, &pwd_entry))
+ return &pwd_entry;
+ }
+
+ return nullptr;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/getpwent.h b/libc/src/pwd/getpwent.h
new file mode 100644
index 0000000000000..5e8e96b8f6ba1
--- /dev/null
+++ b/libc/src/pwd/getpwent.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
+/// Declarations of getpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#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 {
+
+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
new file mode 100644
index 0000000000000..c8f75844917b6
--- /dev/null
+++ b/libc/src/pwd/pwd_utils.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Helper functions for pwd.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/pwd_utils.h"
+#include "src/__support/str_to_integer.h"
+#include "src/string/string_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+bool parse_passwd_line(char *line, struct passwd *pwd) {
+ if (!line || !pwd)
+ return false;
+
+ char *context = line;
+
+ pwd->pw_name = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!pwd->pw_name)
+ return false;
+
+ pwd->pw_passwd = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!pwd->pw_passwd)
+ return false;
+
+ char *uid_str = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!uid_str)
+ return false;
+ auto uid_res = LIBC_NAMESPACE::internal::strtointeger<uid_t>(uid_str, 10);
+ if (uid_res.has_error())
+ return false;
+ pwd->pw_uid = uid_res;
+
+ char *gid_str = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!gid_str)
+ return false;
+ auto gid_res = LIBC_NAMESPACE::internal::strtointeger<gid_t>(gid_str, 10);
+ if (gid_res.has_error())
+ return false;
+ pwd->pw_gid = gid_res;
+
+ pwd->pw_gecos = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!pwd->pw_gecos)
+ return false;
+
+ pwd->pw_dir = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!pwd->pw_dir)
+ return false;
+
+ // shell
+ pwd->pw_shell = LIBC_NAMESPACE::internal::string_token<false>(nullptr, ":", &context);
+ if (!pwd->pw_shell)
+ return false;
+
+ return true;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/pwd_utils.h b/libc/src/pwd/pwd_utils.h
new file mode 100644
index 0000000000000..2ff5b3211dbb6
--- /dev/null
+++ b/libc/src/pwd/pwd_utils.h
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Declarations of helper functions for pwd.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_PWD_UTILS_H
+#define LLVM_LIBC_SRC_PWD_PWD_UTILS_H
+
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+bool parse_passwd_line(char *line, struct passwd *pwd);
+
+} // namespace internal
+
+void setpwent_impl();
+void endpwent_impl();
+
+} // 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..c6dccee3c2e1b
--- /dev/null
+++ b/libc/src/pwd/setpwent.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/macros/config.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, setpwent, ()) {
+ setpwent_impl();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pwd/setpwent.h b/libc/src/pwd/setpwent.h
new file mode 100644
index 0000000000000..91cb263b41d90
--- /dev/null
+++ b/libc/src/pwd/setpwent.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Declarations of setpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_SETPWENT_H
+#define LLVM_LIBC_SRC_PWD_SETPWENT_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void setpwent();
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_SETPWENT_H
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 0c6ec9f07a9b7..38b0cebb7776e 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -82,6 +82,7 @@ add_subdirectory(inttypes)
if(${LIBC_TARGET_OS} STREQUAL "linux")
add_subdirectory(fcntl)
add_subdirectory(poll)
+ add_subdirectory(pwd)
add_subdirectory(sched)
add_subdirectory(sys)
add_subdirectory(termios)
diff --git a/libc/test/src/pwd/CMakeLists.txt b/libc/test/src/pwd/CMakeLists.txt
new file mode 100644
index 0000000000000..b5bf000443b38
--- /dev/null
+++ b/libc/test/src/pwd/CMakeLists.txt
@@ -0,0 +1,22 @@
+#===-- CMakeLists.txt ----------------------------------------------------===#
+#
+# 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
+#
+#===----------------------------------------------------------------------===#
+
+add_custom_target(libc_pwd_unittests)
+
+add_libc_unittest(
+ getpwent_test
+ SUITE
+ libc_pwd_unittests
+ SRCS
+ getpwent_test.cpp
+ DEPENDS
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+ libc.src.pwd.endpwent
+ libc.src.string.strcmp
+)
diff --git a/libc/test/src/pwd/getpwent_test.cpp b/libc/test/src/pwd/getpwent_test.cpp
new file mode 100644
index 0000000000000..cdbdf3c09ec8d
--- /dev/null
+++ b/libc/test/src/pwd/getpwent_test.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Unittests for getpwent.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/getpwent.h"
+#include "src/pwd/setpwent.h"
+#include "src/pwd/endpwent.h"
+#include "src/string/strcmp.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcPwdTest, GetPwentTest) {
+ // We assume /etc/passwd exists and contains at least "root" and "daemon".
+ // We also assume it does NOT contain "baduser".
+
+ bool found_root = false;
+ bool found_daemon = false;
+ bool found_baduser = false;
+
+ LIBC_NAMESPACE::setpwent();
+
+ struct passwd *pw;
+ while ((pw = LIBC_NAMESPACE::getpwent()) != nullptr) {
+ if (LIBC_NAMESPACE::strcmp(pw->pw_name, "root") == 0) {
+ found_root = true;
+ ASSERT_EQ(pw->pw_uid, static_cast<uid_t>(0));
+ }
+ if (LIBC_NAMESPACE::strcmp(pw->pw_name, "daemon") == 0) {
+ found_daemon = true;
+ }
+ if (LIBC_NAMESPACE::strcmp(pw->pw_name, "baduser") == 0) {
+ found_baduser = true;
+ }
+ }
+
+ ASSERT_TRUE(found_root);
+ ASSERT_TRUE(found_daemon);
+ ASSERT_FALSE(found_baduser);
+
+ LIBC_NAMESPACE::endpwent();
+}
+
+TEST(LlvmLibcPwdTest, SetPwentTest) {
+ // Read first entry
+ LIBC_NAMESPACE::setpwent();
+ struct passwd *pw1 = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pw1 != nullptr);
+
+ // Rewind
+ LIBC_NAMESPACE::setpwent();
+ struct passwd *pw2 = LIBC_NAMESPACE::getpwent();
+ ASSERT_TRUE(pw2 != nullptr);
+
+ // Should be the same entry
+ ASSERT_STREQ(pw1->pw_name, pw2->pw_name);
+
+ LIBC_NAMESPACE::endpwent();
+}
More information about the libc-commits
mailing list