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 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 at the end of a scan to
release the underlying file descriptor.
Synopsis#
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 walkinggetgrentin the same process, including inside threads that share the iterator, sees the rewind.$!— on systems whosesetgrent(3)reports errors (rare; most implementations returnvoid), a failure leaveserrnoset. Portable code does not rely on this.
Examples#
Rewind between two passes over the group database — first to collect all group names, then to collect the members of a specific group:
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:
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:
setgrent;
while (my @g = getgrent) {
# ... process ...
}
endgrent;
Edge cases#
No argument form only. Unlike
sethostent,setnetent,setprotoent, andsetservent, which take aSTAYOPENflag,setgrenttakes nothing. Passing an argument is a compile-time error.Calling
setgrentwithout an interveninggetgrentis a no-op on most systems — the iterator is simply positioned at the first entry, and the firstgetgrentafter it reads that entry. Don’t rely onsetgrentas an “open the group file” primitive; its only defined behaviour is “rewind”.Process-global state.
setgrentinside one module rewinds the iterator for every other module in the same process. If a library walksgetgrentto completion and a caller then callssetgrent, the library’s cursor is gone. Treat the iterator as a shared resource: own it for the duration of a scan, bracketed bysetgrentandendgrent.Threads share the iterator. Two threads calling
getgrentconcurrently will each see a subset of the records;setgrentfrom one thread disturbs the other. For per-thread iteration, read/etc/groupdirectly 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— read the next group record; consumes the iterator thatsetgrentrewindsendgrent— close the iterator when the scan is finished; the symmetric bookend tosetgrentgetgrnam— lookup a single group by name without touching the iterator at all; prefer this for one-shot queriesgetgrgid— lookup a single group by GID; same reasoning asgetgrnamsetpwent— the equivalent rewind for the password database