--- etbemon-1.3.5.orig/bin/smartctl.helper.cpp +++ etbemon-1.3.5/bin/smartctl.helper.cpp @@ -3,7 +3,28 @@ #include #include #include +#include +void check_device(const char * const dev) +{ + const char * const errmsg = "ERROR: Device \"%s\" didn't match /dev/sd[a-z] /dev/sd[a-z][a-z] /dev/nvme[0-9] /dev/nvme[0-9][0-9]\n"; + if(!strncmp(dev, "/dev/sd", 7)) + { + if(dev[7] < 'a' || dev[7] > 'z' || (dev[8] && (dev[8] < 'a' || dev[8] > 'z' || dev[9]))) + { + fprintf(stderr, errmsg, dev); + exit(1); + } + } + else if(!strncmp(dev, "/dev/nvme", 9)) + { + if(dev[9] < '0' || dev[9] > '9' || (dev[10] && (dev[10] < '0' || dev[10] > '9' || dev[11]))) + { + fprintf(stderr, errmsg, dev); + exit(1); + } + } +} int main(int argc, char **argv) { if(argc != 2) @@ -11,18 +32,40 @@ fprintf(stderr, "ERROR: Must specify device for smartctl\n"); return 1; } - if(strncmp(argv[1], "/dev/sd", 7)) + char *child_args[5]; + child_args[0] = strdup("/usr/sbin/smartctl"); + if(argv[1][0] == 'M') { - fprintf(stderr, "ERROR: First parameter must specify a /dev/sd device\n"); - return 1; + char *buf = strdup(argv[1] + 1); + char *device = strtok(buf, ","); + char *id; + if(!device || strncmp(device, "/dev/sd", 7) || !(id = strtok(NULL, ",")) ) + { + fprintf(stderr, "ERROR: parameter for MegaRAID must be \"M/dev/sdX,X\"\n"); + return 1; + } + check_device(device); + char *megaraid = (char *)malloc(12 + strlen(id)); + strcpy(megaraid, "-dmegaraid,"); + strcpy(megaraid + 11, id); + child_args[1] = megaraid; + child_args[2] = strdup("-H"); + child_args[3] = device; + child_args[4] = NULL; } - if(argv[1][7] < 'a' || argv[1][7] > 'z' || (argv[1][8] && (argv[1][8] < 'a' || argv[1][8] > 'z' || argv[1][9]))) + else { - fprintf(stderr, "ERROR: Device didn't match /dev/sd[a-z] or /dev/sd[a-z][a-z]\n"); - return 1; + if(strncmp(argv[1], "/dev/sd", 7) && strncmp(argv[1], "/dev/nvme", 9)) + { + fprintf(stderr, "ERROR: First parameter must specify a /dev/sd or /dev/nvme device\n"); + return 1; + } + check_device(argv[1]); + child_args[1] = strdup("-H"); + child_args[2] = argv[1]; + child_args[3] = NULL; } - char * const child_args[] = { "/usr/sbin/smartctl", "-H", argv[1], NULL }; - execv(child_args[0], child_args); + execv(child_args[0], (char* const*)child_args); fprintf(stderr, "ERROR: Can't execute %s\n", child_args[0]); return 1; } --- etbemon-1.3.5.orig/debian/changelog +++ etbemon-1.3.5/debian/changelog @@ -1,3 +1,45 @@ +etbemon (1.3.5-6) unstable; urgency=medium + + * Better fix for headers in imapnew.monitor that doesn't need + libhash-case-perl. + * Added hp-temp.monitor to use /sbin/hplog to monitor HP server temperature + * Added -M option to smartctl.monitor for MegaRAID AKA PERC support and + added support for NVMe devices + + -- Russell Coker Mon, 07 Jun 2021 16:34:01 +1000 + +etbemon (1.3.5-5) unstable; urgency=medium + + * Make the deleted-mapped check avoid perl privsep processes, don't want + to force users to logout to pass the check + * Made imapnew.monitor give a correct error when a message has no Message-Id + also made it do case-insensitive checks on header field names. Now + recommends libhash-case-perl as imapnew.monitor depends on it. + + -- Russell Coker Mon, 05 Apr 2021 18:28:52 +1000 + +etbemon (1.3.5-4) unstable; urgency=medium + + * Make deleted-mapped.monitor skip programs starting with /lib/systemd/system. + Add -u option to specify maximum UID to check, default 999. + + -- Russell Coker Mon, 22 Feb 2021 16:18:05 +1100 + +etbemon (1.3.5-3) unstable; urgency=medium + + * Support "python3" and "python3.9" as interpreters for ps.monitor. + * Don't warn from deleted-mapped.monitor.real when process exits before + we can open the map file. + + -- Russell Coker Tue, 19 Jan 2021 18:04:35 +1100 + +etbemon (1.3.5-2) unstable; urgency=medium + + * Update loadavg.monitor to display PSI cgroup2 data to show which cgroups + are responsible for high load average. + + -- Russell Coker Wed, 06 Jan 2021 08:52:30 +1100 + etbemon (1.3.5-1) unstable; urgency=medium * Add smartctl.monitor to run smartctl and parse it's output. --- etbemon-1.3.5.orig/etc/windows.cf +++ etbemon-1.3.5/etc/windows.cf @@ -0,0 +1,95 @@ +# +# Example mon.cf file for Windows +# +# Author: Russell Coker +# + +# +# Global options +# +alertdir = c:\mon\alert.d +mondir = c:\mon\mon.d;c:\mon\mon-local.d +logdir = c:\mon\log +statedir = c:\mon\state +cfbasedir = c:\mon\etc +historicfile = c:\mon\log\history.log +authfile = c:\mon\etc\auth.cf +maxprocs = 20 +histlength = 100 +randstart = 60s +dtlogging = yes +dtlogfile = dtlog + + +# tcp bind for mon client protocol (monshow etc) +serverbind = 127.0.0.1 +# udp bind for traps +trapbind = 127.0.0.1 +clientallow = 127.0.0.1 + +# +# Define groups of hosts to monitor +# +hostgroup localhost localhost + +# +# Define watches +# +watch localhost +# example trap service for traps from other systems + service trap + description trap + traptimeout 10m + trapduration 60m + period + alert mail.alert root@localhost + upalert mail.alert root@localhost + service ping + description Responses to ping + interval 5m + monitor fping.monitor + period wd {Mon-Fri} hr {7am-10pm} + alert mail.alert root@localhost + alertevery 1h + period wd {Sat-Sun} + alert mail.alert root@localhost + service http + description HTTP service + interval 10m + monitor http.monitor + period + numalerts 10 + alert mail.alert root@localhost + upalert mail.alert root@localhost + service smtp + description SMTP service + interval 10m + monitor smtp.monitor -t 60 + period + numalerts 10 + alert mail.alert root@localhost + upalert mail.alert root@localhost +# service pop3 +# description POP3 service +# interval 10m +# monitor pop3.monitor +# period +# numalerts 10 +# alert mail.alert root@localhost +# upalert mail.alert root@localhost +# service imap +# description IMAP service +# interval 10m +# monitor imap.monitor -t 60 +# period +# numalerts 10 +# alert mail.alert root@localhost +# upalert mail.alert root@localhost +# service telnet +# description TELNET service +# interval 10m +# monitor telnet.monitor +# period wd {Mon-Fri} hr {7am-10pm} +# alertevery 1h +# alertafter 2 30m +# alert mail.alert root@localhost --- etbemon-1.3.5.orig/mon-local.d/deleted-mapped.monitor.real +++ etbemon-1.3.5/mon-local.d/deleted-mapped.monitor.real @@ -1,27 +1,55 @@ #!/usr/bin/perl use strict; +use Getopt::Std; + +# Check for programs that have deleted files mapped, this can be due to +# packages replaced to fix security issues. +# Don't check systemd programs (which can cause problems if restarted in +# +# The option -u specifies the maximum UID to report on, default 999 +# (Debian regular users start at 1000) + +our $opt_u = 999; +getopts("u:"); opendir(my $dh, "/proc") || die "Can't opendir /proc: $!"; my @procs = grep { /^[0-9]+$/ && -d "/proc/$_" } readdir($dh); closedir $dh; -my $warned_once = 0; - my %uniq_file; my %root_procs; my %non_root_procs; foreach ( @procs ) { my $pid_num = $_; + + my $proc_name = readlink("/proc/$pid_num/exe"); + if($proc_name =~ /^\/lib\/systemd\/systemd/ or $proc_name eq "/usr/bin/dbus-daemon") + { + next; + } + + if($proc_name =~ /^\/usr\/sbin\/sshd/ && open(CMD, "; + close(CMD); + if($name =~ /sshd: [a-z][a-z0-9]* .priv/) + { + next; + } + } + + my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) + = stat("/proc/$pid_num"); + if($uid > $opt_u) + { + next; + } + my $maps_file = "/proc/$_/maps"; my $status_file = "/proc/$_/status"; if(not open(MAP, "<$maps_file")) { - if($warned_once == 0) - { - print "Can't open /proc/$_/maps\n"; - } - $warned_once = 1; next; } # /memfd: is for memfd https://dvdhrm.wordpress.com/tag/memfd/ @@ -66,7 +94,6 @@ } } } - my $proc_name = readlink("/proc/$pid_num/exe") or print "Can't read /proc/$pid_num/exe\n"; if($proc_name) { if($uid == 0) --- etbemon-1.3.5.orig/mon-local.d/hp-temp.monitor +++ etbemon-1.3.5/mon-local.d/hp-temp.monitor @@ -0,0 +1,100 @@ +#!/usr/bin/perl +use strict; +use Getopt::Std; + +# Mon script to check HP server temperature via the "hplog" program. +# +# Takes any line containing "Normal" to be good, anything else is bad. +# Copyright Russell Coker GPLv3 +# +# Use -i to specify a comma separated list of ID numbers to ignore, EG +# -i2,4 +# Use -f for Fahrenheit + +open(SENSORS, "/sbin/hplog -t 2> /dev/null|") or die "Can't run hplog"; + +my $line_id = ""; +my $input = 0; +my $summary = ""; +my $failed = ""; +my @ignore_list; +my $temp_ignore = "[- 1-9][- 0-9][-0-9]F."; + +our $opt_f; +our $opt_i; +getopts("i:f"); + +if($opt_f) +{ + $temp_ignore = ".[- 1-9][- 0-9][-0-9]C"; +} + +if(length($opt_i) > 0) +{ + foreach my $item (split(/,/, $opt_i)) + { + $ignore_list[$item] = 1; + } +} + +# this is written for a hplog output line having 2 characters for the ID num, a +# space, then 28 characters for the description, 8 characters for the status, +# and then temperatures. +while() +{ + chomp; + next if(not $_ =~ /^[ 1-9][0-9] /); +# next if($_ =~ /Normal/); + + $line_id = substr($_, 0, 2); + next if($ignore_list[$line_id] == 1); + + my $name = substr($_, 4, 28); + $name =~ s/ *$//; + $name =~ s/Basic Sensor/Bas:/; + $summary .= ", " if(length($summary) > 0); + $summary .= $name; + $_ =~ s/$temp_ignore//g; + $failed .= "$_\n"; +} +if(length($failed) == 0) +{ + exit(0); +} +print "$summary\n"; +print $failed; + +my $format = "%8s %5s %4s %8s %s\n"; +my $ccount = 0; +my $output = ""; + +use Proc::ProcessTable; +my $process_table = new Proc::ProcessTable('cache_ttys' => 0 ); + +foreach my $p ( sort { $b->pctcpu <=> $a->pctcpu } @{$process_table->table} ) +{ + if($ccount > 9 || $p->pctcpu < 5.0) + { + last; + } + $ccount++; + my $name; + $name = getpwuid($p->uid) or $name = $p->uid; + my $cmd = $p->cmndline, 0, 60; + if(length($cmd) == 0) + { + $cmd = "[" . $p->fname . "]"; + } + $cmd = substr($cmd, 0, 60); + my $devname = $p->ttydev; + $devname =~ s/\/dev\///; + $output .= sprintf($format, $name, sprintf("%5d", $p->pid), sprintf("%4.1f", $p->pctcpu), $devname, $cmd); +} +if($ccount > 0) +{ + print "\nHere are processes with the top CPU percentages:\n"; + printf($format, "USER", "PID", "CPU", "TTY", "COMMAND"); + print "$output\n"; +} + +exit(1); --- etbemon-1.3.5.orig/mon-local.d/loadavg.monitor +++ etbemon-1.3.5/mon-local.d/loadavg.monitor @@ -165,7 +165,7 @@ } print "Here are processes with the top CPU percentages:\n"; printf($format, "USER", "PID", "CPU", "TTY", "COMMAND"); - print "$output\n"; + print "$output"; } $format = "%8s %5s %6s %6s %8s %s\n"; @@ -198,9 +198,101 @@ } print "Here are processes with the top RAM use:\n"; printf($format, "USER", "PID", "VIRT", "RES", "TTY", "COMMAND"); - print "$output\n"; + print "$output"; } printf("\nSwap Used: %s / %s\n", fmt2($SwapUsed*1024), fmt2($SwapTotal*1024)); +use File::Find; +use Cwd; + +my $cgmount = "/sys/fs/cgroup"; +my $cgmountlength = length($cgmount); + +my %cpuexclude; +my %ioexclude; +my @iopressure; +my @cpupressure; + +sub wanted +{ + if($_ eq "cpu.pressure" or $_ eq "io.pressure") + { + my $dir = getcwd(); + my @dir_parts = split(/\//, $dir); + pop(@dir_parts); + my $parent = join('/', @dir_parts); + + my $type; + if($_ eq "cpu.pressure") + { + if($cpuexclude{$parent} == 1) + { + $ioexclude{$dir} = 1; + return; + } + $type = "cpu"; + } + else + { + if($ioexclude{$parent} == 1) + { + $ioexclude{$dir} = 1; + return; + } + $type = "io"; + } + open(P, $_) or return; + my $line =

