getgrnam(3)

✨ getgrnam(3) β€” get group file entry ✨

ok so bestie, this one's from the Library Functions Manual and it's about looking up group entries. It's lowkey one of the most useful things in libc and you're gonna slay it. πŸ’–

🌈 LIBRARY

Standard C library (libc, -lc) β€” iconic, we stan.

πŸŽ€ SYNOPSIS

#include <sys/types.h>
#include <grp.h>

struct group *getgrnam(const char *name);
struct group *getgrgid(gid_t gid);

int getgrnam_r(size_t size;
               const char *restrict name, struct group *restrict grp,
               char buf[restrict size], size_t size,
               struct group **restrict result);
int getgrgid_r(size_t size;
               gid_t gid, struct group *restrict grp,
               char buf[restrict size], size_t size,
               struct group **restrict result);

πŸ¦‹ Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

  • getgrnam_r(), getgrgid_r():
    • _POSIX_C_SOURCE
      • || /* glibc <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE

(no cap, you gotta define those macros or glibc will simply not let you see these girls 😀)


πŸ’… DESCRIPTION

okay so, getgrnam() β€” it returns a pointer to a structure holding the broken-out fields of the record in the group database that matches the group name name. And bestie, "the group database" is not just one thing: it's like, the local group file /etc/group, but also NIS, and LDAP. She's versatile. πŸ‘‘

getgrgid() does the exact same thing but you look up by the group ID gid instead of by name. Same broken-out fields, same energy. ✨

The group structure is defined in <grp.h> and she looks like this:

struct group {
    char   *gr_name;        /* group name */
    char   *gr_passwd;      /* group password */
    gid_t   gr_gid;         /* group ID */
    char  **gr_mem;         /* NULL-terminated array of pointers
                               to names of group members */
};

(for the full tea on what all those fields mean, go read group(5) 🫢)

Now β€” getgrnam_r() and getgrgid_r() are the reentrant girlies. They get you the exact same info as getgrnam() and getgrgid(), but instead of handing you a static thing they store the retrieved group structure in the space pointed to by grp. The string fields that the members of the group structure point at get stashed in the buffer buf of size size. And a pointer to the result gets written to *result β€” that's the actual struct on success, or NULL when there's no entry found or a lil error happened. πŸ’€

And this call right here:

sysconf(_SC_GETGR_R_SIZE_MAX)

returns either -1, and she does that without changing errno (periodt, she's polite), or it gives you an initial suggested size for buf. And if that size turns out too small? The call fails with ERANGE, and in that case you just retry with a bigger buffer. growth mindset fr fr. 🌱


πŸ”₯ RETURN VALUE

getgrnam() and getgrgid() hand you back a pointer to a group structure, or NULL if the matching entry isn't found or an error goes down. If there's an error, errno gets set to say which one. And here's the trick bestie: if you wanna check errno after the call, you gotta set it to zero before the call. Otherwise you're just reading stale vibes. πŸ™ˆ

Also, the return value may point into a static area, and it can get overwritten by later calls to getgrent(3), getgrgid(), or getgrnam(). So heads up:

⚠️ Do not pass that returned pointer to free(3). Not even once. She is not yours to free, bestie, she lives in static-land and she stays there. πŸ’€

For the _r versions: on success, getgrnam_r() and getgrgid_r() return zero and set *result to grp. If no matching group record was found, they return 0 and store NULL in *result (yes, zero AND null, that's the bit, don't @ me). And if there's an error, they return an error number and store NULL in *result. Clean, consistent, queen behavior. πŸ‘‘


🌸 ERRORS

  • 0 or ENOENT or ESRCH or EBADF or EPERM or ... β€” the given name or gid was not found. (yeah she's messy like that, whole buffet of possible values)
  • EINTR β€” a signal got caught; see signal(7).
  • EIO β€” I/O error. hardware said "not today".
  • EMFILE β€” the per-process limit on the number of open file descriptors has been reached. too many files open, bestie, close some tabs 😭
  • ENFILE β€” the system-wide limit on the total number of open files has been reached. not just you, the whole system is struggling.
  • ENOMEM β€” not enough memory to allocate the group structure. she needed a bigger plate. πŸ“
  • ERANGE β€” insufficient buffer space supplied. your buf was too smol.

🧚 FILES

  • /etc/group β€” the local group database file. the OG. the source. πŸ’–

πŸ‘‘ ATTRIBUTES

for what all these terms even mean, peep attributes(7). here's the breakdown:

  • getgrnam() β€” Thread safety: MT-Unsafe race:grnam locale
  • getgrgid() β€” Thread safety: MT-Unsafe race:grgid locale
  • getgrnam_r(), getgrgid_r() β€” Thread safety: MT-Safe locale

so like. the non-_r ones are racing, and the _r ones are safe. that's literally the whole point of existing, bestie. 🏁


⭐ VERSIONS

the formulation given above under "RETURN VALUE" is from POSIX.1. And here's the drama: it does not call "not found" an error, hence it does not specify what value errno might have in that situation. But that makes it impossible to recognize errors. Some might argue that according to POSIX, errno should be left unchanged if an entry is not found. But experiments on various UNIX-like systems show that lots of different values occur in this situation:

0, ENOENT, EBADF, ESRCH, EWOULDBLOCK, EPERM, and probably others.

(and probably others. iconic chaos. nobody's checking. πŸ’…)


πŸ’œ STANDARDS

POSIX.1-2008


πŸ¦‹ HISTORY

POSIX.1-2001, SVr4, 4.3BSD β€” she's been around, she's got lore, respect the elders.


🌈 SEE ALSO

endgrent(3), fgetgrent(3), getgrent(3), getpwnam(3), setgrent(3), group(5)


okay that's the whole page, you're officially a group-database girlie now 🫢 and just so you know, this was pulled from Linux man-pages 6.20 and the page itself is dated 2026-02-08 β€” so yeah, go forth and getgrnam() responsibly, bestie. 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