From: Tom Wyant Date: Sun, 11 May 2008 14:40:04 +0000 (-0700) Subject: [perl #53500] op/pwent.t should use the DirectoryService on OS X X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=0d7a9d9f455e176eb389f4d5d28bec38cd9fb15d;p=p5sagit%2Fp5-mst-13.2.git [perl #53500] op/pwent.t should use the DirectoryService on OS X From: "Tom Wyant via RT" Message-ID: p4raw-id: //depot/perl@33850 --- diff --git a/t/op/pwent.t b/t/op/pwent.t index 3303f3e..9653c6b 100755 --- a/t/op/pwent.t +++ b/t/op/pwent.t @@ -41,6 +41,71 @@ BEGIN { } } + if (not defined $where && # Try dscl + $Config{useperlio} eq 'define') { # need perlio + + # Map dscl items to passwd fields, and provide support for + # mucking with the dscl output if we need to (and we do). + my %want = do { + my $inx = 0; + map {$_ => {inx => $inx++, mung => sub {$_[0]}}} + qw{RecordName Password UniqueID PrimaryGroupID + RealName NFSHomeDirectory UserShell}; + }; + + # The RecordName for a /User record is the username. In some + # cases there are synonyms (e.g. _www and www), in which case we + # get a blank-delimited list. We prefer the first entry in the + # list because getpwnam() does. + $want{RecordName}{mung} = sub {(split '\s+', $_[0], 2)[0]}; + + # The UniqueID and PrimaryGroupID for a /User record are the + # user ID and the primary group ID respectively. In cases where + # the high bit is set, 'dscl' returns a negative number, whereas + # getpwnam() returns its twos complement. This mungs the dscl + # output to agree with what getpwnam() produces. Interestingly + # enough, getpwuid(-2) returns the right record ('nobody'), even + # though it returns the uid as 4294967294. If you track uid_t + # on an i386, you find it is an unsigned int, which makes the + # unsigned version the right one; but both /etc/passwd and + # /etc/master.passwd contain negative numbers. + $want{UniqueID}{mung} = $want{PrimaryGroupID}{mung} = sub { + unpack 'L', pack 'l', $_[0]}; + + foreach my $dscl (qw(/usr/bin/dscl)) { + -x $dscl or next; + open (my $fh, '-|', join (' ', $dscl, qw{. -readall /Users}, + keys %want, '2>/dev/null')) or next; + my $data; + my @rec; + while (<$fh>) { + chomp; + if ($_ eq '-') { + @rec and $data .= join (':', @rec) . "\n"; + @rec = (); + next; + } + my ($name, $value) = split ':\s+', $_, 2; + unless (defined $value) { + s/:$//; + $name = $_; + $value = <$fh>; + chomp $value; + $value =~ s/^\s+//; + } + if (defined (my $info = $want{$name})) { + $rec[$info->{inx}] = $info->{mung}->($value); + } + } + @rec and $data .= join (':', @rec) . "\n"; + if (open (PW, '<', \$data)) { + $where = "dscl . -readall /Users"; + undef $reason; + last; + } + } + } + if (not defined $where) { # Try local. my $PW = "/etc/passwd"; if (-f $PW && open(PW, $PW) && defined()) {