1#!./perl
2
3BEGIN {
4    chdir 't' if -d 't';
5    @INC = '../lib';
6    eval {my @n = getpwuid 0; setpwent()};
7    if ($@ && $@ =~ /(The \w+ function is unimplemented)/) {
8	print "1..0 # Skip: $1\n";
9	exit 0;
10    }
11    eval { require Config; import Config; };
12    my $reason;
13    if ($Config{'i_pwd'} ne 'define') {
14	$reason = '$Config{i_pwd} undefined';
15    }
16    elsif (not -f "/etc/passwd" ) { # Play safe.
17	$reason = 'no /etc/passwd file';
18    }
19
20    if (not defined $where) {	# Try NIS.
21	foreach my $ypcat (qw(/usr/bin/ypcat /bin/ypcat /etc/ypcat)) {
22	    if (-x $ypcat &&
23		open(PW, "$ypcat passwd 2>/dev/null |") &&
24		defined(<PW>)) {
25		$where = "NIS passwd";
26		undef $reason;
27		last;
28	    }
29	}
30    }
31
32    if (not defined $where) {	# Try NetInfo.
33	foreach my $nidump (qw(/usr/bin/nidump)) {
34	    if (-x $nidump &&
35		open(PW, "$nidump passwd . 2>/dev/null |") &&
36		defined(<PW>)) {
37		$where = "NetInfo passwd";
38		undef $reason;
39		last;
40	    }
41	}
42    }
43
44    if (not defined $where) {	# Try local.
45	my $PW = "/etc/passwd";
46	if (-f $PW && open(PW, $PW) && defined(<PW>)) {
47	    $where = $PW;
48	    undef $reason;
49	}
50    }
51
52    if (not defined $where) {      # Try NIS+
53     foreach my $niscat (qw(/bin/niscat)) {
54         if (-x $niscat &&
55           open(PW, "$niscat passwd.org_dir 2>/dev/null |") &&
56           defined(<PW>)) {
57           $where = "NIS+ $niscat passwd.org_dir";
58           undef $reason;
59           last;
60         }
61     }
62    }
63
64    if ($reason) {	# Give up.
65	print "1..0 # Skip: $reason\n";
66	exit 0;
67    }
68}
69
70# By now the PW filehandle should be open and full of juicy password entries.
71
72print "1..2\n";
73
74# Go through at most this many users.
75# (note that the first entry has been read away by now)
76my $max = 25;
77
78my $n = 0;
79my $tst = 1;
80my %perfect;
81my %seen;
82
83print "# where $where\n";
84
85setpwent();
86
87while (<PW>) {
88    chomp;
89    # LIMIT -1 so that users with empty shells don't fall off
90    my @s = split /:/, $_, -1;
91    my ($name_s, $passwd_s, $uid_s, $gid_s, $gcos_s, $home_s, $shell_s);
92    if ($^O eq 'darwin') {
93       ($name_s, $passwd_s, $uid_s, $gid_s, $gcos_s, $home_s, $shell_s) = @s[0,1,2,3,7,8,9];
94    } else {
95       ($name_s, $passwd_s, $uid_s, $gid_s, $gcos_s, $home_s, $shell_s) = @s;
96    }
97    next if /^\+/; # ignore NIS includes
98    if (@s) {
99	push @{ $seen{$name_s} }, $.;
100    } else {
101	warn "# Your $where line $. is empty.\n";
102	next;
103    }
104    if ($n == $max) {
105	local $/;
106	my $junk = <PW>;
107	last;
108    }
109    # In principle we could whine if @s != 7 but do we know enough
110    # of passwd file formats everywhere?
111    if (@s == 7 || ($^O eq 'darwin' && @s == 10)) {
112	@n = getpwuid($uid_s);
113	# 'nobody' et al.
114	next unless @n;
115	my ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$home,$shell) = @n;
116	# Protect against one-to-many and many-to-one mappings.
117	if ($name_s ne $name) {
118	    @n = getpwnam($name_s);
119	    ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$home,$shell) = @n;
120	    next if $name_s ne $name;
121	}
122	$perfect{$name_s}++
123	    if $name    eq $name_s    and
124               $uid     eq $uid_s     and
125# Do not compare passwords: think shadow passwords.
126               $gid     eq $gid_s     and
127               $gcos    eq $gcos_s    and
128               $home    eq $home_s    and
129               $shell   eq $shell_s;
130    }
131    $n++;
132}
133
134endpwent();
135
136print "# max = $max, n = $n, perfect = ", scalar keys %perfect, "\n";
137
138if (keys %perfect == 0 && $n) {
139    $max++;
140    print <<EOEX;
141#
142# The failure of op/pwent test is not necessarily serious.
143# It may fail due to local password administration conventions.
144# If you are for example using both NIS and local passwords,
145# test failure is possible.  Any distributed password scheme
146# can cause such failures.
147#
148# What the pwent test is doing is that it compares the $max first
149# entries of $where
150# with the results of getpwuid() and getpwnam() call.  If it finds no
151# matches at all, it suspects something is wrong.
152# 
153EOEX
154    print "not ";
155    $not = 1;
156} else {
157    $not = 0;
158}
159print "ok ", $tst++;
160print "\t# (not necessarily serious: run t/op/pwent.t by itself)" if $not;
161print "\n";
162
163# Test both the scalar and list contexts.
164
165my @pw1;
166
167setpwent();
168for (1..$max) {
169    my $pw = scalar getpwent();
170    last unless defined $pw;
171    push @pw1, $pw;
172}
173endpwent();
174
175my @pw2;
176
177setpwent();
178for (1..$max) {
179    my ($pw) = (getpwent());
180    last unless defined $pw;
181    push @pw2, $pw;
182}
183endpwent();
184
185print "not " unless "@pw1" eq "@pw2";
186print "ok ", $tst++, "\n";
187
188close(PW);
189