This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit a0777a774b1124b0584970ecd79e6e528a47936e
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Oct 9 08:41:45 2026 +0200

    libs/libc/grp: Add getgrent(), setgrent() and endgrent().
    
    POSIX specifies getgrent(), setgrent() and endgrent() to walk the
    group database.  NuttX had the passwd equivalents (getpwent() and the
    others) but not these.
    
    With CONFIG_LIBC_GROUP_FILE the entries come from the group file,
    found by index with a new grp_findby_index().  Without it the only
    group is root, as for getgrgid().
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 include/grp.h                               |   3 +
 libs/libc/grp/CMakeLists.txt                |  10 ++-
 libs/libc/grp/Make.defs                     |   2 +-
 libs/libc/grp/lib_find_grpfile.c            |  63 +++++++++++++++++
 libs/libc/grp/{lib_grp.h => lib_getgrent.c} | 106 ++++++++++++++++------------
 libs/libc/grp/lib_grp.h                     |   2 +
 6 files changed, 137 insertions(+), 49 deletions(-)

diff --git a/include/grp.h b/include/grp.h
index 1c4f215e54f..7a066539945 100644
--- a/include/grp.h
+++ b/include/grp.h
@@ -63,6 +63,9 @@ extern "C"
 
 FAR struct group *getgrnam(FAR const char *name);
 FAR struct group *getgrgid(gid_t gid);
+FAR struct group *getgrent(void);
+void setgrent(void);
+void endgrent(void);
 int getgrnam_r(FAR const char *name,
                FAR struct group *grp,
                FAR char *buf,
diff --git a/libs/libc/grp/CMakeLists.txt b/libs/libc/grp/CMakeLists.txt
index 62d98a9056a..111d4048e16 100644
--- a/libs/libc/grp/CMakeLists.txt
+++ b/libs/libc/grp/CMakeLists.txt
@@ -19,8 +19,14 @@
 # the License.
 #
 # 
##############################################################################
-set(SRCS lib_getgrgid.c lib_getgrgidr.c lib_getgrnam.c lib_getgrnamr.c
-         lib_initgroups.c lib_getgrouplist.c)
+set(SRCS
+    lib_getgrgid.c
+    lib_getgrgidr.c
+    lib_getgrnam.c
+    lib_getgrnamr.c
+    lib_initgroups.c
+    lib_getgrouplist.c
+    lib_getgrent.c)
 
 if(CONFIG_LIBC_GROUP_FILE)
   list(APPEND SRCS lib_find_grpfile.c lib_grp_globals.c)
diff --git a/libs/libc/grp/Make.defs b/libs/libc/grp/Make.defs
index 2fe4e37fc05..3654a811d0d 100644
--- a/libs/libc/grp/Make.defs
+++ b/libs/libc/grp/Make.defs
@@ -23,7 +23,7 @@
 # Add the grp C files to the build
 
 CSRCS += lib_getgrgid.c lib_getgrgidr.c lib_getgrnam.c lib_getgrnamr.c
-CSRCS += lib_initgroups.c lib_getgrouplist.c
+CSRCS += lib_initgroups.c lib_getgrouplist.c lib_getgrent.c
 
 ifeq ($(CONFIG_LIBC_GROUP_FILE),y)
 CSRCS += lib_find_grpfile.c lib_grp_globals.c
diff --git a/libs/libc/grp/lib_find_grpfile.c b/libs/libc/grp/lib_find_grpfile.c
index a7f63db4c3f..f74842ef501 100644
--- a/libs/libc/grp/lib_find_grpfile.c
+++ b/libs/libc/grp/lib_find_grpfile.c
@@ -56,6 +56,14 @@ struct grp_user_s
   int             count;      /* Number of group IDs found so far */
 };
 
