getgrouplist(3)
๐ getgrouplist(3) ๐
okay so we're in the Library Functions Manual section, and bestie, this is your one-stop shop for finding out every group a user is in. no cap. let's go ๐ฆ
โจ NAME โจ
getgrouplist โ get list of groups to which a user belongs
๐ LIBRARY ๐
Standard C library (libc, -lc) โ the classic, the icon, the one you already linked against ๐
๐ซถ SYNOPSIS ๐ซถ
#include <grp.h>
int getgrouplist(const char *user, gid_t group,
gid_t *groups, int *ngroups);
๐ธ Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
getgrouplist():
Since glibc 2.19:
_DEFAULT_SOURCE
glibc 2.19 and earlier:
_BSD_SOURCE
๐ DESCRIPTION ๐
The getgrouplist() function scans the group database (see group(5)) to obtain the list of groups that user belongs to. Up to *ngroups of these groups are returned in the array groups. (yes it's giving "here's your little buffer, hope it's big enough" ๐ญ)
If it was not among the groups defined for user in the group database, then group is included in the list of groups returned by getgrouplist(); typically this argument is specified as the group ID from the password record for user. so like, the group you pass in is your safety net โ it will be in there even if the group database forgot to mention it. periodt. ๐
The ngroups argument is a value-result argument: on return it always contains the number of groups found for user, including group; this value may be greater than the number of groups stored in groups. read that again bestie, because it's the plot twist of this whole function โ the number it hands back isn't necessarily the number it actually wrote. ๐ซ
๐ RETURN VALUE ๐
If the number of groups of which user is a member is less than or equal to *ngroups, then the value *ngroups is returned. slay โ
If the user is a member of more than *ngroups groups, then getgrouplist() returns -1. In this case, the value returned in *ngroups can be used to resize the buffer passed to a further call to getgrouplist(). so you call again with a bigger buffer โ that's the whole trick, iykyk ๐
not you getting -1 and panicking. bestie. it's literally telling you how big your buffer should be. it's being helpful. it's serving. ๐
๐ ATTRIBUTES ๐
For an explanation of the terms used in this section, see attributes(7).
- Interface:
getgrouplist() - Attribute: Thread safety
- Value: MT-Safe locale
so she's thread safe, just keep an eye on your locale, okay? ๐ง
๐ STANDARDS ๐
None.
(not a single one. she's unstandardized. she's independent. she's THAT girl ๐ )
๐ฐ๏ธ HISTORY ๐ฐ๏ธ
glibc 2.2.4. ancient. vintage. iconic for her time ๐
๐ BUGS ๐
Before glibc 2.3.3, the implementation of this function contains a buffer-overrun bug: it returns the complete list of groups for user in the array groups, even when the number of groups exceeds *ngroups.
๐จ BESTIE. THIS IS THE SCARY ONE. ๐จ if you are on a pre-2.3.3 glibc, it will happily write past the end of your array like it's got no survival instincts whatsoever. do not pass go. upgrade. ๐
๐ EXAMPLES ๐
The program below displays the group list for the user named in its first command-line argument. The second command-line argument specifies the ngroups value to be supplied to getgrouplist(). The following shell session shows examples of the use of this program:
$ ./a.out cecilia 0
getgrouplist() returned -1
ngroups = 3
$ ./a.out cecilia 3
ngroups = 3
16 (dialout)
33 (video)
100 (users)
look at that first run like ๐ 0 groups?? obviously -1, obviously it tells you ngroups = 3, and then you come back with 3 and get your little trio of groups with their names attached. the glow up is real. โจ
๐ธ Program source ๐ธ
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
int ngroups;
gid_t *groups;
struct group *gr;
struct passwd *pw;
if (argc != 3) {
fprintf(stderr, "Usage: %s <user> <ngroups>\n", argv[0]);
exit(EXIT_FAILURE);
}
ngroups = atoi(argv[2]);
groups = malloc(sizeof(*groups) * ngroups);
if (groups == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
/* Fetch passwd structure (contains first group ID for user). */
errno = 0;
pw = getpwnam(argv[1]);
if (pw == NULL) {
if (errno)
perror("getpwnam");
else
fprintf(stderr, "no such user\n");
exit(EXIT_FAILURE);
}
/* Retrieve group list. */
if (getgrouplist(argv[1], pw->pw_gid, groups, &ngroups) == -1) {
fprintf(stderr, "getgrouplist() returned -1\n");
fprintf(stderr, "ngroups = %d\n", ngroups);
exit(EXIT_FAILURE);
}
/* Display list of retrieved groups, along with group names. */
fprintf(stderr, "ngroups = %d\n", ngroups);
for (int j = 0; j < ngroups; j++) {
printf("%d", groups[j]);
gr = getgrgid(groups[j]);
if (gr != NULL)
printf(" (%s)", gr->gr_name);
printf("\n");
}
exit(EXIT_SUCCESS);
}
copy it exactly, bestie, don't get creative in the middle of a C file ๐ญ
๐ SEE ALSO ๐
and that's the whole page!! ๐ซถ this little legend comes to you courtesy of Linux man-pages 6.20, dated 2025-09-21 โ go forth and populate your group arrays responsibly, okay?? mwah ๐๐๐ฆ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms