+ # 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]};