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


The following commit(s) were added to refs/heads/master by this push:
     new a9b72ed796c libc/grp: add getgrouplist()
a9b72ed796c is described below

commit a9b72ed796c515a1532c36ebccafb6f29978f248
Author: Xiang Xiao <[email protected]>
AuthorDate: Sun Jun 21 01:55:08 2026 +0800

    libc/grp: add getgrouplist()
    
    Add getgrouplist() to the C library.  It scans the group database for
    a user's supplementary groups and always reports the primary group
    first.  Without CONFIG_LIBC_GROUP_FILE only the primary group is
    returned, since no membership information is available.
    
    The group file is read through lib_get_tempbuffer()/lib_put_tempbuffer()
    to avoid a heap allocation on every lookup.
    
    Signed-off-by: Xiang Xiao <[email protected]>
---
 include/grp.h                    |   2 +
 libs/libc/grp/CMakeLists.txt     |   2 +-
 libs/libc/grp/Make.defs          |   2 +-
 libs/libc/grp/lib_find_grpfile.c | 122 +++++++++++++++++++++++++++++++++++++++
 libs/libc/grp/lib_getgrouplist.c |  95 ++++++++++++++++++++++++++++++
 libs/libc/grp/lib_grp.h          |   2 +
 6 files changed, 223 insertions(+), 2 deletions(-)

diff --git a/include/grp.h b/include/grp.h
index d6297649eaf..1c4f215e54f 100644
--- a/include/grp.h
+++ b/include/grp.h
@@ -72,6 +72,8 @@ int getgrgid_r(gid_t gid, FAR struct group *grp,
                FAR char *buf, size_t buflen,
                FAR struct group **result);
 int initgroups(FAR const char *user, gid_t group);
+int getgrouplist(FAR const char *user, gid_t group, FAR gid_t *groups,
+                 FAR int *ngroups);
 
 #undef EXTERN
 #if defined(__cplusplus)
diff --git a/libs/libc/grp/CMakeLists.txt b/libs/libc/grp/CMakeLists.txt
index 83312f9b56f..62d98a9056a 100644
--- a/libs/libc/grp/CMakeLists.txt
+++ b/libs/libc/grp/CMakeLists.txt
@@ -20,7 +20,7 @@
 #
 # 
##############################################################################
 set(SRCS lib_getgrgid.c lib_getgrgidr.c lib_getgrnam.c lib_getgrnamr.c
-         lib_initgroups.c)
+         lib_initgroups.c lib_getgrouplist.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 7680a6f2ba0..2fe4e37fc05 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
+CSRCS += lib_initgroups.c lib_getgrouplist.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 d0b90ca83a1..98c4cc48150 100644
--- a/libs/libc/grp/lib_find_grpfile.c
+++ b/libs/libc/grp/lib_find_grpfile.c
@@ -31,6 +31,9 @@
 #include <string.h>
 #include <grp.h>
 #include <assert.h>
+#include <errno.h>
+
+#include <nuttx/lib/lib.h>
 
 #include "grp/lib_grp.h"
 
@@ -41,6 +44,19 @@
 typedef CODE int (grp_foreach_match_t)(FAR const struct group *entry,
                                        uintptr_t arg);
 
+/* Context used by grp_match_user() to accumulate the group IDs of all the
+ * groups that a given user is a member of.
+ */
+
+struct grp_user_s
+{
+  FAR const char *user;       /* User name to search for */
+  gid_t           group;      /* Primary group to skip (avoid duplicate) */
+  FAR gid_t      *grouplist;  /* Output array of group IDs */
+  int             maxgroups;  /* Number of slots in grouplist */
+  int             count;      /* Number of group IDs found so far */
+};
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -93,6 +109,61 @@ static int grp_match_gid(FAR const struct group *entry, 
uintptr_t arg)
   return match_gid == entry->gr_gid ? 1 : 0;
 }
 
