- #!/usr/bin/perl -wT
- my $ID = q$Id: localuserinfo,v 1.7 2007-02-07 15:08:09 jonas Exp $;
- #
- # localuserinfo -- List fullname for each user
- #
- # Written by Jonas Smedegaard <dr@jones.dk>
- # Copyright 2003-2007 Jonas Smedegaard <dr@jones.dk>
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- #
- # TODO: Options to suppress infochunks
- #
- use strict;
- use Getopt::Long;
- use User::pwent;
- use User::grent;
- our $verbose = 1; # should we be verbose?
- my $ignore_badname = 0; # should we ignore bad names?
- my $include_username = 1;
- my $include_fullname = 1;
- my $include_office = 0;
- my $include_officehints = 1;
- my $include_workphone = 1;
- my $include_homephone = 1;
- my $include_other = 0;
- my $include_addresshints = 1;
- my $include_mail = 0;
- my $include_groupname = 0;
- my $include_members = 0;
- my $include_groups = 0;
- my $include_grouphints = 1;
- our $custom_template;
- our @names;
- # Resolve version number from CVS id
- my $version = join (' ', (split (' ', $ID))[1..3]);
- $version =~ s/,v\b//;
- $version =~ s/(\S+)$/($1)/;
- our $maildomain_path = '/etc/mailname';
- our $maildomain = &get_maildomain;
- # Parse options, sanity checks
- unless (
- GetOptions (
- "quiet|q" => sub { $verbose = 0 },
- "username" => \$include_username,
- "fullname|n" => \$include_fullname,
- "office" => \$include_office,
- "officehints" => \$include_officehints,
- "workphone" => \$include_workphone,
- "homephone" => \$include_homephone,
- "other" => \$include_other,
- "addresshints" => \$include_addresshints,
- "mail|m" => \$include_mail,
- "groupname" => \$include_groupname,
- "members" => \$include_members,
- "groups" => \$include_groups,
- "grouphints" => \$include_grouphints,
- "custom=s" => \$custom_template,
- "ignore-badname" => \$ignore_badname,
- "help|h" => sub { &usage(); exit 0 },
- "version|v" => sub { &version(); exit 0 },
- "debug" => sub { $verbose = 2 }
- )
- ) {
- &usage();
- exit 1;
- }
- while (defined(my $arg = shift(@ARGV))) {
- push (@names, $arg);
- }
- # TODO: Support custom ordering and custom delimiter
- my @infochunks;
- push (@infochunks, 'username') if ($include_username);
- push (@infochunks, 'fullname') if ($include_fullname);
- push (@infochunks, 'office') if ($include_office);
- push (@infochunks, 'officehints') if ($include_officehints);
- push (@infochunks, 'workphone') if ($include_workphone);
- push (@infochunks, 'homephone') if ($include_homephone);
- push (@infochunks, 'other') if ($include_other);
- push (@infochunks, 'addresshints') if ($include_addresshints);
- push (@infochunks, 'mailaddress') if ($include_mail);
- push (@infochunks, 'groupname') if ($include_groupname);
- push (@infochunks, 'members') if ($include_members);
- push (@infochunks, 'groups') if ($include_groups);
- push (@infochunks, 'grouphints') if ($include_grouphints);
- my $template = $custom_template ? $custom_template : '%' . join('% %', @infochunks) . '%';
- my %groups;
- while (my $gr = getgrent()) {
- foreach my $member (@{$gr->members}) {
- push @{$groups{$member}}, $gr->name unless ($member eq $gr->name);
- }
- }
- # TODO: Rewrite to batch-resolve userinfo for all users before using any
- while (my $username = shift @names) {
- my $string;
- my ($fullname, $office, $workphone, $homephone, $other, $groupname, $members, $groups, @officehints, @addresshints, @grouphints) = &getuserinfo($username);
- my $mailaddress = "$username\@$maildomain";
- $string = $template;
- $string =~ s/\%username\%/$username/g;
- $string =~ s/\%fullname\%/$fullname/g;
- $string =~ s/\%office\%/$office/g;
- $string =~ s/\%workphone\%/$workphone/g;
- $string =~ s/\%homephone\%/$homephone/g;
- $string =~ s/\%other\%/$other/g;
- $string =~ s/\%officehints\%/@officehints/g;
- $string =~ s/\%addresshints\%/@addresshints/g;
- $string =~ s/\%mailaddress\%/$mailaddress/g;
- $string =~ s/\%groupname\%/$groupname/g;
- $string =~ s/\%members\%/$members/g;
- $string =~ s/\%groups\%/$groups/g;
- $string =~ s/\%grouphints\%/@grouphints/g;
- print "$string\n";
- }
- sub getuserinfo($) {
- my $username = shift;
- my $pw = getpwnam($username) || die "Failed locating user \"$username\".";
- my $gr = getgrgid($pw->gid) || die "Failed locating primary group of user \"$username\".";
- my ($fullname, $office, $workphone, $homephone, $other) = split /\s*,\s*/, $pw->gecos;
- my @officehints = grep {s/^([\.[:alnum:]_-]+)$/%$1/} split /\s+/, $office;
- my @addresshints;
- if (defined($other)) {
- @addresshints = grep {/^([\.[:alnum:]_-]+|\+)@([\.[:alnum:]_-]+)?$/} split /\s+/, $other;
- } else {
- $other = "";
- }
- my $groupname = $gr->name;
- my $members = $gr->members;
- my $groups = join ' ', defined($groups{$username}) ? @{$groups{$username}} : '';
- my @grouphints = grep {s/^([\.[:alnum:]_-]+)$/\@$1/} split /\s+/, $groups;
- return ($fullname, $office, $workphone, $homephone, $other, $groupname, $members, $groups, @officehints, @addresshints, @grouphints);
- }
- sub get_maildomain {
- open (MAILDOMAINFILE, "<" . $maildomain_path) || die "can’t open $maildomain_path: $!";
- my $string = readline(MAILDOMAINFILE) || die "can’t read $maildomain_path: $!";
- close (MAILDOMAINFILE);
- chomp($string);
- # FIXME: Do some sanity check of the string - ensure a single word, FQDN syntax etc.
- return $string;
- }
- sub version {
- printf ("localuserinfo version %s\n\n", $version);
- print <<'EOF';
- List fullname and/or other info for each user.
- Copyright (C) 2003-2007 Jonas Smedegaard <dr@jones.dk>
- EOF
- print <<'EOF';
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at
- your option) any later version.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License, /usr/share/common-licenses/GPL, for more details.
- EOF
- }
- sub usage {
- print <<"EOF";
- localuserinfo USER [USER...]
- List fullname and/or other info for each user
- general options:
- --quiet | -q don't give process information to stdout
- --ignore-badname ignore non-existing usernames instead of failing
- --help | -h usage message
- --username include username
- --fullname | -n include fullname
- --office include office
- --officehints include office hints: words in "office" field
- with "%" appended
- --workphone include work phone
- --homephone include home phone
- --other include full "other" field
- --addresshints include address hints: words in "other" field
- containing "@"
- --mail | -m include email address: USERNAME\@MAILDOMAIN
- --groupname include primary group
- --members include members of primary group
- --groups include secondary groups
- --grouphints include group hints: secondary groups with "@"
- appended
- --custom=TEMPLATE custom template, e.g. '%username% (%fullname%)'
- available infochunks:
- * username
- * fullname
- office
- * officehints
- * workphone
- * homephone
- other
- * addresshints
- * mailaddress
- groupname
- members
- groups
- * grouphint
- (all marked infosnippets are included by default,
- in the order listed)
- --version | -v version number and copyright
- EOF
- }
|