3
# $Id: munin-run.in,v 1.6 2004/04/30 13:14:53 jimmyo Exp $
5
# $Log: munin-run.in,v $
6
# Revision 1.6 2004/04/30 13:14:53 jimmyo
7
# Added support for snmpconf option in plugins.
9
# Revision 1.5 2004/01/29 19:39:00 jimmyo
10
# Generic plugins now use printf instead of echo -n, as this is more portable (SF#885564)
12
# Revision 1.4 2004/01/29 17:36:19 jimmyo
13
# Updated copyright information
15
# Revision 1.3 2004/01/29 16:56:54 jimmyo
16
# Fixed "group" bug. Added support for multiple and optional groups
18
# Revision 1.2 2004/01/15 15:20:01 jimmyo
19
# Making things workable after name change. Upping for test verwion.
21
# Revision 1.1 2004/01/02 18:50:00 jimmyo
22
# Renamed occurrances of lrrd -> munin
24
# Revision 1.1.1.1 2004/01/02 15:18:07 jimmyo
25
# Import of LRRD CVS tree after renaming to Munin
27
# Revision 1.16 2003/12/18 18:51:37 jimmyo
28
# added configuration option "ignore_file", which takes regex for files to ignore (e.g. rpmnew/save) (Deb#224265).
30
# Revision 1.15 2003/12/18 17:58:18 jimmyo
31
# Do a fake clean of the environment because of the taint checking.
33
# Revision 1.14 2003/12/17 21:29:26 jimmyo
34
# Don\'t try to change uid/gid if not running as root. (Deb#224300)
36
# Revision 1.13 2003/12/10 15:30:02 jimmyo
37
# Set path before trying to get hostname
39
# Revision 1.12 2003/12/10 15:11:40 jimmyo
40
# A couple of bugfixes.
42
# Revision 1.11 2003/11/07 17:43:16 jimmyo
43
# Cleanups and log entries
51
# "Clean" environment to disable taint-checking on the environment. We _know_
52
# that the environment is insecure, but we want to let admins shoot themselves
53
# in the foot with it, if they want to.
54
foreach my $key (keys %ENV)
56
$ENV{$key} =~ /^(.*)$/;
62
my $servicedir="@@CONFDIR@@/plugins";
63
my $sconfdir="@@CONFDIR@@/plugin-conf.d";
64
my $conffile="@@CONFDIR@@/munin-node.conf";
70
my $VERSION="@@VERSION@@";
71
my $defuser = getpwnam ("nobody");
72
my $defgroup= getgrnam ("munin");
79
GetOptions ( "config=s" => \$conffile,
81
"version!" => \$do_version,
82
"servicedir=s" => \$servicedir,
83
"sconfdir=s" => \$sconfdir,
84
"sconffile=s" => \$sconffile,
85
"paranoia!" => \$paranoia,
86
"help" => \$do_usage );
90
print "Usage: $0 [options]
93
--help View this message.
94
--config <file> Use <file> as configuration file.
95
[@@CONFDIR@@/munin-node.conf]
96
--servicedir <dir> Dir where plugins are found.
98
--sconfdir <dir> Dir where plugin configurations are found.
99
[@@CONFDIR@@/plugin-conf.d]
100
--sconffile <dir> Dir where plugins are found. Overrides sconfdir.
102
--[no]paranoia Only run plugins owned by root. Check permissions.
104
--debug View debug messages.
105
--version View version information.
111
if ($conffile =~ /^([-\/\@_\w\.]+)$/)
113
$conffile = $1; # $data now untainted
117
die "Bad data in $conffile"; # log this somewhere
119
if ($sconfdir =~ /^([-\/\@_\w\.]+)$/)
121
$sconfdir = $1; # $data now untainted
125
die "Bad data in $sconfdir"; # log this somewhere
127
if (defined $sconffile and $sconffile =~ /^([-\/\@_\w\.]+)$/)
129
$sconffile = $1; # $data now untainted
131
elsif (defined $sconffile)
133
die "Bad data in $sconffile"; # log this somewhere
135
if ($servicedir =~ /^([-\/\@_\w\.]+)$/)
137
$servicedir = $1; # $data now untainted
141
die "Bad data in $servicedir"; # log this somewhere
148
print "munin-run (munin-node) version $VERSION.
149
Written by Jimmy Olsen / Linpro AS
151
Copyright (C) 2002-2004
152
This is free software released under the GNU Public License. There is NO
153
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
158
# Check permissions of configuration
160
if (!&check_perms ($servicedir) or !&check_perms ($conffile))
162
die "Fatal error. Bailing out.";
165
if (! -f $conffile) {
166
print "ERROR: Cannot open $conffile\n";
170
open FILE,$conffile or die "Cannot open $conffile\n";
173
s/#.*//; # no comments
174
s/^\s+//; # no leading white
175
s/\s+$//; # no trailing white
176
next unless length; # anything left?
178
if (($1 eq "host_name" or $1 eq "hostname") and $2)
182
elsif (($1 eq "default_plugin_user" or $1 eq "default_client_user") and $2)
185
my $defuser = &get_uid ($tmpid);
186
if (! defined ($defuser))
188
die "Default user defined in \"$conffile\" does not exist ($tmpid)";
191
elsif (($1 eq "default_plugin_group" or $1 eq "default_client_group") and $2)
194
$defgroup = &get_gid ($tmpid);
195
if (! defined ($defgroup))
197
die "Default group defined in \"$conffile\" does not exist ($tmpid)";
200
elsif (($1 eq "paranoia") and defined $2)
202
if ("$2" eq "no" or "$2" eq "false" or "$2" eq "off" or "$2" eq "0")
211
elsif (($1 eq "ignore_file") and defined $2)
217
$FQDN ||= &get_fq_hostname;
228
### over-ridden subs below
233
if (!&load_auth_file ("", $sconffile, \%sconf))
235
warn "Something wicked happened while reading \"$sconffile\". Check the previous log lines for spesifics.";
240
if (opendir (DIR,$sconfdir))
243
for my $file (grep { -f "$sconfdir/$_" } readdir (DIR))
245
next if $file =~ m/^\./; # Hidden files
246
next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars
247
$file = $1; # Not tainted anymore.
248
foreach my $regex (@ignores)
250
next FILES if $file =~ /$regex/;
252
if (!&load_auth_file ($sconfdir, $file, \%sconf))
254
warn "Something wicked happened while reading \"$servicedir/$file\". Check the previous log lines for spesifics.";
261
opendir (DIR,$servicedir) || die "Cannot open plugindir: $servicedir $!";
263
for my $file (grep { -f "$servicedir/$_" } readdir(DIR)) {
264
next if $file =~ m/^\./; # Hidden files
265
next if $file =~ m/.conf$/; # Config files
266
next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars
267
$file = $1; # Not tainted anymore.
268
foreach my $regex (@ignores)
270
next FILES if $file =~ /$regex/;
272
next if (! -x "$servicedir/$file"); # File not executeable
273
next unless ($file =~ /^$ARGV[0]$/);
274
print "# file: '$file'\n" if $DEBUG;
276
if (defined $ARGV[1])
278
if ($ARGV[1] =~ /^c/i)
282
elsif ($ARGV[1] =~ /^a/i)
286
elsif ($ARGV[1] =~ /^snmp/i)
290
elsif ($ARGV[1] =~ /^s/i)
296
my @rows = run_service($file, $arg);
298
for my $row (@rows) {
299
print "row: $row\n" if $DEBUG;
300
if ($row =~ m/^host_name (.+)$/) {
301
print "Found host_name, using it\n" if $DEBUG;
305
$nodes{$node}{$file}=1;
311
my ($service,$command) = @_;
315
if ($services{$service}) {
317
local $SIG{ALRM} = sub {
321
# Setting environment
322
$sconf{$service}{user} = &get_var (\%sconf, $service, 'user');
323
$sconf{$service}{group} = &get_var (\%sconf, $service, 'group');
324
$sconf{$service}{command} = &get_var (\%sconf, $service, 'command');
325
&get_var (\%sconf, $service, 'env', \%{$sconf{$service}{env}});
327
if ($< == 0) # If root
329
# Giving up gid egid uid euid
330
my $u = (defined $sconf{$service}{'user'}?
331
$sconf{$service}{'user'}:
335
($sconf{$service}{'group'}?" $sconf{$service}{group}":"");
337
print "# Want to run as euid/egid $u/$g\n" if $DEBUG;
339
$( = $g unless $g == 0;
340
$) = $gs unless $g == 0;
341
$< = $u unless $u == 0;
342
$> = $u unless $u == 0;
344
if ($> != $u or $g != (split (' ', $)))[0])
346
print "# Can't drop privileges. Bailing out. (wanted uid=",
347
($sconf{$service}{'user'} || $defuser), " gid=\"",
348
$gs, "\"($g), got uid=$> gid=\"$)\"(", (split (' ', $)))[0], ").\n";
351
print "# Running as uid/gid/euid/egid $</$(/$>/$)\n" if $DEBUG;
352
if (!&check_perms ("$servicedir/$service"))
354
print "# Error: unsafe permissions. Bailing out.";
359
# Setting environment...
360
if (exists $sconf{$service}{'env'} and
361
defined $sconf{$service}{'env'})
363
foreach my $key (keys %{$sconf{$service}{'env'}})
365
print "Setting environment $key=$sconf{$service}{env}{$key}\n" if $DEBUG;
366
$ENV{$key} = $sconf{$service}{env}{$key};
369
if (exists $sconf{$service}{'command'} and
370
defined $sconf{$service}{'command'})
373
foreach my $t (@{$sconf{$service}{'command'}})
377
push (@run, "$servicedir/$service", $command);
384
print STDERR "About to run \"", join (' ', @run), "\"\n" if $DEBUG;
385
print "About to run \"", join (' ', @run), "\"\n" if $DEBUG;
390
exec ("$servicedir/$service", $command);
393
print "# Unknown service\n";
399
sub get_fq_hostname {
403
$hostname = Net::Domain::hostfqdn();
405
return $hostname if $hostname;
407
$hostname = `hostname`; # Fall$
409
$hostname =~ s/\s//g;
417
return undef if (!defined $user);
421
$user = getpwnam ($user);
429
return undef if (!defined $group);
433
$group = getgrnam ($group);
440
my ($dir, $file, $sconf) = @_;
443
if (!defined $dir or !defined $file or !defined $sconf)
448
return undef if (length $dir and !&check_perms ($dir));
449
return undef if (!&check_perms ("$dir/$file"));
451
if (!open (IN, "$dir/$file"))
453
warn "Could not open file \"$dir/$file\" for reading ($!), skipping plugin\n";
461
if (/^\s*\[([^\]]+)\]\s*$/)
465
elsif (/^\s*user\s+(\S+)\s*$/)
468
$sconf->{$service}{'user'} = &get_uid ($tmpid);
469
if (!defined $sconf->{$service}{'user'})
471
warn "User \"$tmpid\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin.";
475
elsif (/^\s*group\s+(.+)\s*$/)
478
foreach my $group (split /\s*,\s*/, $tmpid)
482
if ($group =~ /^\(([^)]+)\)$/)
488
my $g = &get_gid ($group);
489
if (!defined $g and !$optional)
491
warn "Group \"$group\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin.";
494
elsif (!defined $g and $optional)
496
print "DEBUG: Skipping \"$group\" (optional).\n" if $DEBUG;
500
if (!defined $sconf->{$service}{'group'})
502
$sconf->{$service}{'group'} = $g;
506
$sconf->{$service}{'group'} .= " $g";
510
elsif (/^\s*command\s+(.+)\s*$/)
512
@{$sconf->{$service}{'command'}} = split (/\s+/, $1);
514
elsif (/^\s*host_name\s+(.+)\s*$/)
516
$sconf->{$service}{'host_name'} = $1;
518
elsif (/^\s*env\s+([^=\s]+)\s*=\s*(.+)$/)
520
$sconf->{$service}{'env'}{$1} = $2;
521
print "Saving $service->env->$1 = $2...\n" if $DEBUG;
522
warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"env $1=$2\" should be rewritten to \"env.$1 $2\").";
524
elsif (/^\s*env\.(\S+)\s+(.+)$/)
526
$sconf->{$service}{'env'}{$1} = $2;
527
print "Saving $service->env->$1 = $2...\n" if $DEBUG;
529
elsif (/^\s*(\w+)\s+(.+)$/)
531
$sconf->{$service}{'env'}{"lrrd_$1"} = $2;
532
print "Saving $service->env->lrrd_$1 = $2...\n" if $DEBUG;
533
warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"$1 $2\" should be rewritten to \"env lrrd_$1=$2\").";
537
warn "Warning: Unknown config option in \"$dir/$file\" under \"[$service]\": $_";
549
return undef if (!defined $target);
550
return 1 if (!$paranoia);
554
warn "Failed to check permissions on nonexistant target: \"$target\"";
558
@stat = stat ($target);
559
if (!$stat[4] == 0 or
560
($stat[5] != 0 and $stat[2] & 00020) or
563
warn "Warning: \"$target\" has dangerous permissions (", sprintf ("%04o", $stat[2] & 07777), ").";
567
if (-f "$target") # Check dir as well
569
(my $dirname = $target) =~ s/[^\/]+$//;
570
return &check_perms ($dirname);
583
if ($var eq 'env' and !defined $env)
588
if ($var ne 'env' and exists $sconf->{$name}{$var})
590
return $sconf->{$name}{$var};
592
# Deciding environment
593
foreach my $wildservice (grep (/\*$/, reverse sort keys %{$sconf}))
595
(my $tmpservice = $wildservice) =~ s/\*$//;
596
next unless ($name =~ /^$tmpservice/);
597
print "Checking $wildservice...\n" if $DEBUG;
601
if (exists $sconf->{$wildservice}{'env'})
603
foreach my $key (keys %{$sconf->{$wildservice}{'env'}})
605
if (! exists $sconf->{$name}{'env'}{$key})
607
$sconf->{$name}{'env'}{$key} = $sconf->{$wildservice}{'env'}{$key};
608
print "Saving $wildservice->$key\n" if $DEBUG;
615
if (! exists $sconf->{$name}{$var} and
616
exists $sconf->{$wildservice}{$var})
618
return ($sconf->{$wildservice}{$var});
631
munin-run - A program to run munin-node plugins from the command line
635
munin-run [--options] <plugin>
641
=item B<< --config <configfile> >>
643
Use E<lt>fileE<gt> as configuration file. [@@CONFDIR@@/munin-node.conf]
645
=item B<< --servicedir <dir> >>
647
Use E<lt>dirE<gt> as plugin dir. [@@CONFDIR@@/plugins]
649
=item B<< --sconfdir <dir> >>
651
Use E<lt>dirE<gt> as plugin configuration dir. [@@CONFDIR@@/plugin-conf.d]
653
=item B<< --sconffile <file> >>
655
Use E<lt>fileE<gt> as plugin configuration. [undefined]
659
View this help message.
667
Show version information.
673
Munin's node is a daemon that Munin connects to fetch data. This data is
674
stored in .rrd-files, and later graphed and htmlified. It's designed to
675
let it be very easy to graph new datasources.
677
munin-run is a small perlscript to run the plugins used by the munin-node
678
daemon from the command line.
680
For more information, see the documentation section at L<http://munin.sf.net/>.
684
@@CONFDIR@@/munin-node.conf
685
@@CONFDIR@@/plugins/*
686
@@CONFDIR@@/plugin-conf.d/*
687
@@STATEDIR@@/munin-node.pid
688
@@LOGDIR@@/munin-node
692
This is munin-node v@@VERSION@@
696
Audun Ytterdal, Jimmy Olsen, and Tore Anderson.
700
munin-node does, as of now, not check the syntax of the configuration file.
702
Please report other bugs in the bug tracker at L<http://munin.sf.net/>.
706
Copyright � 2002 Audun Ytterdal, Jimmy Olsen, and Tore Anderson / Linpro AS.
708
This is free software; see the source for copying conditions. There is
709
NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
712
This program is released under the GNU General Public License