+/****************************************************************************
+ * Name: grp_match_user
+ *
+ * Description:
+ *   Called for each record in the group file.  If the user (passed via the
+ *   context in arg) is a member of the group, its group ID is appended to
+ *   the caller's output array.  Always returns 0 so that every record in
+ *   the file is visited and the total number of matching groups is counted.
+ *
+ * Input Parameters:
+ *   entry  - The parsed group file record
+ *   arg    - A pointer to the grp_user_s search context
+ *
+ * Returned Value:
+ *   = 0 :  Always, so that iteration continues to the end of the file.
+ *
+ ****************************************************************************/
+
+static int grp_match_user(FAR const struct group *entry, uintptr_t arg)
+{
+  FAR struct grp_user_s *ctx = (FAR struct grp_user_s *)arg;
+  FAR char **member;
+
+  /* The primary group has already been accounted for by the caller.  Skip
+   * it here to avoid reporting it twice.
+   */
+
+  if (entry->gr_gid == ctx->group)
+    {
+      return 0;
+    }
+
+  /* Check whether the user is listed as a member of this group. */
+
+  for (member = entry->gr_mem; *member != NULL; member++)
+    {
+      if (strcmp(*member, ctx->user) == 0)
+        {
+          /* Append the group ID if there is room in the output array.  Keep
+           * counting regardless so the caller learns the required size.
+           */
+
+          if (ctx->count < ctx->maxgroups)
+            {
+              ctx->grouplist[ctx->count] = entry->gr_gid;
+            }
+
+          ctx->count++;
+          break;
+        }
+    }
+
+  return 0;
+}
+
 /****************************************************************************
  * Name: grp_foreach
  *
@@ -337,3 +408,54 @@ 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_user
+ *
+ * Description:
+ *   Scan the group file and collect the group IDs of all groups that have
+ *   'user' as a member, excluding the primary group 'group'.
+ *
+ * Input Parameters:
+ *   user      - The user name to search for
+ *   group     - The primary group ID to exclude from the search
+ *   grouplist - Location to return the matching group IDs
+ *   maxgroups - The number of slots available in grouplist
+ *   count     - On input, the number of group IDs already stored in
+ *               grouplist.  On output, the total number of group IDs found
+ *               (which may exceed maxgroups).
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success.  A negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+int grp_findby_user(FAR const char *user, gid_t group,
+                    FAR gid_t *grouplist, int maxgroups, FAR int *count)
+{
+  struct grp_user_s ctx;
+  struct group entry;
+  FAR char *buffer;
+  int ret;
+
+  buffer = lib_get_tempbuffer(GRPBUF_RESERVE_SIZE);
+  if (buffer == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  ctx.user      = user;
+  ctx.group     = group;
+  ctx.grouplist = grouplist;
+  ctx.maxgroups = maxgroups;
+  ctx.count     = *count;
+
+  ret = grp_foreach(grp_match_user, (uintptr_t)&ctx, &entry, buffer,
+                    GRPBUF_RESERVE_SIZE);
+
+  *count = ctx.count;
+  lib_put_tempbuffer(buffer);
+
+  return ret < 0 ? ret : 0;
+}
diff --git a/libs/libc/grp/lib_getgrouplist.c b/libs/libc/grp/lib_getgrouplist.c
new file mode 100644
index 00000000000..a497434cdb1
--- /dev/null
+++ b/libs/libc/grp/lib_getgrouplist.c
@@ -0,0 +1,95 @@
+/****************************************************************************
+ * libs/libc/grp/lib_getgrouplist.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <grp.h>
+
+#include "grp/lib_grp.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: getgrouplist
+ *
+ * Description:
+ *   The getgrouplist() function scans the group database to obtain the list
+ *   of groups that 'user' belongs to.  The group 'group' (typically the
+ *   primary group ID from the password database) is always included in the
+ *   returned list and is stored as the first element.
+ *
+ * Input Parameters:
+ *   user    - The user name whose group membership is queried.
+ *   group   - An additional group ID (the primary group) to include.
+ *   groups  - Location to return the list of group IDs.
+ *   ngroups - On input, the number of slots available in groups.  On output,
+ *             the actual number of group IDs found.
+ *
+ * Returned Value:
+ *   On success, the number of group IDs found is returned.  If the number of
+ *   groups exceeds the available space, -1 is returned and ngroups is set to
+ *   the number of group IDs that would have been returned.
+ *
+ ****************************************************************************/
+
+int getgrouplist(FAR const char *user, gid_t group, FAR gid_t *groups,
+                 FAR int *ngroups)
+{
+  int maxgroups = *ngroups;
+  int count;
+
+  /* The primary group is always reported first. */
+
+  if (maxgroups > 0)
+    {
+      groups[0] = group;
+    }
+
+  count = 1;
+
+#ifdef CONFIG_LIBC_GROUP_FILE
+  /* Scan the group file for any supplementary groups that 'user' belongs to
+   * and append their group IDs to the list.
+   */
+
+  grp_findby_user(user, group, groups, maxgroups, &count);
+#else
+  /* Without a group file there is no membership information, so only the
+   * primary group is reported.
+   */
+
+  UNUSED(user);
+#endif
+
+  /* If the caller's buffer was too small, report the required size and
+   * return failure.  Otherwise, return the number of group IDs stored.
+   */
+
+  *ngroups = count;
+  return count > maxgroups ? -1 : count;
+}
diff --git a/libs/libc/grp/lib_grp.h b/libs/libc/grp/lib_grp.h
index a7dbf0efb05..0d84dd39652 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_user(FAR const char *user, gid_t group,
+                    FAR gid_t *grouplist, int maxgroups, FAR int *count);
 #endif
 
 #undef EXTERN

Reply via email to