File: netsaint_statd

package info (click to toggle)
netsaint-statd 2.15-9
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 156 kB
  • ctags: 29
  • sloc: perl: 1,040; sh: 53; makefile: 42
file content (442 lines) | stat: -rwxr-xr-x 13,695 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
#!/usr/bin/perl

################################################################################
#                                                                              #
# Version 2.15 by Nick Reinking, original code by Charlie Cook.                #
# See LICENSE for copyright information                                        #
#                                                                              #
# netsaint_statd [port]                                                        #
#                                                                              #
# netsaint_statd is a daemon which allows for a Netsaint host using            #
# scripts to get information suck as process count, users, disk usage, and     #
# load information.  This daemon does not process the information in anyway.   #
# It merely collects the info and hands it back to the calling script to do    #
# with as it pleases.                                                          #
#                                                                              #
# This script is designed in such a way as to allow for easy porting via the   #
# %commandlist hash.  Adding other checks should also be as easy as making a   #
# minor modification to the %commandlist hash for the wanted command.          #
#                                                                              #
# Function calls have been recently reworked.  This is to allow for *much*     #
# easier extensions of netsaint_statd.  When a client communicates to          #
# netsaint_statd, it sends one line, which contains a request for information  #
# on a particular resource, and arguments for that request.  The new           #
# netsaint_statd will call the function by the resource called, and pass it    #
# the arguments.  For example, client A connections to server B, and sends the #
# line "dog /with/one/tail".  netsaint_statd will then call the function dog() #
# and pass it the parameter /with/one/tail.  This should make adding extra     #
# functionality as easy adding a single function, and modifying an existing    #
# client script.  Note that you must enter these functions in the dispatch     #
# table below. If you need to call commands from the %commandlist for your     #
# functions, they are referenced by $commandlist{$os}{functionname}.  So, if   #
# you want the df command for your current machine, you can get it by          #
# accessing $commandlist{$os}{dfcommand}.  It's that easy.  Sending the client #
# information is a simple 'print Client information'.                          #
#                                                                              #
################################################################################
#
# modification history:
# 20030201	using "df -P" on Linux for long device names in df check
# 20030201	procs check initializes to 0 instead of -1 
# 		(Debian bugs #149742 and #149821 
# 		 thanks to Peter Palfrader <weasel@debian.org>)
# 20030201	better proc state regex (Debian bug #153958)
# 		(thanks to Rainer Clasen <bj@zuto.de>)
# 20030218	allow '.' to appear in command argument
# 20030405	change to SCO uname (now "SCO_SV")
# 		thanks to Torsten Warncke
# 20030530	security fix for named_proc/now using Perl's grep)
# 		(Debian bug #195326 - thanks to Paul Fenwick for the patch)
# 20040901	somehow we lost the -P on the df check for Linux
# 20040926	using /usr/bin/free instead of /proc/meminfo for swapcommand
#	(Debian bug #273566 - thanks to Craig Small)
################################################################################
# VERSION allows us to check netsaint_statd versions in large environments
# using the check_netsaint_statd.pl plugin 
my $VERSION = "2.15-9";

# Uncomment @allowed_hosts if you want to restrict access to only
# certain hosts.  Leaving it uncommented allows everybody to access
# netsaint_statd.  I recommend placing the IP of your netsaint
# server in here, for security reasons (not that my program has any
# security bugs).  :P

my @allowed_hosts; # = ("127.0.0.1","10.20.30.40","123.123.123.123");

my $os = os_uname();
$os = "IRIX" if $os =~ "IRIX64"; # IRIX can have two different unames.
# my $os = "NEXTSTEP";  # Uncomment this if you have a NeXT machine.