+/* Context used by grp_match_index() to find the record with a given index */
+
+struct grp_index_s
+{
+  int index;                  /* Index of the record to find */
+  int current;                /* Index of the record being visited */
+};
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -110,6 +118,31 @@ static int grp_match_gid(FAR const struct group *entry, 
uintptr_t arg)
   return match_gid == entry->gr_gid ? 1 : 0;
 }
 
+/****************************************************************************
+ * Name: grp_match_index
+ *
+ * Description:
+ *   Called for each record in the group file.  Returns "1" for the record
+ *   with the index in the context (passed as arg).
+ *
+ * Input Parameters:
+ *   entry  - The parsed group file record
+ *   arg    - A pointer to the struct grp_index_s context
+ *
+ * Returned Value:
+ *   = 0 :  This is not the record with the index.
+ *   = 1 :  This is the record with the index.
+ *
+ ****************************************************************************/
+
+static int grp_match_index(FAR const struct group *entry, uintptr_t arg)
+{
+  FAR struct grp_index_s *ctx = (FAR struct grp_index_s *)arg;
+
+  UNUSED(entry);
+  return ctx->current++ == ctx->index ? 1 : 0;
+}
+
 /****************************************************************************
  * Name: grp_match_user
  *
@@ -401,6 +434,36 @@ int grp_findby_gid(gid_t gid, FAR struct group *entry, FAR 
char *buffer,
   return grp_foreach(grp_match_gid, (uintptr_t)gid, entry, buffer, buflen);
 }
 
+/****************************************************************************
+ * Name: grp_findby_index
+ *
+ * Description:
+ *   Find the group file entry with the given index (0 is the first).
+ *
+ * Input Parameters:
+ *   index  - The index of the entry
+ *   entry  - Location to return the parsed group file entry
+ *   buffer - I/O buffer used to access the group file
+ *   buflen - The size of the I/O buffer in bytes
+ *
+ * Returned Value:
+ *   < 0 :  An error has occurred.
+ *   = 0 :  There is no entry with this index.
+ *   = 1 :  The entry with this index was found.
+ *
+ ****************************************************************************/
+
+int grp_findby_index(int index, FAR struct group *entry, FAR char *buffer,
+                     size_t buflen)
+{
+  struct grp_index_s ctx;
+
+  ctx.index   = index;
+  ctx.current = 0;
+  return grp_foreach(grp_match_index, (uintptr_t)&ctx, entry, buffer,
+                     buflen);
+}
+
 /****************************************************************************
  * Name: grp_findby_user
  *
diff --git a/libs/libc/grp/lib_grp.h b/libs/libc/grp/lib_getgrent.c
similarity index 53%
copy from libs/libc/grp/lib_grp.h
copy to libs/libc/grp/lib_getgrent.c
index 0d84dd39652..761e904a13a 100644
--- a/libs/libc/grp/lib_grp.h
+++ b/libs/libc/grp/lib_getgrent.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * libs/libc/grp/lib_grp.h
+ * libs/libc/grp/lib_getgrent.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -20,9 +20,6 @@
  *
  ****************************************************************************/
 
-#ifndef __LIBS_LIBC_GRP_LIB_GRP_H
-#define __LIBS_LIBC_GRP_LIB_GRP_H
-
 /****************************************************************************
  * Included Files
  ****************************************************************************/
@@ -31,65 +28,82 @@
 
 #include <grp.h>
 
+#include "grp/lib_grp.h"
+
 /****************************************************************************
- * Pre-processor Definitions
+ * Private Data
  ****************************************************************************/
 
-#define ROOT_GID 0
-#define ROOT_NAME "root"
-#define ROOT_PASSWD "x"
+/* Index of the next entry that getgrent() returns */
 
-/* Reserver space for a NULL terminated list for group member names */
+static int g_group_index;
 
-#define MEMBER_SIZE ((CONFIG_LIBC_GROUP_NUSERS + 1) * sizeof(FAR char *))
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
 
