[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 07:46:58 PDT 2026
https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/206064
>From 618f6ff3d99863f02f7fee681f45903e36d2f924 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 (full build only).
* Implemented `getpwent` to robustly skip malformed lines by looping.
* Implemented passwd line parsing in 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.
* Centrally declared internal implementation helpers in `pwd_utils.h`.
* Added unit tests for `getpwent` and `setpwent` / `endpwent` behaviour.
* Fixed missing dependency for `elf_proxy` in CMake.
Assisted-by: Automated tooling, human reviewed.
---
libc/config/linux/aarch64/entrypoints.txt | 6 ++
libc/config/linux/arm/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 6 ++
libc/config/linux/x86_64/entrypoints.txt | 6 ++
libc/hdr/CMakeLists.txt | 1 +
libc/hdr/types/CMakeLists.txt | 8 +++
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 | 23 ++++++
libc/src/pwd/endpwent.h | 25 +++++++
libc/src/pwd/getpwent.cpp | 65 +++++++++++++++++
libc/src/pwd/getpwent.h | 26 +++++++
libc/src/pwd/pwd_utils.cpp | 75 ++++++++++++++++++++
libc/src/pwd/pwd_utils.h | 32 +++++++++
libc/src/pwd/setpwent.cpp | 23 ++++++
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 +++++++++++++++++
24 files changed, 575 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 570f7666ba67b..665c71340a36b 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -35,6 +35,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+
# sched.h entrypoints
libc.src.sched.sched_get_priority_max
libc.src.sched.sched_get_priority_min
@@ -1107,6 +1108,11 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_setname_np
libc.src.pthread.pthread_setspecific
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# sched.h entrypoints
libc.src.sched.__sched_clrcpuset
libc.src.sched.__sched_cpualloc
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index e6aa6091ed550..46576b122f139 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -23,6 +23,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+
# 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 2508de5cfe5a4..22704d517fc6d 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -35,6 +35,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+
# sched.h entrypoints
libc.src.sched.sched_get_priority_max
libc.src.sched.sched_get_priority_min
@@ -1240,6 +1241,11 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_setname_np
libc.src.pthread.pthread_setspecific
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# sched.h entrypoints
libc.src.sched.__sched_clrcpuset
libc.src.sched.__sched_cpualloc
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 5ace968a739c8..82c828e062de5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -48,6 +48,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# poll.h entrypoints
libc.src.poll.poll
+
# sched.h entrypoints
libc.src.sched.getcpu
libc.src.sched.sched_get_priority_max
@@ -1302,6 +1303,11 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.pthread.pthread_setname_np
libc.src.pthread.pthread_setspecific
+ # pwd.h entrypoints
+ libc.src.pwd.endpwent
+ libc.src.pwd.getpwent
+ libc.src.pwd.setpwent
+
# sched.h entrypoints
libc.src.sched.__sched_clrcpuset
libc.src.sched.__sched_cpualloc
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index c24b826a6ef14..240cfd8f83017 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -345,6 +345,7 @@ add_gen_header(
GEN_HDR
elf_proxy.h
DEPENDS
+ libc.include.llvm-libc-macros.elf_macros
libc.include.llvm_libc_common_h
libc.include.llvm-libc-types.Elf32_Addr
libc.include.llvm-libc-types.Elf32_Chdr
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index a130f7ee0000a..93eb08e1f3620 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -1127,3 +1127,11 @@ add_proxy_header_library(
FULL_BUILD_DEPENDS
libc.include.llvm-libc-types.regmatch_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 bb670b614742a..c740dae56f620 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -1034,6 +1034,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 0512d3f0e642a..eeff097d6ceec 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -178,6 +178,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 62aa164b35ee7..a269ac4a83ffd 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -28,6 +28,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(semaphore)
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..948eac2b72349
--- /dev/null
+++ b/libc/src/pwd/endpwent.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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..83bbe1ade4137
--- /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/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/pwd/pwd_utils.h"
+#include "src/stdio/fclose.h"
+#include "src/stdio/fgets.h"
+#include "src/stdio/fopen.h"
+#include "src/string/string_utils.h"
+
+#include "hdr/stdio_macros.h"
+#include "src/stdio/fseek.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..6a993c1129c5a
--- /dev/null
+++ b/libc/src/pwd/pwd_utils.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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..a4efcdacba2dc
--- /dev/null
+++ b/libc/src/pwd/setpwent.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 45815c9bba8ca..c0617d83c30ab 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -87,6 +87,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..eabc09e502f69
--- /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/endpwent.h"
+#include "src/pwd/getpwent.h"
+#include "src/pwd/setpwent.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