my %commandlist = (
	"HP-UX" => {
		dfcommand => "/bin/bdf -l",
		whocommand => "/bin/who -q | /usr/bin/grep \"#\"",
		proccommand => "/bin/ps -el",
		procstates => "SWRITZX",
		uptimecommand => "/bin/uptime",
	},
	"Linux" => {
		dfcommand => "/bin/df -Pk",
		whocommand => "/usr/bin/who -q | /bin/grep \"#\"",
		swapcommand => "/usr/bin/free | /bin/grep \"^Swap:\" | /usr/bin/awk '{ print (\$3/\$2)*100 }'",
		proccommand => "/bin/ps ax",
		procstates => "RSTDZ",
		uptimecommand => "/usr/bin/uptime",
	},
	"SunOS" =>	{
		dfcommand => "/bin/df -k",
		whocommand => "/bin/who -q | /usr/bin/grep \"#\"",
		swapcommand => "/usr/sbin/swap -s | /bin/tr -d -s -c [:digit:][:space:] | nawk '{print (\$3/(\$3+\$4))*100}'",
		proccommand => "ps -e -o \"pid tty s time comm\"",
		procstates => "SRZTO",
		uptimecommand => "/usr/bin/uptime",
	},
	"IRIX" => {
		dfcommand => "/bin/df -kP",
		whocommand => "/bin/who -q | /usr/bin/grep \"#\"",
		proccommand => "ps -e -o \"pid tty state time comm\"",
		procstates => "SRZTIXC0",
		uptimecommand => "/usr/bsd/uptime",
	},
  "OSF1" => {
		dfcommand => "/bin/df -k",
		whocommand => "/bin/who -q | /usr/bin/grep \"Total user\"",
		proccommand => "ps -e -o \"pid tty state time comm\"",
		procstates => "RVSITH",
		uptimecommand => "/bin/uptime",
	},
  "FreeBSD" => {
		dfcommand => "/bin/df -k",
		whocommand => "/usr/bin/who | /usr/bin/wc -l",
		proccommand => "/bin/ps ax",
		procstates => "RSTDIZ",
		uptimecommand => "/usr/bin/uptime",
	},
  "NEXTSTEP" => {
		dfcommand => "/bin/df",
		whocommand => "/bin/who | /usr/ucb/wc -l",
		proccommand => "/bin/ps -ax",
		procstates => "RSTDIZ",
		uptimecommand => "/usr/bin/uptime",
	},
  "BSD/OS" => {
		dfcommand => "/bin/df",
		whocommand => "/usr/bin/who | /usr/bin/wc -l",
		proccommand => "/bin/ps -ax",
		procstates => "RSTDIZ",
		uptimecommand => "/usr/bin/uptime",
	},
  "OpenBSD" => {
		dfcommand => "/bin/df -k",
		whocommand => "/usr/bin/who | /usr/bin/wc -l",
		proccommand => "/bin/ps -ax",
		procstates => "RIDLIS",
		uptimecommand => "/usr/bin/uptime",
	},
  "AIX" => {
		dfcommand => "/usr/bin/df -Ik",
		whocommand => "/usr/bin/who | /usr/bin/wc -l",
		swapcommand => "lsps -sl | grep -v Paging | awk '{print \$2}' | cut -f1 -d%",
		proccommand => "/usr/bin/ps x",
		procstates => "OAWISTZ",
		uptimecommand => "/usr/bin/uptime",
	},
  "NetBSD" => {
		dfcommand => "/usr/bin/df -k",
		whocommand => "/usr/bin/who | /usr/bin/wc -l",
		proccommand => "/bin/ps ax",
		procstates => "RSTDIZ",
		uptimecommand => "/usr/bin/uptime",
	},
  "UNIXWARE2" => {
		dfcommand => "/usr/ucb/df",
		whocommand => "/usr/bin/who -q | /bin/grep \"#\"",
		proccommand => "/usr/bin/ps -el | awk '{printf(\"%6d%9s%2s%5s %s\\n\",\$4,substr(\$0, 61, 8),\$2,substr(\$0,69,5),substr(\$0,75))}",
		procstates => "OSRIZTX",
		uptimecommand => "echo `/usr/bin/uptime`, load average: 0.00, `sar | awk '{oldidle=idle;idle=\$5} END {print 100-oldidle}'`,0.00",
	},
  "SCO_SV" => {
		dfcommand => "/bin/df -Bk",
		whocommand => "/bin/who -q | /usr/bin/grep \"#\"",
		proccommand => "ps -el -o \"pid tty s time args\"",
		procstates => "OSRIZTB",
		uptimecommand => "/usr/bin/uptime",
	}
); 

