--- name: setgrent signature: 'setgrent' since: 5.0 status: documented categories: ["User and group info"] --- ```{index} single: setgrent; Perl built-in ``` *[User and group info](../perlfunc-by-category)* # setgrent Rewind the group-database iterator back to the first entry. `setgrent` tells the system's group-database iterator to start over. The next call to [`getgrent`](getgrent) returns the first group record again, regardless of how far a previous iteration walked. It takes no arguments, returns no useful value, and exists so that a program can re-scan the group database without having to close and reopen it by hand. Pair it with [`endgrent`](endgrent) at the end of a scan to release the underlying file descriptor. ## Synopsis ```perl setgrent; setgrent(); ``` ## What you get back The return value is unspecified and conventionally ignored. Call `setgrent` for its side effect — positioning the iterator — not for its value. ## Global state it touches - The **per-process group-database iterator** maintained by the C library (`getgrent(3)`). It is global to the process, not scoped to a package or a lexical: any other code walking `getgrent` in the same process, including inside threads that share the iterator, sees the rewind. - [`$!`](../perlvar) — on systems whose `setgrent(3)` reports errors (rare; most implementations return `void`), a failure leaves `errno` set. Portable code does not rely on this. `setgrent` does not touch [`$_`](../perlvar), [`@ARGV`](../perlvar), or any filehandle. ## Examples Rewind between two passes over the group database — first to collect all group names, then to collect the members of a specific group: ```perl my @names; while (my @g = getgrent) { push @names, $g[0]; } setgrent; # start over while (my @g = getgrent) { next unless $g[0] eq 'wheel'; print "wheel members: $g[3]\n"; last; } endgrent; ``` Use `setgrent` at the top of a sub that is called repeatedly and wants a fresh scan every time: ```perl sub groups_containing { my ($user) = @_; setgrent; my @groups; while (my ($name, undef, undef, $members) = getgrent) { push @groups, $name if grep { $_ eq $user } split / /, $members; } endgrent; return @groups; } ``` Pair `setgrent` / `endgrent` around a scan so an unrelated caller that was mid-iteration is not surprised when control returns: ```perl setgrent; while (my @g = getgrent) { # ... process ... } endgrent; ``` ## Edge cases - **No argument form only.** Unlike [`sethostent`](sethostent), [`setnetent`](setnetent), [`setprotoent`](setprotoent), and [`setservent`](setservent), which take a `STAYOPEN` flag, `setgrent` takes nothing. Passing an argument is a compile-time error. - **Calling `setgrent` without an intervening `getgrent` is a no-op on most systems** — the iterator is simply positioned at the first entry, and the first `getgrent` after it reads that entry. Don't rely on `setgrent` as an "open the group file" primitive; its only defined behaviour is "rewind". - **Process-global state.** `setgrent` inside one module rewinds the iterator for every other module in the same process. If a library walks `getgrent` to completion and a caller then calls `setgrent`, the library's cursor is gone. Treat the iterator as a shared resource: own it for the duration of a scan, bracketed by `setgrent` and [`endgrent`](endgrent). - **Threads share the iterator.** Two threads calling `getgrent` concurrently will each see a subset of the records; `setgrent` from one thread disturbs the other. For per-thread iteration, read `/etc/group` directly or use a thread-safe wrapper; the built-in is not reentrant. - **Not all platforms implement it identically.** On systems without `setgrent(3)` the call is a no-op and silently succeeds. On systems that do implement it, the exact cost (reopening `/etc/group`, restarting an NSS query, re-querying LDAP) depends on the backing name-service and can be non-trivial — avoid calling it in a tight loop. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`getgrent`](getgrent) — read the next group record; consumes the iterator that `setgrent` rewinds - [`endgrent`](endgrent) — close the iterator when the scan is finished; the symmetric bookend to `setgrent` - [`getgrnam`](getgrnam) — lookup a single group by name without touching the iterator at all; prefer this for one-shot queries - [`getgrgid`](getgrgid) — lookup a single group by GID; same reasoning as [`getgrnam`](getgrnam) - [`setpwent`](setpwent) — the equivalent rewind for the password database