5f9b7675 |
1 | #!/usr/bin/perl -- |
2 | |
3 | use POSIX; |
4 | |
5 | setup(); |
6 | read_config(); |
7 | read_services(); |
8 | parse_query(); |
9 | process_query(); |
10 | |
11 | sub process_query () { |
12 | if (exists $services{$query}) { |
13 | |
14 | exec ($verbose && length $services{$query}->{'verbose'} ? |
15 | $services{$query}->{'verbose'} : |
16 | $services{$query}->{'command'}); |
17 | die $!; |
18 | |
19 | } |
20 | |
21 | if ($query eq '/') { |
22 | |
23 | print ("userv fingerd on $hostname\r\n". |
24 | "queries supported:\r\n". |
25 | "\r\n". |
26 | " <nothing> list of logged on users and available services\r\n". |
27 | " / this help text\r\n". |
28 | " <service> separately advertised special finger service\r\n". |
29 | " <user> user (logged in or otherwise)\r\n". |
30 | " <user>+<xtra> user-provided extended/special finger service\r\n". |
31 | " /<substring> search for user matching substring\r\n") |
32 | or die $!; |
33 | |
34 | return; |
35 | |
36 | } |
37 | |
38 | if (!length $query) { |
39 | |
40 | read_per_user(); |
41 | |
42 | if ($verbose) { |
43 | print "Username Idle Msg,tty Login at From\r\n" or die $!; |
44 | } |
45 | |
46 | open W,"who -iw|" or die $!; |
47 | while (<W>) { |
48 | |
49 | m/^(\w+) +(\S) +(\S+) +(\w+ +\d+ \d\d\:\d\d) +(\S+) +(.*)$/ or die; |
50 | ($user, $mesg, $tty, $login, $idle, $from) = ($1,$2,$3,$4,$5,$6); |
51 | $mesg = $mesg =~ m/[-+]/ ? $& : '?'; |
52 | |
53 | if ($tty =~ m/\./) { |
54 | $from =~ s/.$/$& /; |
55 | $from.= $tty; |
56 | $tty= ''; |
57 | } |
58 | |
59 | $pref= exists $user_pref_list{$user} |
60 | ? $user_pref_list{$user} : $def_pref_list; |
61 | next unless $pref =~ m/^\+/; |
62 | |
63 | $idle= '' unless $pref =~ m/i/; |
64 | $mesg= ' ' unless $pref =~ m/m/; |
65 | $tty= '' unless $pref =~ m/t/; |
66 | $login= '' unless $pref =~ m/l/; |
67 | $from= '' unless $pref =~ m/t/; |
68 | |
69 | if ($verbose) { |
70 | |
71 | printf "%-8s %-5s %s%-8s %-12s %s\r\n", |
72 | $user, $idle, $mesg, $tty, $login, $from |
73 | or die $!; |
74 | } else { |
75 | $users{$user}->{'pref'} = $pref; |
76 | $users{$user}->{'mesg'}->{$mesg} = 1; |
77 | $users{$user}->{'idle'} = min_idle($users{$user}->{'idle'}, $idle); |
78 | } |
79 | |
80 | } |
81 | $!=0; close W; $? and die "$! $?"; |
82 | |
83 | if (!$verbose) { |
84 | print "Username Idle Msg Name\r\n" or die $!; |
85 | |
86 | for $user (sort keys %users) { |
87 | $pref= $users{$user}->{'pref'}; |
88 | $name= $pref =~ m/n/ ? (getpwnam($user))[6] : ''; |
89 | $name =~ s/,.*//; |
90 | $mesg= join('', sort keys %{ $users{$user}->{'mesg'} }); |
91 | $mesg= '+' if $mesg =~ m,\+,; |
92 | printf "%-8s %-5s %s %s\r\n", |
93 | $user, $users{$user}->{'idle'}, $mesg, $name |
94 | or die $!; |
95 | } |
96 | } |
97 | |
98 | foreach $service (sort keys %services) { |
99 | $desc= $services{$service}->{'desc'}; |
100 | next unless length $desc; |
101 | |
102 | if (!$anyservice) { |
103 | print "\r\nService Description\r\n" or die $!; |
104 | $anyservice= 1; |
105 | } |
106 | |
107 | printf "%-12s %s\r\n", $service, $desc or die $!; |
108 | } |
109 | |
110 | print "\r\nFor help, finger /\@$hostname\r\n"; |
111 | return; |
112 | |
113 | } |
114 | |
115 | if ($query =~ s,^/,,) { |
116 | $query =~ s/\W/\\$&/g; |
117 | read_per_user(); |
118 | |
119 | while (($user,$passwd,$uid,$gid,$quota,$comment,$name) = getpwent) { |
120 | $name =~ s/,.*//; |
121 | |
122 | $pref= exists $user_pref_search{$user} |
123 | ? $user_pref_search{$user} |
124 | : $def_pref_search; |
125 | next unless $pref =~ m/[uy]/; |
126 | $name= '' unless $pref =~ m/y/; |
127 | next unless query_match($user) || query_match($name); |
128 | |
129 | if (!$found) { |
130 | print "Username Name\r\n" or die $!; |
131 | $found= 1; |
132 | } |
133 | printf "%-9s %s\r\n", $user,$name or die $!; |
134 | |
135 | } |
136 | |
137 | if (!$found) { |
138 | print "No matches. finger /\@$hostname for help.\r\n" or die $!; |
139 | } |
140 | |
141 | return; |
142 | } |
143 | |
144 | if ($query =~ s/\+.*$//) { $qsuffix= $&; } |
145 | |
146 | if (!(($user)= getpwnam($query))) { |
147 | print "No user named \`$query'. finger /\@$hostname for help.\r\n" or die $!; |
148 | return; |
149 | } |
150 | |
151 | @servcmd= length $qsuffix |
152 | ? ('finger-finger') |
153 | : ('finger-extended',$qsuffix); |
154 | exec 'userv','-t',300,$user,@list; |
155 | die $!; |
156 | |
157 | } |
158 | |
159 | sub query_match ($) { |
160 | my ($data) = @_; |
161 | return $data =~ m/\b$query\b/io; |
162 | } |
163 | |
164 | sub setup () { |
165 | $progname= $0; $progname =~ s,.*/,,; |
166 | alarm(300); |
167 | |
168 | $config= '/etc/finger-userv/config'; |
169 | |
170 | if (@ARGV) { @ARGV == 1 or die; $config= $ARGV[1]; } |
171 | $services= '/etc/userv/finger/services'; |
172 | $peruser= '/var/lib/userv/finger/prefs'; |
173 | $def_pref_list= '+m'; $list_fields= 'imtlfn'; |
174 | $def_pref_search= 'y'; $search_opts= 'nuy'; |
175 | } |
176 | |
177 | sub parse_query () { |
178 | $query= <STDIN>; |
179 | $query =~ s/\r?\n$// or die "$0: no query\n"; |
180 | |
181 | $verbose = $query =~ s,^/[wW],,; |
182 | $query =~ s/^ *//; |
183 | } |
184 | |
185 | sub min_idle ($$) { |
186 | my ($a,$b) = @_; |
187 | return '.' if $a eq '.' || $b eq '.'; |
188 | return $b if $a eq 'old' || $a eq ''; |
189 | return $a if $b eq 'old' || $b eq '';; |
190 | return $a le $b ? $a : $b; |
191 | } |
192 | |
193 | sub read_config () { |
194 | if (open C, "$config") { |
195 | while (<C>) { |
196 | chomp; s/\s+$//; s/^\s+//; |
197 | if (m/^default\-pref\s+([-+][$list_fields]+)\s+([$search_opts])$/) { |
198 | $def_pref_list= $1; |
199 | $def_pref_search= $2; |
200 | } elsif (m/^hostname\s+(\S+)$/) { |
201 | $hostname= $1; |
202 | } elsif (m/^prefs\-file\s+(\S.*)$/) { |
203 | $peruser= $1; |
204 | } elsif (m/^services\-file\s+(\S.*)$/) { |
205 | $services= $1; |
206 | } elsif (m/\S/ && !m/^\#/) { |
207 | die; |
208 | } |
209 | } |
210 | close C or die $!; |
211 | } elsif ($! != &ENOENT) { |
212 | die $!; |
213 | } |
214 | |
215 | if (!defined $hostname) { |
216 | chomp($hostname= `hostname -f`); |
217 | length $hostname or die $?; |
218 | } |
219 | } |
220 | |
221 | sub read_services () { |
222 | if (open C, "$services") { |
223 | while (<C>) { |
224 | chomp; s/\s+$//; s/^\s+//; |
225 | next if m/^\#/ || !m/\S/; |
226 | if (m/^service\s+(\S.*)$/) { |
227 | $sname= $1; |
228 | die if exists $services{$sname}; |
229 | } elsif (m/^(desc|command|verbose)\s+(\S.*)$/) { |
230 | die if exists $services{$sname}->{$1}; |
231 | $services{$sname}->{$1}= $2; |
232 | } else { |
233 | die; |
234 | } |
235 | } |
236 | close C; |
237 | foreach $sname (keys %services) { |
238 | die unless exists $services{$sname}->{'command'}; |
239 | } |
240 | } elsif ($! != &ENOENT) { |
241 | die $!; |
242 | } |
243 | } |
244 | |
245 | sub read_per_user () { |
246 | if (open DL, "$peruser") { |
247 | while (<DL>) { |
248 | m/^(\w+) ([-+][$list_fields]+) ([$search_opts])$/ or die; |
249 | $user_pref_list{$1}= $2; |
250 | $user_pref_search{$1}= $3; |
251 | } |
252 | close DL; |
253 | } elsif ($! != &ENOENT) { |
254 | die $!; |
255 | } |
256 | } |