User and group info

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 walking getgrent in the same process, including inside threads that share the iterator, sees the rewind.

  • $! — 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 $_, @ARGV, 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:

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, and 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.

  • 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 — read the next group record; consumes the iterator that setgrent rewinds

  • endgrent — close the iterator when the scan is finished; the symmetric bookend to setgrent

  • getgrnam — lookup a single group by name without touching the iterator at all; prefer this for one-shot queries

  • getgrgid — lookup a single group by GID; same reasoning as getgrnam

  • setpwent — the equivalent rewind for the password database