summaryrefslogtreecommitdiff
path: root/localuserinfo
blob: a13b2b375101013428d2a33e4e096399883c0fdd (plain)
  1. #!/usr/bin/perl -wT
  2. my $ID = q$Id: localuserinfo,v 1.7 2007-02-07 15:08:09 jonas Exp $;
  3. #
  4. # localuserinfo -- List fullname for each user
  5. #
  6. # Written by Jonas Smedegaard <dr@jones.dk>
  7. # Copyright 2003-2007 Jonas Smedegaard <dr@jones.dk>
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. #
  23. # TODO: Options to suppress infochunks
  24. #
  25. use strict;
  26. use Getopt::Long;
  27. use User::pwent;
  28. use User::grent;
  29. our $verbose = 1; # should we be verbose?
  30. my $ignore_badname = 0; # should we ignore bad names?
  31. my $include_username = 1;
  32. my $include_fullname = 1;
  33. my $include_office = 0;
  34. my $include_officehints = 1;
  35. my $include_workphone = 1;
  36. my $include_homephone = 1;
  37. my $include_other = 0;
  38. my $include_addresshints = 1;
  39. my $include_mail = 0;
  40. my $include_groupname = 0;
  41. my $include_members = 0;
  42. my $include_groups = 0;
  43. my $include_grouphints = 1;
  44. our $custom_template;
  45. our @names;
  46. # Resolve version number from CVS id
  47. my $version = join (' ', (split (' ', $ID))[1..3]);
  48. $version =~ s/,v\b//;
  49. $version =~ s/(\S+)$/($1)/;
  50. our $maildomain_path = '/etc/mailname';
  51. our $maildomain = &get_maildomain;
  52. # Parse options, sanity checks
  53. unless (
  54. GetOptions (
  55. "quiet|q" => sub { $verbose = 0 },
  56. "username" => \$include_username,
  57. "fullname|n" => \$include_fullname,
  58. "office" => \$include_office,
  59. "officehints" => \$include_officehints,
  60. "workphone" => \$include_workphone,
  61. "homephone" => \$include_homephone,
  62. "other" => \$include_other,
  63. "addresshints" => \$include_addresshints,
  64. "mail|m" => \$include_mail,
  65. "groupname" => \$include_groupname,
  66. "members" => \$include_members,
  67. "groups" => \$include_groups,
  68. "grouphints" => \$include_grouphints,
  69. "custom=s" => \$custom_template,
  70. "ignore-badname" => \$ignore_badname,
  71. "help|h" => sub { &usage(); exit 0 },
  72. "version|v" => sub { &version(); exit 0 },
  73. "debug" => sub { $verbose = 2 }
  74. )
  75. ) {
  76. &usage();
  77. exit 1;
  78. }
  79. while (defined(my $arg = shift(@ARGV))) {
  80. push (@names, $arg);
  81. }
  82. # TODO: Support custom ordering and custom delimiter
  83. my @infochunks;
  84. push (@infochunks, 'username') if ($include_username);
  85. push (@infochunks, 'fullname') if ($include_fullname);
  86. push (@infochunks, 'office') if ($include_office);
  87. push (@infochunks, 'officehints') if ($include_officehints);
  88. push (@infochunks, 'workphone') if ($include_workphone);
  89. push (@infochunks, 'homephone') if ($include_homephone);
  90. push (@infochunks, 'other') if ($include_other);
  91. push (@infochunks, 'addresshints') if ($include_addresshints);
  92. push (@infochunks, 'mailaddress') if ($include_mail);
  93. push (@infochunks, 'groupname') if ($include_groupname);
  94. push (@infochunks, 'members') if ($include_members);
  95. push (@infochunks, 'groups') if ($include_groups);
  96. push (@infochunks, 'grouphints') if ($include_grouphints);
  97. my $template = $custom_template ? $custom_template : '%' . join('% %', @infochunks) . '%';
  98. my %groups;
  99. while (my $gr = getgrent()) {
  100. foreach my $member (@{$gr->members}) {
  101. push @{$groups{$member}}, $gr->name unless ($member eq $gr->name);
  102. }
  103. }
  104. # TODO: Rewrite to batch-resolve userinfo for all users before using any
  105. while (my $username = shift @names) {
  106. my $string;
  107. my ($fullname, $office, $workphone, $homephone, $other, $groupname, $members, $groups, $officehints, $addresshints, $grouphints) = &getuserinfo($username);
  108. my $mailaddress = "$username\@$maildomain";
  109. $string = $template;
  110. $string =~ s/\%username\%/$username/g;
  111. $string =~ s/\%fullname\%/$fullname/g;
  112. $string =~ s/\%office\%/$office/g;
  113. $string =~ s/\%workphone\%/$workphone/g;
  114. $string =~ s/\%homephone\%/$homephone/g;
  115. $string =~ s/\%other\%/$other/g;
  116. $string =~ s/\%officehints\%/@$officehints/g;
  117. $string =~ s/\%addresshints\%/@$addresshints/g;
  118. $string =~ s/\%mailaddress\%/$mailaddress/g;
  119. $string =~ s/\%groupname\%/$groupname/g;
  120. $string =~ s/\%members\%/$members/g;
  121. $string =~ s/\%groups\%/$groups/g;
  122. $string =~ s/\%grouphints\%/@$grouphints/g;
  123. print "$string\n";
  124. }
  125. sub getuserinfo($) {
  126. my $username = shift;
  127. my $pw = getpwnam($username) || die "Failed locating user \"$username\".";
  128. my $gr = getgrgid($pw->gid) || die "Failed locating primary group of user \"$username\".";
  129. my ($fullname, $office, $workphone, $homephone, $other) = split /\s*,\s*/, $pw->gecos;
  130. $office .= '';
  131. $workphone .= '';
  132. $homephone .= '';
  133. $other .= '';
  134. my @officehints = grep {s/^([\.[:alnum:]_-]+)$/%$1/} split /\s+/, $office;
  135. my @addresshints = grep {/^([\.[:alnum:]_-]+|\+)@([\.[:alnum:]_-]+)?$/} split /\s+/, $other;
  136. my $groupname = $gr->name;
  137. my $members = $gr->members;
  138. my $groups = join ' ', defined($groups{$username}) ? @{$groups{$username}} : '';
  139. my @grouphints = grep {s/^([\.[:alnum:]_-]+)$/\@$1/} split /\s+/, $groups;
  140. return ($fullname, $office, $workphone, $homephone, $other, $groupname, $members, $groups, \@officehints, \@addresshints, \@grouphints);
  141. }
  142. sub get_maildomain {
  143. open (MAILDOMAINFILE, "<" . $maildomain_path) || die "can’t open $maildomain_path: $!";
  144. my $string = readline(MAILDOMAINFILE) || die "can’t read $maildomain_path: $!";
  145. close (MAILDOMAINFILE);
  146. chomp($string);
  147. # FIXME: Do some sanity check of the string - ensure a single word, FQDN syntax etc.
  148. return $string;
  149. }
  150. sub version {
  151. printf ("localuserinfo version %s\n\n", $version);
  152. print <<'EOF';
  153. List fullname and/or other info for each user.
  154. Copyright (C) 2003-2007 Jonas Smedegaard <dr@jones.dk>
  155. EOF
  156. print <<'EOF';
  157. This program is free software; you can redistribute it and/or modify
  158. it under the terms of the GNU General Public License as published by
  159. the Free Software Foundation; either version 2 of the License, or (at
  160. your option) any later version.
  161. This program is distributed in the hope that it will be useful, but
  162. WITHOUT ANY WARRANTY; without even the implied warranty of
  163. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  164. General Public License, /usr/share/common-licenses/GPL, for more details.
  165. EOF
  166. }
  167. sub usage {
  168. print <<"EOF";
  169. localuserinfo USER [USER...]
  170. List fullname and/or other info for each user
  171. general options:
  172. --quiet | -q don't give process information to stdout
  173. --ignore-badname ignore non-existing usernames instead of failing
  174. --help | -h usage message
  175. --username include username
  176. --fullname | -n include fullname
  177. --office include office
  178. --officehints include office hints: words in "office" field
  179. with "%" appended
  180. --workphone include work phone
  181. --homephone include home phone
  182. --other include full "other" field
  183. --addresshints include address hints: words in "other" field
  184. containing "@"
  185. --mail | -m include email address: USERNAME\@MAILDOMAIN
  186. --groupname include primary group
  187. --members include members of primary group
  188. --groups include secondary groups
  189. --grouphints include group hints: secondary groups with "@"
  190. appended
  191. --custom=TEMPLATE custom template, e.g. '%username% (%fullname%)'
  192. available infochunks:
  193. * username
  194. * fullname
  195. office
  196. * officehints
  197. * workphone
  198. * homephone
  199. other
  200. * addresshints
  201. * mailaddress
  202. groupname
  203. members
  204. groups
  205. * grouphint
  206. (all marked infosnippets are included by default,
  207. in the order listed)
  208. --version | -v version number and copyright
  209. EOF
  210. }