-/* Reserve space for the maximum line in the group file PLUS space for an
- * array of Member names.
- */
+/****************************************************************************
+ * Name: setgrent
+ *
+ * Description:
+ *   Rewind the group database, so that the next getgrent() returns the
+ *   first entry.
+ *
+ ****************************************************************************/
 
-#define GRPBUF_RESERVE_SIZE (CONFIG_LIBC_GROUP_LINESIZE + MEMBER_SIZE)
+void setgrent(void)
+{
+  g_group_index = 0;
+}
 
 /****************************************************************************
- * Public Data
+ * Name: endgrent
+ *
+ * Description:
+ *   Close the group database.  The next getgrent() returns the first entry.
+ *
  ****************************************************************************/
 
-#ifdef __cplusplus
-#define EXTERN extern "C"
-extern "C"
+void endgrent(void)
 {
-#else
-#define EXTERN extern
-#endif
+  g_group_index = 0;
+}
 
+/****************************************************************************
+ * Name: getgrent
+ *
+ * Description:
+ *   Return the next entry of the group database.
+ *
+ * Returned Value:
+ *   A pointer to a statically allocated group structure, or NULL if there
+ *   are no more entries or an error occurs.
+ *
+ ****************************************************************************/
+
+FAR struct group *getgrent(void)
+{
 #ifdef CONFIG_LIBC_GROUP_FILE
-/* Data for non-reentrant group functions */
+  int ret;
 
-EXTERN struct group g_group;
-EXTERN char g_group_buffer[GRPBUF_RESERVE_SIZE];
-#endif
+  ret = grp_findby_index(g_group_index, &g_group, g_group_buffer,
+                         GRPBUF_RESERVE_SIZE);
+  if (ret != 1)
+    {
+      return NULL;
+    }
 
-/****************************************************************************
- * Public Function Prototypes
- ****************************************************************************/
+  g_group_index++;
+  return &g_group;
+#else
+  /* The only group is root */
 
-FAR struct group *getgrbuf(gid_t gid, FAR const char *name,
-                           FAR const char *passwd);
-int getgrbuf_r(gid_t gid, FAR const char *name, FAR const char *passwd,
-               FAR struct group *grp, FAR char *buf, size_t buflen,
-               FAR struct group **result);
+  if (g_group_index != 0)
+    {
+      return NULL;
+    }
 
-#ifdef CONFIG_LIBC_GROUP_FILE
-int grp_findby_name(FAR const char *gname, FAR struct group *entry,
-                    FAR char *buffer, size_t buflen);
-int grp_findby_gid(gid_t gid, FAR struct group *entry, FAR char *buffer,
-                   size_t buflen);
-int grp_findby_user(FAR const char *user, gid_t group,
-                    FAR gid_t *grouplist, int maxgroups, FAR int *count);
+  g_group_index++;
+  return getgrbuf(ROOT_GID, ROOT_NAME, ROOT_PASSWD);
 #endif
-
-#undef EXTERN
-#ifdef __cplusplus
 }
-#endif
-
-#endif /* __LIBS_LIBC_GRP_LIB_GRP_H */
diff --git a/libs/libc/grp/lib_grp.h b/libs/libc/grp/lib_grp.h
index 0d84dd39652..b70831d2a2b 100644
--- a/libs/libc/grp/lib_grp.h
+++ b/libs/libc/grp/lib_grp.h
@@ -83,6 +83,8 @@ int grp_findby_name(FAR const char *gname, FAR struct group 
*entry,
                     FAR char *buffer, size_t buflen);
 int grp_findby_gid(gid_t gid, FAR struct group *entry, FAR char *buffer,
                    size_t buflen);
+int grp_findby_index(int index, FAR struct group *entry, FAR char *buffer,
+                     size_t buflen);
 int grp_findby_user(FAR const char *user, gid_t group,
                     FAR gid_t *grouplist, int maxgroups, FAR int *count);
 #endif

Reply via email to