# Dispatch table for subroutines

my %subroutines =
	(
	"users"      => \&users,
	"disk"       => \&disk,
	"alldisks"   => \&alldisks,
	"uptime"     => \&uptime,
	"procs"      => \&procs,
	"named_proc" => \&named_proc,
	"version"    => \&version,
	"swap"       => \&swap,
	"filemodinterval"    => \&filemodinterval
	);

################################################################################
################################################################################

require 5.003;
BEGIN { $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin:/usr/sbin' }
use POSIX;
use Socket;
use strict;

# Setup upgly global varialbes
my %restrictions;

# Forking into a new daemon...

my $pid = fork;
exit if $pid;
die "Couldn't fork: $!\n" unless defined($pid);
POSIX::setsid() || die "Cannot spawn new session id: $!\n";

# hack in support for PIDFILE by <tmancill@debian.org>
system("echo $$ >/var/run/netsaint_statd.pid");

# Verifying IP restriction information...

&verify_ip_list if @allowed_hosts;

# Extra information needed...

my $port = shift || 1040;
chomp($os);

# Setting up server for listening...
my $proto = getprotobyname('tcp');
socket(Server, PF_INET, SOCK_STREAM, $proto) || die "Can't create socket: $!\n";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1) || die "Can't setsockopt $!\n";
bind(Server, sockaddr_in($port, INADDR_ANY)) || die "Can't bind to socket: $!\n";
listen(Server,SOMAXCONN) || die "Can't listen to socket: $1";

# Infinite loop listening for client connections...

while (my $paddr = accept(Client,Server))
	{
	if (@allowed_hosts)
		{
		my ($cport, $packed_ip) = sockaddr_in($paddr);
		my $dotted_quad = inet_ntoa($packed_ip);
		unless ($restrictions{$dotted_quad})
			{
			send(Client,"Sorry, you ($dotted_quad) are not among the allowed hosts...\n",0);
			close(Client);
			next;
			}
		}
	my ($command,$arg_for_command,$input) = undef;
	next unless(defined($input = <Client>));
	if ($input =~ /^(\w*)\s?([\w\-\/\.]*)/)
		{
		$command = $1;
		$arg_for_command = $2 if $2;
 		$command =~ tr/A-Z/a-z/;
		}

# Call function by name (if in dispatch table)...

	if (exists $subroutines{$command})
		{
		my $rsub = $subroutines{$command};
		&$rsub($arg_for_command);
		close(Client);
		}
	else
		{
		send(Client,"Unknown command\n",0);
		close(Client);
		}
	}