; + my $some = (split(/ /, (split(/=/, $line))[1]))[0]; + if($some < 0.5) + { + if($type eq "cpu") + { + $cpuexclude{$dir} = 1; + } + else + { + $ioexclude{$dir} = 1; + } + } + else + { + $line = substr($line, 5); + $dir = substr($dir, $cgmountlength); + if($type eq "cpu") + { + push(@cpupressure, "$dir $line"); + } + else + { + push(@iopressure, "$dir $line"); + $line =

; + push(@iopressure, "$dir $line"); + } + } + close(P); + } +} +find(\&wanted, ( $cgmount )); + +if($#cpupressure != -1) +{ + print "\nSystem CPU Pressure:"; + foreach (@cpupressure) + { + print "$_"; + } +} + +if($#iopressure != -1) +{ + print "\nSystem IO Pressure:"; + foreach (@iopressure) + { + print "$_"; + } + print "\n"; +} + exit(1); --- etbemon-1.3.5.orig/mon-local.d/ps.monitor +++ etbemon-1.3.5/mon-local.d/ps.monitor @@ -51,7 +51,7 @@ } } -my @interpreters = ( "perl", "python", "lua5.1", "lua5.2" ); +my @interpreters = ( "perl", "python", "python3", "python3.9", "lua5.1", "lua5.2" ); # read process table and count the processes of interest my $process_table = new Proc::ProcessTable('cache_ttys' => 0 ); --- etbemon-1.3.5.orig/mon-local.d/smartctl.monitor +++ etbemon-1.3.5/mon-local.d/smartctl.monitor @@ -5,38 +5,67 @@ # copyright 2020 Russell Coker, Licensed under GPLv3 or higher. # # Monitor script to run smartctl and parse output. By default checks -# /dev/sd[a-z] and /dev/sd[a-z][a-z] but you can give a list of devices on the -# command line +# /dev/sd[a-z] /dev/sd[a-z][a-z] /dev/nvme[0-9] /dev/nvme[0-9][0-9] but +# you can give a list of devices on the command line # -# -f to treat marginal as failed +# -f to treat all marginal conditions as failed # -m ATTRIBUTE_NAME to treat attribute as marginal +# +# -M for MegaRAID support, takes parameters of a device node on the MegaRAID +# and a list of disk IDs separated by commas, eg "-M /dev/sda,0,1,7" for +# disks 0, 1, and 7 on the MegaRAID controller that runs /dev/sda. my $summary; my $margsummary; my $detail; my $margdetail; +my $megadev; +my @ids; our $opt_f; our $opt_m; -getopts("fm:") or die; +our $opt_M; +getopts("fm:M:") or die; -if(-1 == $#ARGV) +if($opt_M) +{ + @ids = split(/,/, $opt_M); + $megadev = $ids[0]; + shift @ids; +} +else { - @ARGV = glob( "/dev/sd[a-z] /dev/sd[a-z][a-z]" ); if(-1 == $#ARGV) { - print "No devices found\n"; - exit(1); + @ids = glob( "/dev/sd[a-z] /dev/sd[a-z][a-z] /dev/nvme[0-9] /dev/nvme[0-9][0-9]" ); + if(-1 == $#ids) + { + print "No devices found\n"; + exit(1); + } + } + else + { + @ids = @ARGV; } } -foreach my $dev (@ARGV) +foreach my $dev (@ids) { - open(SMART, "/usr/lib/mon/bin/smartctl.helper $dev|") or die "Can't run smartctl.helper"; + my $cmd; + if($opt_M) + { + $cmd = "/usr/lib/mon/bin/smartctl.helper M$megadev,$dev" + } + else + { + $cmd = "/usr/lib/mon/bin/smartctl.helper $dev"; + } + open(SMART, "$cmd|") or die "Can't run smartctl.helper"; my $header = 0; while() { - if($_ =~ /^=== START OF READ/) + if($_ =~ /^=== START OF .*SMART DATA SECTION/) { $header = 1; last; @@ -44,7 +73,7 @@ } if(not $header) { - die "Error running smartctl"; + die "Error running \"$cmd\", does device exist?"; } my $line = ; my $name = $dev; @@ -106,6 +135,20 @@ exit(1); } -print "$margsummary\n"; -print $margdetail; +if($margsummary) +{ + print "$margsummary\n"; + print $margdetail; +} +else +{ + if($opt_M) + { + print("MegaRAID $opt_M OK\n"); + } + else + { + print("@ids OK\n"); + } +} exit(0); --- etbemon-1.3.5.orig/mon.d/imapnew.monitor +++ etbemon-1.3.5/mon.d/imapnew.monitor @@ -132,8 +132,7 @@ $newcount++; } - my %headers = %{ $imap->parse_headers( $msg, "ALL" ) }; - my @received = @{ $headers{Received} }; + my @received = $imap->parse_headers( $msg, "Received" );; my @rec_date; my @rec_host; push(@rec_date, $delivery_secs); @@ -148,13 +147,17 @@ push(@rec_date, str2time($rdate)); push(@rec_host, $host); } - my @header_date = @{ $headers{Date} }; - push(@rec_date, str2time($header_date[0])); + my $header_date = $imap->get_header($msg, "Date" ); + push(@rec_date, str2time($header_date)); push(@rec_host, "Sender"); - my @subject = @{ $headers{Subject} }; - my @msgid = @{ $headers{'Message-Id'} }; - + my $subject = $imap->get_header($msg, "Subject"); + my $msgid = $imap->get_header($msg, "Message-ID"); + if(not $msgid) + { + print "message without Message-Id header (subject $subject)\n"; + exit(1); + } for(my $i = 0; $rec_date[$i+1]; $i++) { @@ -163,7 +166,7 @@ if($skew > $max_skew) { print "Clock skewed\n"; - print "$rec_host[$i] received message $skew seconds before $rec_host[$i+1] sent it\nSubject: $subject[0]\nMessage-ID: $msgid[0]\n"; + print "$rec_host[$i] received message $skew seconds before $rec_host[$i+1] sent it\nSubject: $subject\nMessage-ID: $msgid\n"; if($delcount) { $imap->expunge(); @@ -178,7 +181,7 @@ elsif($delay > $max_delay) { print "Message delayed $delay seconds\n"; - print "$rec_host[$i] received message $delay seconds after $rec_host[$i+1] sent it\nSubject: $subject[0]\nMessage-ID: $msgid[0]\n"; + print "$rec_host[$i] received message $delay seconds after $rec_host[$i+1] sent it\nSubject: $subject\nMessage-ID: $msgid\n"; if($delcount) { $imap->expunge();