sub verify_ip_list
################################################################################
# verify_ip_list scans the @allowed_hosts array, and double checks to make     #
# sure that you didn't put anything that isn't an IP address in there.         #
################################################################################
	{
	for (my $i=0;$i<=$#allowed_hosts;$i++)
		{
		if ($allowed_hosts[$i] =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/)
			{
			$restrictions{$allowed_hosts[$i]} = 1;
			}
		else
			{
			print "Sorry, your allowed hosts list doesn't contain valid IPs.\n";
			exit(0); 
			}
		}
	}

sub os_uname
	{
	my $uname = ( -e '/usr/bin/uname' ) ? '/usr/bin/uname' : '/bin/uname';
	my $os = (`$uname 2>/dev/null`);
	chomp $os;
	return $os ? $os : undef;
	}

sub users
	{
	open(WHOOUT,"$commandlist{$os}{whocommand} |") || die;
	$_ = <WHOOUT>;
	$_ =~ /[users]*[=|:]?\s?(\d+)/;
	my $users = $1;
	print Client "$users ";
	close(WHOOUT);
	}

sub disk
	{
	my $arg = shift;
	my ($disk, $avail, $capper, $mountpt);

	open(DFOUTPUT,"$commandlist{$os}{dfcommand} |") || die;
	$_ = <DFOUTPUT>;
	DFCHECK: while($_ = <DFOUTPUT>)
		{   
		if (/^([\w\/\:_\.\-\=]*)\s*\d*\s*\d*\s*(\d*)\s*(\d*)\%\s*([\w\/\-]*)/)
			{
			$disk = $1;
			$avail = $2;
			$capper = $3;
			$mountpt = $4;
			last DFCHECK if ($disk eq "$arg");
			}
		}
		
	# assert:  it is possible to fall out of this loop 
	# with $disk set and still not have matched the 
	# device name passed as an arg <tmancill@debian.org>
	if (($disk eq "$arg") && ($disk && $mountpt)) 
		{
		$capper = 100 - $capper;
		print Client "$disk $avail $capper $mountpt ";  
  		} 
	else 
		{
		# the last filesystem didn't match either
		print Client "$arg not found";
		}
	
	($disk,$avail,$capper,$mountpt) = undef;
	close(DFOUTPUT);
	}

sub alldisks
	{
	my $disklisting;

	open(DFOUTPUT,"$commandlist{$os}{dfcommand} |") || die;
	$_ = <DFOUTPUT>;
	while($_ = <DFOUTPUT>)
		{
		if (/^[\w\/\:\.\-\=]*\s*\d*\s*\d*\s*\d*\s*(\d*)\%\s*([\w\/\-]*)/)
			{
			$disklisting .= "(".$2.",".$1.")";
			}
		}
	if ($disklisting)
		{
		print Client $disklisting;
		}
	else
		{
		print Client "no disks?";
		}
	close(DFOUTPUT);
	undef $disklisting;
	}
   
sub uptime
	{
	open(UPTIMEOUTPUT,"$commandlist{$os}{uptimecommand} |");
	$_ = <UPTIMEOUTPUT>;
	$_ =~ /up\s*(.*),\s*\d*\s*user[s]?,\s*load average[s]?:\s*[0-9\.]*,\s*([0-9\.]*),/;
	print Client "$1 - $2 ";
	close(UPTIMEOUTPUT);
	} 

sub procs
	{
	my $procs = 0;
	my $procflags = shift || $commandlist{$os}{procstates};
	open(PROCOUT, "$commandlist{$os}{proccommand} |") || die;
	$_ = <PROCOUT>;
	if ($procflags)
		{
		while (defined($_ = <PROCOUT>))
			{
			if ($_ =~ /\s+\w*([$procflags]+)\w*\s+\d*/)
				{
				$procs++;
				}
			}
		}
	else
		{
		while (<PROCOUT>)
			{
			$procs++;
			}
		}
	print Client "$procs $procflags ";
	($procs, $procflags) = undef;
	close(PROCOUT);
	}

sub named_proc {
	my $args = shift;
	open(PROCOUT, "$commandlist{$os}{proccommand} |") || die;
	@_ = <PROCOUT>;
	# prevent counting the named process check on the netsaint server
	@_ = grep { !/\/usr\/lib\/netsaint\/plugins\/check_named_proc.pl / } @_;
	@_ = grep { /$args/ } @_;
	print Client ++$#_;
	close(PROCOUT);
}
	
# added by <tmancill@debian.org>	
sub version 
        {
	print Client "$VERSION";
	}

# added by <tmancill@debian.org> 
sub swap
	{
	if (defined $commandlist{$os}{swapcommand}) 
		{
		print Client `$commandlist{$os}{swapcommand}`;
		} 
	else 
		{
		print Client "swapcommand not defined for $os";
		}
	}

# added by <tmancill@debian.org> 
# $stat[9] returns mtime in seconds since the epoch
sub filemodinterval
{
	my $filename = shift;
	my $currenttime = time;
	if (-e $filename) {
	   if (my @filestat = stat $filename) {
	      print Client ($currenttime - $filestat[9]);
	   } else {
	      print Client "pluginerror: unable to stat $filename - check perms";
	   }
        } else {
	   print Client "pluginerror: filename $filename not found";
	}
}