#!/usr/local/sysmansw/runtime/perl/bin/perl -w

## -_- $Name: PerfGraph-2_4d $ % $Id: perfgatherd,v 1.27.2.4.2.1.2.9 2001/09/05 18:30:07 sietse Exp $

#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# 
# User configurable options
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# 

# When using sysmanswd, normally port 29172 will be used for
# communication between sysmanswd and perfgatherd.
# If you want to use another port, change the following variable,
# or set the environment variable $PORT_SYSMANSWD to your value.

$sysmanswd_port = 29172;

#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# 
# End user configurable options
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# 

use Pg;
use Time::Local;
use IO::Handle;
use IO::Socket;
use POSIX ":sys_wait_h";

# Default database name is perfdb - changeable by defining the variable PERFDB
$PERFDB = $ENV{"PERFDB"};
$PERFDB = "perfdb" if not defined($PERFDB);

# Default directory name
$PGDIR = $ENV{'PGDIR'};
$PGDIR = $ENV{'HOME'} . "/perfgraph" if not defined($PGDIR);

# Check whether $PORT_SYSMANSWD exists
$clport = $ENV{"PORT_SYSMANSWD"};
$sysmanswd_port = $clport if defined($clport);
chomp($PGDIR = `ksh -c 'echo ~perfgr'`) if not defined($PGDIR);

$C_UPTIME  = 'a';
$C_SAR     = 'b';
$C_NETSTAT = 'c';
$C_VMSTAT  = 'd';
$C_IOSTAT  = 'e';
$C_PROC1   = 'f'; # for linux 2.0.3x kernels
$C_PROC2   = 'g'; # for linux 2.2.xx kernels
$C_USER    = 'h';

$C_NT4     = 'NT4'; # also valid for W2K


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

sub logmsg
{
    my $msg = shift @_;
    my $tm;

    chomp($tm = localtime(time));
    print "$tm: ". $msg;
}

sub logdie
{
    my $msg = shift @_;
    my $tm;

    chomp($tm = localtime(time));
    die "$tm: ". $msg;
}

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

sub doq($$$)
{
    my ($db, $q, $expected) = @_;
    my ($r, $tm);

    $r = $db->exec($q);
    return $r if $r->resultStatus == $expected;

    logmsg "Error executing query:\n        " . $q . "\n        Reason: " .
           $db->errorMessage . "\n";
    return 0;
}

sub getconfig()
{
    my ($result, $i, $q, $fields, $perfdb);

    undef $perfdb;
    $perfdb = Pg::connectdb("dbname = $PERFDB");
    if ($perfdb->status == PGRES_CONNECTION_BAD)
    {
        logdie "(getconfig) Cannot open database connection: " . $perfdb->errorMessage;
    }

    undef $conn;
    $conn = Pg::connectdb("dbname = " . $sys);
    if ($conn->status == PGRES_CONNECTION_BAD)
    {
        logdie "(getconfig) Cannot open database connection: " . $conn->errorMessage;
    }

    $q = "select systype,gathering from systems where hostname = '" . $sys . "'";
    logdie "(getconfig) Stopping\n" unless $result = doq($perfdb, $q, PGRES_TUPLES_OK);

    $systype = $result->getvalue(0, 0);
    $gathertype = $result->getvalue(0, 1);

    $q = "select distinct gatherfrom from tables where systype = '" . $systype . "'";
    logdie "(getconfig) Stopping\n" unless $result = doq($perfdb, $q, PGRES_TUPLES_OK);

    foreach $i (0 .. $result->ntuples - 1)
    {
        $get_uptime  = 1 if $result->getvalue($i, 0) eq "uptime";
        $get_netstat = 1 if $result->getvalue($i, 0) eq "netstat";
        $get_iostat  = 1 if $result->getvalue($i, 0) eq "iostat";
        $get_vmstat  = 1 if $result->getvalue($i, 0) eq "vmstat";
        $get_proc    = 1 if $result->getvalue($i, 0) eq "proc";
        $get_sar     = 1 if $result->getvalue($i, 0) eq "sar";
    }

    chomp($thissystem = `uname`);
    if ($thissystem eq "HP-UX")
    {
      $rsh = "remsh";
    }
    else
    {
       $rsh = "rsh";
    }

    $q = "select tablename, multiple from tables where systype = '" . $systype . "'";
    print "(getconfig) Stopping\n" unless $tables = doq($perfdb, $q, PGRES_TUPLES_OK);

    foreach $i (0 .. $tables->ntuples - 1)
    {
        $q = "select fieldname, fieldtype, fieldseq from fields" .
             " where fieldtable = '" . $tables->getvalue($i, 0) . "' order by fieldseq";
        print "(getconfig) Stopping\n" unless $fields = doq($perfdb, $q, PGRES_TUPLES_OK);

        %tblfldhash = (%tblfldhash, $tables->getvalue($i, 0), $fields);
    }

    undef $perfdb;
}

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

$DAYAGG  =   5*60; # one sample every 5 mins
$WEEKAGG =  20*60; # one sample every 20 mins
$MONAGG  =  90*60; # one sample every 1.5 hours
$YEARAGG = 720*60; # one sample every 12 hours

sub do_agg_single
{
    my ($table, $max_h, $max_d, $max_w, $max_m, $max_y, $fields) = @_;
    my (@avg_d, @avg_w, @avg_m, @avg_y, $i);
    my ($num_d, $num_w, $num_m, $num_y) = (0, 0, 0, 0);
    my ($result, $rows, $flds, $tstamp, $r);
    
    $q = "select tstamp";
    foreach $fld (1 .. $fields->ntuples - 1)
    {
        $q .= ", " . $fields->getvalue($fld, 0);
        $avg_d[$fld - 1] = 0.0;
        $avg_w[$fld - 1] = 0.0;
        $avg_m[$fld - 1] = 0.0;
        $avg_y[$fld - 1] = 0.0;
    }
    $q .= " from $table where tstamp > ";

    if ($max_h - $YEARAGG > $max_y) { $q .= $max_y; }
    elsif ($max_h - $MONAGG > $max_m) { $q .= $max_m; }
    elsif ($max_h - $WEEKAGG > $max_w) { $q .= $max_w; }
    else { $q .= $max_d; }
    $q .= " order by tstamp";
    logdie "(do_agg_single) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);

    $flds = $fields->ntuples - 1;  # don't count the timestamp
    $rows = $result->ntuples;
    foreach $i (0 .. $rows - 1)
    {
        $tstamp = $result->getvalue($i, 0);

        if ($tstamp > $max_d)
        {
            if ($tstamp <= $max_d + $DAYAGG)
            {
                $num_d++;
                foreach my $j (0 .. $flds - 1)
                {
                    $avg_d[$j] += $result->getvalue($i, $j + 1);
                }
            }

            if ($tstamp >= $max_d + $DAYAGG)
            {
                $max_d += $DAYAGG;
                if ($num_d > 0)
                {
                    $q = "insert into $table" . "_d values (" . $max_d;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $q .= ", " . (($fields->getvalue($j+1, 1) eq "i") ?
                                     int($avg_d[$j]/$num_d) : $avg_d[$j]/$num_d);
                        $avg_d[$j] = 0.0;
                    }
                    $q .= ")";
                    logdie "(do_agg_single) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                }

                # Skip possible hole
                while ($max_d + $DAYAGG < $tstamp) { $max_d += $DAYAGG; }
                $num_d = 0;
            }
        }

        if ($tstamp > $max_w)
        {
            if ($tstamp <= $max_w + $WEEKAGG)
            {
                $num_w++;
                foreach my $j (0 .. $flds - 1)
                {
                    $avg_w[$j] += $result->getvalue($i, $j + 1);
                }
            }

            if ($tstamp >= $max_w + $WEEKAGG)
            {
                $max_w += $WEEKAGG;
                if ($num_w > 0)
                {
                    $q = "insert into $table" . "_w values (" . $max_w;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $q .= ", " . (($fields->getvalue($j+1, 1) eq "i") ?
                                     int($avg_w[$j]/$num_w) : $avg_w[$j]/$num_w);
                        $avg_w[$j] = 0.0;
                    }
                    $q .= ")";
                    logdie "(do_agg_single) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                }

                # Skip possible hole
                while ($max_w + $WEEKAGG < $tstamp) { $max_w += $WEEKAGG; }
                $num_w = 0;
            }
        }

        if ($tstamp > $max_m)
        {
            if ($tstamp <= $max_m + $MONAGG)
            {
                $num_m++;
                foreach my $j (0 .. $flds - 1)
                {
                    $avg_m[$j] += $result->getvalue($i, $j + 1);
                }
            }

            if ($tstamp >= $max_m + $MONAGG)
            {
                $max_m += $MONAGG;
                if ($num_m > 0)
                {
                    $q = "insert into $table" . "_m values (" . $max_m;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $q .= ", " . (($fields->getvalue($j+1, 1) eq "i") ?
                                     int($avg_m[$j]/$num_m) : $avg_m[$j]/$num_m);
                        $avg_m[$j] = 0.0;
                    }
                    $q .= ")";
                    logdie "(do_agg_single) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                }

                # Skip possible hole
                while ($max_m + $MONAGG < $tstamp) { $max_m += $MONAGG; } $num_m = 0;
            }
        }

        if ($tstamp > $max_y)
        {
            if ($tstamp <= $max_y + $YEARAGG)
            {
                $num_y++;
                foreach my $j (0 .. $flds - 1)
                {
                    $avg_y[$j] += $result->getvalue($i, $j + 1);
                }
            }

            if ($tstamp >= $max_y + $YEARAGG)
            {
                $max_y += $YEARAGG;
                if ($num_y > 0)
                {
                    $q = "insert into $table" . "_y values (" . $max_y;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $q .= ", " . (($fields->getvalue($j+1, 1) eq "i") ?
                                     int($avg_y[$j]/$num_y) : $avg_y[$j]/$num_y);
                        $avg_y[$j] = 0.0;
                    }
                    $q .= ")";
                    logdie "(do_agg_single) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                }

                # Skip possible hole
                while ($max_y + $YEARAGG < $tstamp) { $max_y += $YEARAGG; } $num_y = 0;
            }
        }
    }
    return ($max_d, $max_w, $max_m, $max_y);
}


sub do_agg_multi
{
    my ($table, $max_h, $max_d, $max_w, $max_m, $max_y, $fields) = @_;
    my (@avg_d, @avg_w, @avg_m, @avg_y, $i);
    my ($num_d, $num_w, $num_m, $num_y) = (0, 0, 0, 0);
    my ($result, $rows, $flds, $tstamp, $r, $mresult);
    my ($o_max_d, $o_max_w, $o_max_m, $o_max_y);
    
    $o_max_d = $max_d; $o_max_w = $max_w; $o_max_m = $max_m; $o_max_y = $max_y;

    $q = "select * from " . $table . "_mult";
    logdie "(srv_table) Stopping\n" unless $mresult = doq($conn, $q, PGRES_TUPLES_OK);

    foreach my $mult (0 .. $mresult->ntuples - 1)
    {
        $max_d = $o_max_d; $max_w = $o_max_w; $max_m = $o_max_m; $max_y = $o_max_y;

        $q = "select tstamp";
        foreach $fld (2 .. $fields->ntuples - 1)
        {
            $q .= ", " . $fields->getvalue($fld, 0);
            $avg_d[$fld - 1] = 0.0;
            $avg_w[$fld - 1] = 0.0;
            $avg_m[$fld - 1] = 0.0;
            $avg_y[$fld - 1] = 0.0;
        }
        $q .= " from $table where tstamp > ";
    
        if ($max_h - $YEARAGG > $max_y) { $q .= $max_y; }
        elsif ($max_h - $MONAGG > $max_m) { $q .= $max_m; }
        elsif ($max_h - $WEEKAGG > $max_w) { $q .= $max_w; }
        else { $q .= $max_d; }
        $q .= " and " . $fields->getvalue(1, 0) . "='" . $mresult->getvalue($mult, 0) . "'";
        $q .= " order by tstamp";
        logdie "(do_agg_multi) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    
        $flds = $fields->ntuples - 2;
        $rows = $result->ntuples;
        foreach $i (0 .. $result->ntuples - 1)
        {
            $tstamp = $result->getvalue($i, 0);
    
            if ($tstamp > $max_d)
            {
                if ($tstamp <= $max_d + $DAYAGG)
                {
                    $num_d++;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $avg_d[$j] += $result->getvalue($i, $j + 1);
                    }
                }
    
                if ($tstamp >= $max_d + $DAYAGG)
                {
                    $max_d += $DAYAGG;
                    if ($num_d > 0)
                    {
                        $q = "insert into $table" . "_d values (" . $max_d . ", '";
                        $q .= $mresult->getvalue($mult, 0) . "'";
                        foreach my $j (0 .. $flds - 1)
                        {
                            $q .= ", " . (($fields->getvalue($j+2, 1) eq "i") ?
                                         int($avg_d[$j]/$num_d) : $avg_d[$j]/$num_d);
                            $avg_d[$j] = 0.0;
                        }
                        $q .= ")";
                        logdie "(do_agg_multi) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                    }
    
                    # Skip possible hole
                    while ($max_d + $DAYAGG < $tstamp) { $max_d += $DAYAGG; }
                    $num_d = 0;
                }
            }
    
            if ($tstamp > $max_w)
            {
                if ($tstamp <= $max_w + $WEEKAGG)
                {
                    $num_w++;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $avg_w[$j] += $result->getvalue($i, $j + 1);
                    }
                }
    
                if ($tstamp >= $max_w + $WEEKAGG)
                {
                    $max_w += $WEEKAGG;
                    if ($num_w > 0)
                    {
                        $q = "insert into $table" . "_w values (" . $max_w . ", '";
                        $q .= $mresult->getvalue($mult, 0) . "'";
                        foreach my $j (0 .. $flds - 1)
                        {
                            $q .= ", " . (($fields->getvalue($j+2, 1) eq "i") ?
                                         int($avg_w[$j]/$num_w) : $avg_w[$j]/$num_w);
                            $avg_w[$j] = 0.0;
                        }
                        $q .= ")";
                        logdie "(do_agg_multi) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                    }
    
                    # Skip possible hole
                    while ($max_w + $WEEKAGG < $tstamp) { $max_w += $WEEKAGG; }
                    $num_w = 0;
                }
            }
    
            if ($tstamp > $max_m)
            {
                if ($tstamp <= $max_m + $MONAGG)
                {
                    $num_m++;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $avg_m[$j] += $result->getvalue($i, $j + 1);
                    }
                }
    
                if ($tstamp >= $max_m + $MONAGG)
                {
                    $max_m += $MONAGG;
                    if ($num_m > 0)
                    {
                        $q = "insert into $table" . "_m values (" . $max_m . ", '";
                        $q .= $mresult->getvalue($mult, 0) . "'";
                        foreach my $j (0 .. $flds - 1)
                        {
                            $q .= ", " . (($fields->getvalue($j+2, 1) eq "i") ?
                                         int($avg_m[$j]/$num_m) : $avg_m[$j]/$num_m);
                            $avg_m[$j] = 0.0;
                        }
                        $q .= ")";
                        logdie "(do_agg_multi) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                    }
    
                    # Skip possible hole
                    while ($max_m + $MONAGG < $tstamp) { $max_m += $MONAGG; }
                    $num_m = 0;
                }
            }
    
            if ($tstamp > $max_y)
            {
                if ($tstamp <= $max_y + $YEARAGG)
                {
                    $num_y++;
                    foreach my $j (0 .. $flds - 1)
                    {
                        $avg_y[$j] += $result->getvalue($i, $j + 1);
                    }
                }
    
                if ($tstamp >= $max_y + $YEARAGG)
                {
                    $max_y += $YEARAGG;
                    if ($num_y > 0)
                    {
                        $q = "insert into $table" . "_y values (" . $max_y . ", '";
                        $q .= $mresult->getvalue($mult, 0) . "'";
                        foreach my $j (0 .. $flds - 1)
                        {
                            $q .= ", " . (($fields->getvalue($j+2, 1) eq "i") ?
                                         int($avg_y[$j]/$num_y) : $avg_y[$j]/$num_y);
                            $avg_y[$j] = 0.0;
                        }
                        $q .= ")";
                        logdie "(do_agg_multi) Stopping\n" unless $r = doq($conn, $q, PGRES_COMMAND_OK);
                    }
    
                    # Skip possible hole
                    while ($max_y + $YEARAGG < $tstamp) { $max_y += $YEARAGG; }
                    $num_y = 0;
                }
            }
        }
    }
    return ($max_d, $max_w, $max_m, $max_y);
}

sub agg_fields
{
    my ($table, $mult, $max_h, $max_d, $max_w, $max_m, $max_y) = @_;
    my (@new_max_tstamps, $fields);

    $fields = $tblfldhash{$table};
    if ($mult eq "s")
    {
        @new_max_tstamps = do_agg_single($table, $max_h, $max_d, $max_w, $max_m, $max_y, $fields);
    }
    else
    {
        @new_max_tstamps = do_agg_multi($table, $max_h, $max_d, $max_w, $max_m, $max_y, $fields);
    }
    return @new_max_tstamps;
}

sub agg()
{
    my ($n_max_d, $n_max_w, $n_max_m, $n_max_y);
    my ($max_h, $max_d, $max_w, $max_m, $max_y);
    my ($new_max_w, $new_max_m, $new_max_y);
    my ($q, $result, $res);

    $q = "select max_h, max_d, max_sar from tstamps";
    logdie "(agg) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    if ($result->getvalue(0, 0) == 0 && $result->getvalue(0, 2) == 0)
    {
        logmsg "No data in database yet\n";
        return;
    }

    if ((!$loading) && ($result->getvalue(0, 1) != 0) && ($result->getvalue(0, 1) < time - 60 * 60 * 24))
    {
        # More than one day no data gathered - adjust tstamps
        my $max_h = time;
        my $max_d = ($max_h / $DAYAGG) * $DAYAGG;
        my $max_w = ($max_h / $WEEKAGG) * $WEEKAGG;
        my $max_m = ($max_h / $MONAGG) * $MONAGG;
        my $max_y = ($max_h / $YEARAGG) * $YEARAGG;

        my $q = "update tstamps set max_h=$max_h, max_d=$max_d, max_w=$max_w, " .
                "max_m=$max_m, max_y=$max_y, max_sar=$max_h";

        logmsg "More than one day no data gathered - adjusting timestamps\n";
        logdie "(agg) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);

        $q = "select max_h, max_d, max_sar from tstamps";
        logdie "(agg) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    }

    if($result->getvalue(0, 1) == 0)
    {
        my ($max_h);

        # First aggregation ever

        # This test is mainly for the case where the -l option had been used
        if ($loading)
        {
            $max_h = $result->getvalue(0, 2);
        } else
        {
            $max_h = $result->getvalue(0, 0);
        }

        $q = "select min(tstamp) from sysload";
        $result = $conn->exec($q);
        $m = $result->getvalue(0, 0);
        $m = 0 if $m eq "";
        $q = "select min(tstamp) from sar_cpu";
        $result = $conn->exec($q);
        if ($result->ntuples > 0)
        {
            $m2 = $result->getvalue(0, 0);
            $m2 = 0 if $m2 eq "";
            if ($m2 > $m) { $m = $m2; }
        }
        $max_d = ($m / $DAYAGG) * $DAYAGG;
        $max_w = ($m / $WEEKAGG) * $WEEKAGG;
        $max_m = ($m / $MONAGG) * $MONAGG;
        $max_y = ($m / $YEARAGG) * $YEARAGG;
        $q = "update tstamps set max_h=" . $max_h . ", max_d=" . $max_d . ", max_w=" . $max_w .
             ", max_m=" . $max_m . ", max_y=" . $max_y . ", first_entry=" . $m;
        logdie "(agg) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    }

    $q = "select max_h, max_d, max_w, max_m, max_y, max_sar from tstamps";
    logdie "(agg) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);

    # If loading, use as max value max_sar
    $max_h = $loading ? $result->getvalue(0, 5) : $result->getvalue(0, 0);
    $new_max_d = $max_d = $result->getvalue(0, 1);
    $new_max_w = $max_w = $result->getvalue(0, 2);
    $new_max_m = $max_m = $result->getvalue(0, 3);
    $new_max_y = $max_y = $result->getvalue(0, 4);

    logdie "(agg) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);

    foreach $tbl (0 .. $tables->ntuples - 1)
    {
        ($n_max_d, $n_max_w, $n_max_m, $n_max_y) = agg_fields($tables->getvalue($tbl, 0),
                                                              $tables->getvalue($tbl, 1),
                                                              $max_h, $max_d, $max_w, $max_m, $max_y);
        $new_max_d = $n_max_d if $n_max_d > $new_max_d;
        $new_max_w = $n_max_w if $n_max_w > $new_max_w;
        $new_max_m = $n_max_m if $n_max_m > $new_max_m;
        $new_max_y = $n_max_y if $n_max_y > $new_max_y;
    }

    $q = "update tstamps set max_d = " . $new_max_d . ", max_w = " . $new_max_w . 
                          ", max_m = " . $new_max_m . ", max_y = " . $new_max_y;
    logdie "(agg) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    logdie "(agg) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}

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

sub check_mult($$)
{
    my ($mult, $all_mults) = @_;
    my $i;

    foreach $i (0 .. $all_mults->ntuples - 1)
    {
        return 1 if ($all_mults->getvalue($i, 0) eq $mult);
    }
    return 0;
}

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

sub read_single_cum
{
    my $table = shift @_;
    my $tstamp = shift @_;
    my @parts = @_;
    my ($lst, $q, $q2, $result);

    # Truncate the cumulative value to 9 digits, otherwise might overflow int
    foreach my $i (0 .. scalar(@parts) - 1)
    {
        $parts[$i] = substr($parts[$i], -9);
    }

    # Read previous values
    $q = "select * from " . $table . "_last";
    logdie "(read_single_cum) Stopping\n" unless $last = doq($conn, $q, PGRES_TUPLES_OK);
    if ($last->ntuples == 0)
    {
        # First time ever
        $q = "insert into " . $table . "_last values (" . $tstamp;
        foreach $p (@parts)
        {
            $q .= ", " . $p;
        }
        $q .= ")";
        logdie "(read_single_cum) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    } else
    {
        my $restart = 0;
        my $restarted = "";

        foreach my $i (0 .. scalar(@parts) - 1)
        {
            if ($parts[$i] < $last->getvalue(0, $i + 1))
            {
                $restart = 1;
                $restarted .= "\n        Field " . $last->fname($i + 1) . ": prev=" .
                              $last->getvalue(0, $i + 1) . ", curr=" . $parts[$i];
            }
        }
        if ($restart == 0 &&
            $tstamp - $last->getvalue(0, 0) <= 90)   # otherwise: restarted or missed?
        {
            # Values ok, insert in database
            $q = "insert into " . $table . " values (" . $tstamp;
            $lst = 1;
            foreach my $p (@parts)
            {
                $q .= ", " . ($p - $last->getvalue(0, $lst++));
            }
            $q .= ")";
         
            logdie "(read_single_cum) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
        } else
        {
            if ($restart == 1)
            {
                logmsg("New value smaller than last one for $table:" .
                        $restarted . "\nSystem restarted?\n");
            }
            if ($tstamp - $last->getvalue(0, 0) > 90)
            {
                logmsg("Timegap between two measurements (" . ($tstamp - $last->getvalue(0, 0)) .
                       "); measurement missed for $table\n");
            }
        }

        # Update _last table. It is easier to delete, then insert first
        $q2 = "delete from " . $table . "_last";
        logdie "(read_single_cum) Stopping\n" unless $result = doq($conn, $q2, PGRES_COMMAND_OK);

        $q = "insert into " . $table . "_last values (" . $tstamp;
        foreach my $p (@parts)
        {
            $q .= ", " . $p;
        }
        $q .= ")";

        logdie "(read_single_cum) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    }
}

sub read_mult_cum
{
    my $table = shift @_;
    my $mult_name = shift @_;
    my $mult = shift @_;
    my $tstamp = shift @_;
    my @parts = @_;
    my ($lst, $q, $q2, $result);

    # Truncate the cumulative value to 9 digits, otherwise might overflow int
    foreach my $i (0 .. scalar(@parts) - 1)
    {
        $parts[$i] = substr($parts[$i], -9);
    }

    # Read previous values
    $q = "select * from " . $table . "_last where " . $mult_name . " = '" . $mult . "'";
    logdie "(read_mult_cum) Stopping\n" unless $last = doq($conn, $q, PGRES_TUPLES_OK);
    if ($last->ntuples == 0)
    {
        # New device
        $q = "insert into " . $table . "_last values (" . $tstamp . ", '" . $mult . "'";
        foreach my $p (@parts)
        {
            $q .= ", " . $p;
        }
        $q .= ")";
        logdie "(read_mult_cum) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    } else
    {
        my $restart = 0;
        my $restarted = "";

        foreach my $i (0 .. scalar(@parts) - 1)
        {
            if ($parts[$i] < $last->getvalue(0, $i + 2))
            {
                $restart = 1;
                $restarted .= "\n        Field " . $last->fname($i + 2) . ": prev=" .
                              $last->getvalue(0, $i + 2) . ", curr=" . $parts[$i];
            }
        }
        if ($restart == 0 &&
            $tstamp - $last->getvalue(0, 0) <= 90)   # otherwise: restarted or missed?
        {
            # Values ok, insert in database
            $q = "insert into " . $table . " values (" . $tstamp . ", '" . $mult . "'";
            $lst = 2;
            foreach my $p (@parts)
            {
                $q .= ", " . ($p - $last->getvalue(0, $lst++));
            }
            $q .= ")";
         
            logdie "(read_mult_cum) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
        } else
        {
            if ($restart == 1)
            {
                logmsg("New value smaller than last one for $table, $mult:" .
                        $restarted . "\nSystem restarted?\n");
            }
            if ($tstamp - $last->getvalue(0, 0) > 90)
            {
                logmsg("Timegap between two measurements (" . ($tstamp - $last->getvalue(0, 0)) .
                       "); measurement missed for $table, $mult\n");
            }
        }

        # Update _last table. It is easier to delete, then insert
        $q2 = "delete from " . $table . "_last where " . $mult_name . " = '" . $mult . "'";
        logdie "(read_mult_cum) Stopping\n" unless $result = doq($conn, $q2, PGRES_COMMAND_OK);

        $q = "insert into " . $table . "_last values (" . $tstamp . ", '" . $mult . "'";
        foreach my $p (@parts)
        {
            $q .= ", " . $p;
        }
        $q .= ")";

        logdie "(read_mult_cum) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    }
}

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

sub loadline
{
    my $tbl = shift @_;
    my $mult = shift @_;
    my $tstamp = shift @_;
    my @parts = @_;
    my ($q, $result);

    shift @parts if $parts[0] =~ /\s+/ || $parts[0] eq ""; # get rid of spaces

    if ($mult eq "s")
    {
        $q = "insert into " . $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
        logdie "(loadline) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    }
    else
    {
        my ($all_mult);

        logdie "(loadline) Stopping\n" unless $all_mult = doq($conn, "select * from " .
                                                $tbl . "_mult", PGRES_TUPLES_OK);
        if (check_mult($parts[0], $all_mult))
        {
            $parts[0] = '\'' . $parts[0] . '\'';
            $q = "insert into ". $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
            logdie "(loadline) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
        }
    }
}

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

sub gettstamp
{
    my ($dt, $up, $ld1, $ld2, $ld3, @ld);
    my ($year, $mon, $mday, $hour, $min, $tstamp);

    $dt = <INP>;
    if (! defined($dt))
    {
        logmsg "While reading timestamp: No valid input?\n";
        return 0;
    }

    chomp($dt);
    ($year, $mon, $mday, $hour, $min) = split(" ", $dt);

    # Sanity check
    if (! ($year >= 1970 && $year <= 2036 && $mon >= 1 && $mon <= 12 &&
              $mday >= 1 && $mday <= 31 && $hour >= 0 && $hour <= 23 &&
              $min >= 0 && $min <= 59) )
    {
        logmsg "While reading timestamp: No valid input?\n";
        return 0;
    }
    $tstamp = timegm(0, $min, $hour, $mday, $mon - 1, $year);

    return $tstamp;
}

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

sub nt4
{
    my $tstamp = shift @_;
    my ($line, @tmp, @flds, $q, $result, $fld, $mult_log, $mult_phys, $skip);

    # which devices to measure
    logdie "(nt4) Stopping\n" unless $mult_phys = doq($conn,
                  "select * from NTphysdisk_mult", PGRES_TUPLES_OK);
    logdie "(nt4) Stopping\n" unless $mult_log = doq($conn,
                  "select * from NTlogdisk_mult", PGRES_TUPLES_OK);

    logdie "(nt4) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    $line = <INP>;
    chomp($line);
    while ($line ne "-_-_-")
    {
        $skip = 0;
        @flds = split(/\s+/, $line);
        $fld = shift @flds;

        if ($fld eq "CPUload:")
        {
            $q = "insert into NTsysload values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "CPUstates:")
        {
            $q = "insert into NTcpustates values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "Memory:")
        {
            foreach my $f (@flds) { $f = int($f); }
            foreach my $i (0, 1, 2, 5, 6) { $flds[$i] /= 1024; }
            $q = "insert into NTmemory values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "Syscalls:")
        {
            $q = "insert into NTsyscalls values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "Fileops:")
        {
            $q = "insert into NTfileops values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "Processes:")
        {
            $q = "insert into NTprocs values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "Cache:")
        {
            foreach my $f (@flds) { $f = int($f); }
            foreach my $i (1, 3, 5, 7) { $flds[$i] = 0 if $flds[$i] < 0; }
            $q = "insert into NTcache values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "Paging:")
        {
            $q = "insert into NTpaging values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "RedirRW:")
        {
            $q = "insert into NTredirRW values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "RedirSessions:")
        {
            read_single_cum('NTredirSess', $tstamp, @flds);
            next;
        }

        if ($fld eq "ServerRW:")
        {
            $q = "insert into NTserverRW values (" . $tstamp . ", " . join(", ", @flds) . ")";
            next;
        }

        if ($fld eq "ServerSessions:")
        {
            read_single_cum('NTserverSess', $tstamp, @flds);
            next;
        }

        if ($fld eq "PhysDisk:")
        {
            if (check_mult($flds[0], $mult_phys))
            {
                $q = "insert into NTphysdisk values (" . $tstamp . ", '" . $flds[0];
                shift @flds;
                $flds[0] = 100 if $flds[0] > 100;
                $flds[2] *= 1000;
                $q .= "', " . join(", ", @flds) . ")";
            }
            else
            {
                $skip = 1;
            }
            next;
        }

        if ($fld eq "LogDisk:")
        {
            if (check_mult($flds[0], $mult_log))
            {
                $q = "insert into NTlogdisk values (" . $tstamp . ", '" . $flds[0];
                shift @flds;
                $flds[0] = 100 if $flds[0] > 100;
                $flds[2] *= 1000;
                $q .= "', " . join(", ", @flds) . ")";
            }
            else
            {
                $skip = 1;
            }
            next;
        }
    }
    continue
    {
        if ($skip == 0)
        {
            logdie "(nt4) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
        }
        $line = <INP>;
        chomp($line);
    }

    logdie "(nt4) Stopping\n" unless $result = doq($conn, "select max_h from tstamps", PGRES_TUPLES_OK);
    if ($tstamp > $result->getvalue(0, 0))
    {
        $q = "update tstamps set max_h = " . $tstamp;
        logdie "(nt4) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    }
    logdie "(nt4) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}

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

sub uptime
{
    my $tstamp = shift @_;
    my ($up, $ld1, $ld2, $ld3, @ld, $q, $result);

    $up = <INP>;
    chomp($up);
    @ld = split(/\s+/, $up);

    # Find keyword user or users; number before this one is important
    foreach my $i (0 .. scalar(@ld) - 1)
    {
        if ($ld[$i] =~ /user/)
        {
            $users = $ld[$i - 1];
        }
    }
    # Now the last 3 numbers:
    $ld1 = @ld[scalar(@ld) - 3];
    $ld2 = @ld[scalar(@ld) - 2];
    $ld3 = @ld[scalar(@ld) - 1];

    logdie "(sysload) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    $q = "insert into sysload values (" . $tstamp . ", " . $users .  ", " . $ld1 . $ld2 . $ld3 . ")";
    logdie "(sysload) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    logdie "(sysload) Stopping\n" unless $result = doq($conn, "select max_h from tstamps", PGRES_TUPLES_OK);
    if ($tstamp > $result->getvalue(0, 0))
    {
        $q = "update tstamps set max_h = " . $tstamp;
        logdie "(sysload) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
    }
    logdie "(sysload) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);

    # Skip next line (should be -_-_-)
    <INP>;
}

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

# Netstat for solaris and hpux
sub netstat_su($$)
{
    my $tbl = shift @_;
    my $tstamp = shift @_;
    my ($last, $mult, $line, @parts, $dev);

    # which devices to measure
    logdie "(netstat_su) Stopping\n" unless $mult = doq($conn, "select * from " . $tbl .
                                                        "_mult", PGRES_TUPLES_OK);

    # Skip header
    <INP>;
    $line = <INP>;
    while (defined($line) && $line !~ /-_-_-/)
    {
     	chomp($line);

	if (not $line)
	{
            $line = <INP>;
            next;
	}

        @parts = split(/\s+/, $line);
	if (grep(/:/, $parts[2]))
	{
            # IPv6, forget it for now
            $line = <INP>;
            next;
	}

        $dev = shift @parts;

        # Drop optional *
        if (substr($dev, -1) eq '*')
        {
            $dev = substr($dev, 0, -1);
        }

        if (check_mult($dev, $mult))
        {
            shift @parts; shift @parts; shift @parts;
            @parts = ($parts[0], 0, $parts[1], 0, 0) if scalar(@parts) == 2;
            read_mult_cum($tbl, "iface", $dev, $tstamp, @parts);
        }
        $line = <INP>;
    }
}

# Netstat for aix
sub netstat_aix($$)
{
    my $tbl = shift @_;
    my $tstamp = shift @_;
    my ($last, $mult, $line, @parts, $dev);

    # which devices to measure
    logdie "(netstat_aix) Stopping\n" unless $mult = doq($conn, "select * from " . $tbl .
                                                         "_mult", PGRES_TUPLES_OK);

    # Skip header
    <INP>;
    $line = <INP>;
    while (defined($line) && $line !~ /-_-_-/)
    {
        # Skip lines with <Link> in them - they are merely links to 'real' devices
        if ($line !~ /Link/)
        {
            chomp($line);
            @parts = split(/\s+/, $line);
            $dev = shift @parts;
 
            # Drop optional *
            if (substr($dev, -1) eq '*')
            {
                $dev = substr($dev, 0, -1);
            }

            if (check_mult($dev, $mult))
            {
                shift @parts; shift @parts; shift @parts;

                read_mult_cum($tbl, "iface", $dev, $tstamp, @parts);
            }
        }
        $line = <INP>;
    }
}

sub netstat
{
    my $tstamp = shift @_;
    my $result;

    logdie "(netstat) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    netstat_su("netstat", $tstamp) if $systype eq "solaris";
    netstat_su("netstatux", $tstamp) if $systype eq "hpux";
    netstat_aix("netstataix", $tstamp) if $systype eq "aix";
    logdie "(netstat) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}

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

# iostat for aix
sub iostat_aix($)
{
    my $tstamp = shift @_;
    my ($last, $mult, $line, @parts, $dev);

    # which devices to measure
    logdie "(iostat_aix) Stopping\n" unless $mult = doq($conn, "select * from iostat_mult", PGRES_TUPLES_OK);

    # Skip header until 2nd disks
    do
    {
        $line = <INP>;
    } until (!defined($line) || $line =~ /-_-_-/ || $line =~ /^Disks:/ ||
             $line =~ /Disk history since boot not available/);

    do
    {
        $line = <INP>;
    } until (!defined($line) || $line =~ /-_-_-/ || $line =~ /Disks/);

    if (! defined($line) || $line !~ /Disks/)
    {
        logmsg "(iostat_aix) No valid input for iostat?\n";
        return;
    }

    $line = <INP>;

    while (defined($line) && $line !~ /-_-_-/)
    {
        chomp($line);
        @parts = split(/\s+/, $line);
        $dev = $parts[0];
        if (check_mult($dev, $mult))
        {
            loadline("iostat", "m", $tstamp, @parts);
        }
        $line = <INP>;
    }
}

sub iostat
{
    my $tstamp = shift @_;
    my $result;

    logdie "(iostat) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    iostat_aix($tstamp) if $systype eq "aix";
    logdie "(iostat) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}

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

# vmstat hpux
sub vmstat_hpux($)
{
    my $tstamp = shift @_;
    my ($line, @parts);

    # Skip header until 2nd line in vmstat (= 4th line in the file)
    $line = <INP>;
    $line = <INP>;
    $line = <INP>;
    $line = <INP>;

    if (defined ($line))
    {
        @parts = split(/\s+/, $line);
        shift @parts if $parts[0] =~ /\s+/ || $parts[0] eq ""; # get rid of spaces
        if (scalar(@parts) != 18)
        {
            logmsg "(vmstat_hpux) No valid input for vmstat?\n";
            return;
        }
        @parts=($parts[3], $parts[4], $parts[5], $parts[6], $parts[7], $parts[8],
                $parts[9], $parts[10], $parts[11]);
        loadline("vmstatux", "s", $tstamp, @parts);
    }
    else
    {
        logmsg "(vmstat_hpux) No valid input for vmstat?\n";
        return;
    }
}

# vmstat aix
sub vmstat_aix($)
{
    my $tstamp = shift @_;
    my ($line, @parts);

    # Skip header until 2nd line in vmstat (= 5th line in the file)
    $line = <INP>;
    $line = <INP>;
    $line = <INP>;
    $line = <INP>;
    $line = <INP>;

    if (defined ($line))
    {
        @parts = split(/\s+/, $line);
        shift @parts if $parts[0] =~ /\s+/ || $parts[0] eq ""; # get rid of spaces
        if (scalar(@parts) != 17)
        {
            logmsg "(vmstat_aix) No valid input for vmstat?\n";
            return;
        }
        @parts=($parts[2], $parts[3], $parts[4], $parts[5], $parts[6], $parts[7],
                $parts[8], $parts[9]);
        loadline("vmstataix", "s", $tstamp, @parts);
    }
    else
    {
        logmsg "(vmstat_aix) No valid input for vmstat?\n";
        return;
    }
}

sub vmstat
{
    my $tstamp = shift @_;
    my $result;

    logdie "(vmstat) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    vmstat_hpux($tstamp) if $systype eq "hpux";
    vmstat_aix($tstamp) if $systype eq "aix";
    logdie "(vmstat) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}

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

# usertbl
sub usertbl($)
{
    my $tstamp = shift @_;
    my ($line, @parts, @nums);

    foreach my $i (0 .. 15) { $nums[$i] = 0; }
    chomp($line = <INP>);
    if (defined ($line))
    {
        @parts = split(/\s+/, $line);
        shift @parts if $parts[0] =~ /\s+/ || $parts[0] eq "";
        my $cnt = 0;
        foreach my $part (@parts)
        {
            if ($part =~ /\d+/)
            {
                $nums[$cnt++] = $part if $part =~ /\d+/;
            }
            last if $cnt == 16;
        }
        loadline("usertbl", "s", $tstamp, @nums);
    }
    else
    {
        logmsg "(usertbl) No valid input for user table?\n";
        return;
    }
}

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

sub proc_linux2_0
{
    my $tstamp = shift @_;
    my ($dt, $mult, $last, $line, $dev, $q, $q2, $dsk1, $dsk2, $dsk3, $dsk4, $dsk5);

    # which devices to measure
    logdie "(proc_linux2_0) Stopping\n" unless $mult = doq($conn, "select * from proc_net_mult", PGRES_TUPLES_OK);

    <INP>;
    <INP>;
    $line = <INP>;

    # Next lines until -_-_- is for /proc/dev
    while (defined($line) && $line !~ /-_-_-/ )
    {
        chomp($line);
        ($dev, $line) = split(/:/, $line);
        $dev =~ s/ //g;
        if (check_mult($dev, $mult))
        {
            @parts = split(" ", $line);
            read_mult_cum("proc_net", "iface", $dev, $tstamp, @parts);
        }
        $line = <INP>;
    }

    # which devices to measure
    logdie "(proc_linux2_0) Stopping\n" unless $mult = doq($conn, "select * from proc_disk_mult", PGRES_TUPLES_OK);

    $line = <INP>;
    # Next lines until -_-_- is for /proc/stat
    while (defined($line) && $line !~ /-_-_-/)
    {
        chomp($line);
        @parts = split(" ", $line);
        if ($parts[0] eq "cpu")
        {
            shift @parts;
            $parts[0] = int ($parts[0] / 60);
            $parts[1] = int ($parts[1] / 60);
            $parts[2] = int ($parts[2] / 60);
            $parts[3] = int ($parts[3] / 60);
            read_single_cum("proc_cpu", $tstamp, @parts);
        }

        if ($parts[0] eq "disk")
        {
            shift @parts;
            @dsk1 = @parts;
        }

        if ($parts[0] eq "disk_rio")
        {
            shift @parts;
            @dsk2 = @parts;
        }

        if ($parts[0] eq "disk_wio")
        {
            shift @parts;
            @dsk3 = @parts;
        }

        if ($parts[0] eq "disk_rblk")
        {
            shift @parts;
            @dsk4 = @parts;
        }

        if ($parts[0] eq "disk_wblk")
        {
            shift @parts;
            @dsk5 = @parts;

            read_mult_cum("proc_disk", "disk", "hda", $tstamp, $dsk1[0], $dsk2[0], $dsk3[0], $dsk4[0], $dsk5[0])
                if (check_mult("hda", $mult));
            read_mult_cum("proc_disk", "disk", "hdb", $tstamp, $dsk1[1], $dsk2[1], $dsk3[1], $dsk4[1], $dsk5[1])
                if (check_mult("hdb", $mult));
            read_mult_cum("proc_disk", "disk", "hdc", $tstamp, $dsk1[2], $dsk2[2], $dsk3[2], $dsk4[2], $dsk5[2])
                if (check_mult("hdc", $mult));
            read_mult_cum("proc_disk", "disk", "hdd", $tstamp, $dsk1[3], $dsk2[3], $dsk3[3], $dsk4[3], $dsk5[3])
                if (check_mult("hdd", $mult));
        }

        if ($parts[0] eq "intr")
        {
            shift @parts;
            read_single_cum("proc_intr", $tstamp, @parts);
        }
        $line = <INP>;
    }
}

sub proc_linux2_2
{
    my $tstamp = shift @_;
    my ($dt, $mult, $last, $line, $dev, $q, $q2, $dsk1, $dsk2, $dsk3, $dsk4, $dsk5);
    my ($memtotal, $memfree, $memshared, $buffers, $cached, $swaptotal, $swapfree);
    my (@parts, @nums);

    # which devices to measure
    logdie "(proc_linux2_2) Stopping\n" unless $mult = doq($conn, "select * from proc_net2_mult", PGRES_TUPLES_OK);

    <INP>;
    <INP>;
    $line = <INP>;

    # Next lines until -_-_- is for /proc/net/dev
    while (defined($line) && $line !~ /-_-_-/ )
    {
        chomp($line);
        ($dev, $line) = split(/:/, $line);
        $dev =~ s/ //g;
        if (check_mult($dev, $mult))
        {
            @parts = split(/\s+/, $line);
            shift @parts if $parts[0] =~ /\s+/ || $parts[0] eq "";
            read_mult_cum("proc_net2", "iface", $dev, $tstamp, @parts);
        }
        $line = <INP>;
    }

    # which devices to measure
    logdie "(proc_linux2_2) Stopping\n" unless $mult = doq($conn, "select * from proc_disk_mult", PGRES_TUPLES_OK);

    $line = <INP>;
    # Next lines until -_-_- is for /proc/stat
    while (defined($line) && $line !~ /-_-_-/)
    {
        chomp($line);
        @parts = split(" ", $line);
        if ($parts[0] eq "cpu")
        {
            shift @parts;
            $parts[0] = int ($parts[0] / 60);
            $parts[1] = int ($parts[1] / 60);
            $parts[2] = int ($parts[2] / 60);
            $parts[3] = int ($parts[3] / 60);
            read_single_cum("proc_cpu", $tstamp, @parts);
        }

        if ($parts[0] eq "disk")
        {
            shift @parts;
            @dsk1 = @parts;
        }

        if ($parts[0] eq "disk_rio")
        {
            shift @parts;
            @dsk2 = @parts;
        }

        if ($parts[0] eq "disk_wio")
        {
            shift @parts;
            @dsk3 = @parts;
        }

        if ($parts[0] eq "disk_rblk")
        {
            shift @parts;
            @dsk4 = @parts;
        }

        if ($parts[0] eq "disk_wblk")
        {
            shift @parts;
            @dsk5 = @parts;

            read_mult_cum("proc_disk", "disk", "hda", $tstamp, $dsk1[0], $dsk2[0], $dsk3[0], $dsk4[0], $dsk5[0])
                if (check_mult("hda", $mult));
            read_mult_cum("proc_disk", "disk", "hdb", $tstamp, $dsk1[1], $dsk2[1], $dsk3[1], $dsk4[1], $dsk5[1])
                if (check_mult("hdb", $mult));
            read_mult_cum("proc_disk", "disk", "hdc", $tstamp, $dsk1[2], $dsk2[2], $dsk3[2], $dsk4[2], $dsk5[2])
                if (check_mult("hdc", $mult));
            read_mult_cum("proc_disk", "disk", "hdd", $tstamp, $dsk1[3], $dsk2[3], $dsk3[3], $dsk4[3], $dsk5[3])
                if (check_mult("hdd", $mult));
        }

        if ($parts[0] eq "intr")
        {
            shift @parts;
            @parts = ($parts[ 0], $parts[ 1], $parts[ 2], $parts[ 3],
                      $parts[ 4], $parts[ 5], $parts[ 6], $parts[ 7],
                      $parts[ 8], $parts[ 9], $parts[10], $parts[11],
                      $parts[12], $parts[13], $parts[14], $parts[15],
                      $parts[16]);
            read_single_cum("proc_intr", $tstamp, @parts);
        }
        $line = <INP>;
    }

    $line = <INP>;
    # Next lines until -_-_- is for /proc/meminfo
    while (defined($line) && $line !~ /-_-_-/)
    {
        chomp($line);
        @parts = split(/\s+/, $line);
        $memtotal  = $parts[1] if $parts[0] eq "MemTotal:";
        $memfree   = $parts[1] if $parts[0] eq "MemFree:";
        $memshared = $parts[1] if $parts[0] eq "MemShared:";
        $buffers   = $parts[1] if $parts[0] eq "Buffers:";
        $cached    = $parts[1] if $parts[0] eq "Cached:";
        $swaptotal = $parts[1] if $parts[0] eq "SwapTotal:";
        $swapfree  = $parts[1] if $parts[0] eq "SwapFree:";
        $line = <INP>;
    }
    loadline("proc_meminfo", "s", $tstamp, ($memtotal, $memfree, $memshared, $buffers, $cached,
                                            $swaptotal, $swapfree));

    # Next lines until -_-_- is for /proc/sys/fs/...
    undef @parts;
    chomp ($line = <INP>); $parts[0] = $line; # file-max
    chomp ($line = <INP>); @nums = split (/\s+/, $line);
    $parts[1] = $nums[0]; # file-nr1;
    $parts[2] = $nums[1]; # file-nr2;
    $parts[3] = $nums[2]; # file-nr3;
    chomp ($line = <INP>); $parts[4] = $line; # inode-max
    chomp ($line = <INP>); @nums = split (/\s+/, $line);
    $parts[5] = $nums[0]; # inode-nr1;
    $parts[6] = $nums[1]; # inode-nr2;
    loadline("proc_size", "s", $tstamp, @parts);

    <INP>; # read -_-_-
}

sub proc
{
    my $tstamp = shift @_;
    my $result;

    logdie "(proc) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    proc_linux2_0($tstamp) if $systype eq "linux2_0";
    proc_linux2_2($tstamp) if $systype eq "linux2_2";
    logdie "(proc) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}

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


sub readdisk($$$$$)
{
    my ($tbl, $mday, $mon, $year, $lasttstamp) = @_;
    my ($i, @parts, $tstamp, $q, @tm, $result, $skipping, $mult, $all_mult);

    # which devices to measure
    logdie "(readdisk) Stopping\n"
        unless $all_mult = doq($conn, "select * from ${tbl}_mult", PGRES_TUPLES_OK);

    do {
        $line = <INP>
    } while (defined($line) && $line !~ /device/);
    
    do {
        $line = <INP>;
    } while (defined($line) && $line !~ /\d\d:\d\d:\d\d\s+.*\s+\d+/ );

    $i = 0; $skipping = 0;
    do {
        if ($line =~ /\d\d:\d\d:\d\d\s+.*\s+\d+/)
        {
            #
            # First line of new time, there is a date
            #
            @parts = split (/\s+/, $line);
	    @tm = split (/:/, $parts[0]);
	    $tstamp = timegm(0, $tm[1], $tm[0], $mday, $mon, $year);
            if ($tstamp > $lasttstamp)
            {
                $skipping = 0;
                shift @parts;
                if (check_mult($parts[0], $all_mult))
                {
                    $parts[0] = '\'' . $parts[0] . '\'';
                    $q = "insert into ". $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
                    logdie "(readdisk) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
                    $i++;
                }
            } else
            {
                $skipping = 1;
            }
        }
        else 
        {
            #
            # Not first line, use timestamp of first line
            #
            if ($skipping == 0)
            {
                if ($line =~ /\s+.*\s+\d+/)
                {
                    @parts = split (/\s+/, $line);
                    shift @parts;
                    if (check_mult($parts[0], $all_mult))
                    {
                        $parts[0] = '\'' . $parts[0] . '\'';
                        $q = "insert into " . $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
                        logdie "(readdisk) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
                        $i++;
                    }
                }
            }
        }
        $line = <INP>;
    } while (defined($line) && $line !~ /^Average/ );
}

sub readq($$$$$)
{
    my ($tbl, $mday, $mon, $year, $lasttstamp) = @_;
    my ($i, @parts, @tm, $tstamp, $q, $result);

    $i = 0;
    do {
        if ($line !~ /restarts/ && $line !~ /change/ )
        {
            @parts = split (/\s+/, $line);
	    @tm = split (/:/, $parts[0]);
	    $tstamp = timegm(0, $tm[1], $tm[0], $mday, $mon, $year);
            if ($tstamp > $lasttstamp)
            {
                shift @parts;
                #
                # Problems - check for available fields in the $line:
                # 17:50:17 runq-sz %runocc swpq-sz %swpocc
                # 17:50:17        unix restarts
                # 17:52:01
                # 17:51:02     1.8       9                
                # 17:52:03                     1.5       3                
                # 17:52:04     1.8       9     1.5       3                
                #
                if (index ($line, ".") == -1 )
                {
                    @parts=(0, 0, 0, 0);
                } else
                {
                    if (rindex ($line, ".") < 20)
                    {
                        @parts=($parts[0], $parts[1], 0, 0);
                    } else
                    {
                        if (index($line, ".") > 20)
                        {
                            @parts=(0, 0, $parts[0], $parts[1]);
                        }
                    }
                }

                $q = "insert into " . $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
                logdie "(readq) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
                $i++;
            }
        }
        $line = <INP>;
    } while (defined($line) && $line !~ /^$/ );
}

################################################################################
# Skip until info
#
sub skip($)
{
    my $txt = shift @_;

    do {
        $line = <INP>;
    } while (defined($line) && $line !~ /$txt/);

    do {
        $line = <INP>;
    } while (defined($line) && $line !~ /\d\d:\d\d:\d\d\s+/ );
}

################################################################################
# Read a table
#
sub readtable($$$$$)
{
    my ($tbl, $mday, $mon, $year, $lasttstamp) = @_;
    my ($i, @parts, @tm, $tstamp, $q, $result);

    $i = 0;
    do {
        if ($line !~ /restarts/ && $line !~ /change/ )
        {
            @parts = split (/\s+|\//, $line);
	    @tm = split (/:/, $parts[0]);
	    $tstamp = timegm(0, $tm[1], $tm[0], $mday, $mon, $year);
            if ($tstamp > $lasttstamp)
            {
                shift @parts;
                if ($tbl eq "sar_mem") # numbers are too big - divide by 1024
                {
                    $parts[0] = int($parts[0] / 1024); 
                    $parts[1] = int($parts[1] / 1024);
                    $parts[3] = int($parts[3] / 1024);
                    $parts[4] = int($parts[4] / 1024);
                    $parts[6] = int($parts[6] / 1024);
                }
                $q = "insert into " . $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
                logdie "(readtable) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
                $i++;
            }
        }
        $line = <INP>;
    } while (defined($line) && $line !~ /^$/ );

    return $tstamp;
}

# HP has some N/A in its table size entries; needs special handing
sub readtable_sizehp($$$$$)
{
    my ($tbl, $mday, $mon, $year, $lasttstamp) = @_;
    my ($i, @parts, @tm, $tstamp, $q, $result);

    $i = 0;
    do {
        if ($line !~ /restarts/ && $line !~ /change/ )
        {
            @parts = split (/\s+|\//, $line);
	    @tm = split (/:/, $parts[0]);
	    $tstamp = timegm(0, $tm[1], $tm[0], $mday, $mon, $year);
            if ($tstamp > $lasttstamp)
            {
                shift @parts; shift @parts; # second N/A must translate into 1 0
                $parts[0] = "0";
                $parts[1] = "0";
                $parts[2] = "0";
                $q = "insert into " . $tbl . " values (" . join(", ", $tstamp, @parts) . ")";
                logdie "(readtable) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
                $i++;
            }
        }
        $line = <INP>;
    } while (defined($line) && $line !~ /^$/ );

    return $tstamp;
}


sub sar_Solaris($$$)
{
    my ($mday, $mon, $year) = @_;
    my($q, $result, $tstamp, $lasttstamp);

    $line = <INP>;
    ################################################################################
    # Skip until CPU info
    #
    if ($line !~ /-_-_-/)
    {
        do {
            $line = <INP>
        } while (defined($line) && $line !~ /usr/ && $line !~ /-_-_-/);
    }

    if ($line !~ /-_-_-/)
    {
        do {
            $line = <INP>;
        } while (defined($line) && $line !~ /\d\d:\d\d:\d\d\s+\d+/ && $line !~ /^$/ 
                 && $line !~ /-_-_-/);
    }

    if ($line =~ /^$/ || $line =~ /-_-_-/)
    {
        # Hmm, empty line. Most likely there is no SAR info; return.
        logmsg "No info in sar output?\n";
        return;
    }

    $q = "select max_sar from tstamps";
    logdie "(sar_Solaris) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    $lasttstamp = $result->getvalue(0, 0);

    $tstamp = readtable("sar_cpu", $mday, $mon, $year, $lasttstamp);

    $q = "update tstamps set max_sar = " . $tstamp;
    logdie "(sar_Solaris) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);

    readdisk("sar_disk", $mday, $mon, $year, $lasttstamp);
    skip("runq");	readq("sar_q", $mday, $mon, $year, $lasttstamp);
    skip("bread");	readtable("sar_rw", $mday, $mon, $year, $lasttstamp);
    skip("swpin");	readtable("sar_swp", $mday, $mon, $year, $lasttstamp);
    skip("scall");	readtable("sar_sys", $mday, $mon, $year, $lasttstamp);
    skip("iget");	readtable("sar_ino", $mday, $mon, $year, $lasttstamp);
    skip("rawch");	readtable("sar_io", $mday, $mon, $year, $lasttstamp);
    skip("proc");	readtable("sar_size", $mday, $mon, $year, $lasttstamp);
    skip("msg");	readtable("sar_ipc", $mday, $mon, $year, $lasttstamp);
    skip("atch");	readtable("sar_pgin", $mday, $mon, $year, $lasttstamp);
    skip("pgout");	readtable("sar_pgout", $mday, $mon, $year, $lasttstamp);
    skip("freemem");	readtable("sar_fmem", $mday, $mon, $year, $lasttstamp);
    skip("sml_mem");	readtable("sar_mem", $mday, $mon, $year, $lasttstamp);
}

sub sar_AIX($$$)
{
    my ($mday, $mon, $year) = @_;
    my($q, $result, $tstamp, $lasttstamp);

    $line = <INP>;
    ################################################################################
    # Skip until INODE info
    #
    if ($line !~ /-_-_-/)
    {
        do {
            $line = <INP>
        } while (defined($line) && $line !~ /iget/ && $line !~ /-_-_-/);
    }

    if ($line !~ /-_-_-/)
    {
        do {
            $line = <INP>;
        } while (defined($line) && $line !~ /\d\d:\d\d:\d\d\s+\d+/ && $line !~ /^$/ 
                 && $line !~ /-_-_-/);
    }

    if ($line =~ /^$/ || $line =~ /-_-_-/)
    {
        # Hmm, empty line. Most likely there is no SAR info; return.
        logmsg "No info in sar output?\n";
        return;
    }

    $q = "select max_sar from tstamps";
    logdie "(sar_AIX) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    $lasttstamp = $result->getvalue(0, 0);

    $tstamp = readtable("sar_inoaix", $mday, $mon, $year, $lasttstamp);

    $q = "update tstamps set max_sar = " . $tstamp;
    logdie "(sar_AIX) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);

    skip("bread");	readtable("sar_rw", $mday, $mon, $year, $lasttstamp);
    skip("scall");	readtable("sar_sys", $mday, $mon, $year, $lasttstamp);
    skip("ksched");	readtable("sar_kproc", $mday, $mon, $year, $lasttstamp);
    skip("msg");	readtable("sar_ipc", $mday, $mon, $year, $lasttstamp);
    skip("runq");	readtable("sar_q", $mday, $mon, $year, $lasttstamp);
    skip("slots");	readtable("sar_slots", $mday, $mon, $year, $lasttstamp);
    skip("usr");	readtable("sar_cpu", $mday, $mon, $year, $lasttstamp);
    skip("proc");	readtable("sar_sizeaix", $mday, $mon, $year, $lasttstamp);
    skip("cswch");	readtable("sar_csw", $mday, $mon, $year, $lasttstamp);
    skip("rawch");	readtable("sar_io", $mday, $mon, $year, $lasttstamp);
}

sub sar_HPUX($$$)
{
    my ($mday, $mon, $year) = @_;
    my($q, $result, $tstamp, $lasttstamp, $old_style);

    $line = <INP>;
    if ($line !~ /-_-_-/)
    {
        do {
            $line = <INP>;
        } while (defined($line) && $line !~ /HP-UX/ && $line !~ /^$/ 
                 && $line !~ /-_-_-/);
    }

    $line = <INP>;
    $old_style = 0;
    if ($line !~ /-_-_-/)
    {
        do {
            $old_style = 1 if $line =~ /device/;
            $line = <INP>;
        } while (defined($line) && $line !~ /\d\d:\d\d:\d\d\s+\d+/ && $line !~ /^$/ 
                 && $line !~ /-_-_-/);
    }

    if ($line =~ /^$/ || $line =~ /-_-_-/)
    {
        # Hmm, empty line. Most likely there is no SAR info; return.
        logmsg "No info in sar output?\n";
        return;
    }

    $q = "select max_sar from tstamps";
    logdie "(sar_HPUX) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    $lasttstamp = $result->getvalue(0, 0);
    if ($lasttstamp == 0) { $lasttstamp = 1; }
    $tstamp = 0;

    # What type of HP-UX have we got?

    if ($old_style)
    {
        # Old-style hp-ux
        # Skip to time not yet read
        while (defined($line) && $line !~ /^$/ && $tstamp <= $lasttstamp && $line !~ /-_-_-/)
        {
            @parts = split (/\s+|\//, $line);
	    @tm = split (/:/, $parts[0]);
	    $tstamp = timegm(0, $tm[1], $tm[0], $mday, $mon, $year);
            if ($tstamp <= $lasttstamp)
            {
                do
                {
                    $line = <INP>;
                } while (defined($line) && $line !~ /\d\d:\d\d:\d\d\s+\d+/ && $line !~ /^$/ 
                         && $line !~ /-_-_-/);
            }
        }

        if ($line =~ /^$/ || $line =~ /-_-_-/)
        {
            # Hmm, no new line. Most likely there is no SAR info; return.
            logmsg "No new info in sar output?\n";
            return;
        }

        # Read info
        while (defined($line) && $line =~ /\d\d:\d\d:\d\d\s+\d+/)
        {
            shift @parts;  # get rid of time
            loadline("sar_cpu", "s", $tstamp, @parts);
            $line = <INP>; @parts = split(/\s+|\//, $line);

            do
            {
                loadline("sar_diskux", "m", $tstamp, @parts);
                $line = <INP>; @parts = split(/\s+|\//, $line);
            } while (defined($line) && (scalar(@parts) == 8 || scalar(@parts) < 2));

            loadline("sar_q", "s", $tstamp, @parts);

            $line = <INP>; @parts = split(/\s+|\//, $line);
            loadline("sar_rw", "s", $tstamp, @parts);

            $line = <INP>; @parts = split(/\s+|\//, $line);
            loadline("sar_swp", "s", $tstamp, @parts);

            $line = <INP>; @parts = split(/\s+|\//, $line);
            loadline("sar_sys", "s", $tstamp, @parts);

            $line = <INP>; @parts = split(/\s+|\//, $line);
            loadline("sar_ino", "s", $tstamp, @parts);

            $line = <INP>; @parts = split(/\s+|\//, $line);
            loadline("sar_io", "s", $tstamp, @parts);

            # Make sure that N/A is xlated into 0/0
            $line = <INP>; @parts = split(/\s+/, $line);
            if ($parts[0] eq "N/A") { $parts[0] = "0/0"; }
            if ($parts[1] eq "N/A") { $parts[1] = "0"; }
            if ($parts[2] eq "N/A") { $parts[2] = "0/0"; }
            if ($parts[3] eq "N/A") { $parts[3] = "0"; }
            if ($parts[4] eq "N/A") { $parts[4] = "0/0"; }
            if ($parts[5] eq "N/A") { $parts[5] = "0"; }
            if ($parts[6] eq "N/A") { $parts[6] = "0/0"; }
            if ($parts[7] eq "N/A") { $parts[7] = "0"; }
            $line = join(" ", @parts);
            @parts = split(/\s+|\//, $line);
            loadline("sar_sizeux", "s", $tstamp, @parts);
            $line = <INP>; @parts = split(/\s+|\//, $line);

            loadline("sar_ipc", "s", $tstamp, @parts);

            $line = <INP>;
            if (defined($line) && $line =~ /\d\d:\d\d:\d\d\s+\d+/)
            {
                @parts = split (/\s+|\//, $line);
	        @tm = split (/:/, $parts[0]);
	        $tstamp = timegm(0, $tm[1], $tm[0], $mday, $mon, $year);
            }
        }
    }
    else
    {
        # New-style hp-ux - standard unix
        $tstamp = readtable("sar_cpu", $mday, $mon, $year, $lasttstamp);

        readdisk("sar_diskux", $mday, $mon, $year, $lasttstamp);
        skip("runq");	readtable("sar_q", $mday, $mon, $year, $lasttstamp);
        skip("bread");	readtable("sar_rw", $mday, $mon, $year, $lasttstamp);
        skip("swpin");	readtable("sar_swp", $mday, $mon, $year, $lasttstamp);
        skip("scall");	readtable("sar_sys", $mday, $mon, $year, $lasttstamp);
        skip("iget");	readtable("sar_ino", $mday, $mon, $year, $lasttstamp);
        skip("rawch");	readtable("sar_io", $mday, $mon, $year, $lasttstamp);
        skip("proc");	readtable_sizehp("sar_sizeux", $mday, $mon, $year, $lasttstamp);
        skip("msg");	readtable("sar_ipc", $mday, $mon, $year, $lasttstamp);
    }

    $q = "update tstamps set max_sar = " . $tstamp;
    logdie "(sar_HPUX) Stopping\n" unless $result = doq($conn, $q, PGRES_COMMAND_OK);
}

sub sar($)
{
    my ($cmd) = @_;
    my ($result, $year, $mon, $mday);

    ($year, $mon, $mday) = (split(/ /, $cmd))[1, 2, 3];
    if (!defined($year) || !defined($mon) || !defined($mday) ||
       $year !~ /\d+/ || $mon !~ /\d+/ || $mday !~ /\d+/)
    {
        logmsg("(sar) No or illegal date in sar; upgrade sysmanswd?\n");
        return;
    }
    $year += 1900 if $year < 1000;
    logdie "(sar) Stopping\n" unless $result = doq($conn, "begin transaction", PGRES_COMMAND_OK);
    sar_Solaris($mday, $mon, $year) if $systype eq "solaris";
    sar_AIX($mday, $mon, $year) if $systype eq "aix";
    sar_HPUX($mday, $mon, $year) if $systype eq "hpux";
    logdie "(sar) Stopping\n" unless $result = doq($conn, "end transaction", PGRES_COMMAND_OK);
}


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

$loading = 0;

if ($ARGV[0] eq "-a")
{
    shift @ARGV;
    $loading = 1;

    $sys = shift @ARGV;
    getconfig(); # Open database etc.

    agg();
    exit(0);
}

if ($ARGV[0] eq "-l")
{
    my($mday, $mon, $year, $file);

    shift @ARGV;
    $loading = 1;
   
    # Supposed to load a sar file
    $sys = shift @ARGV;

    # Next will be the file to load, day, month and year to load it in
    $file = shift @ARGV;
    $year = shift @ARGV;
    $mon = shift @ARGV;
    $mday = shift @ARGV;

    getconfig(); # Open database etc.

    open INP, $file or logdie "Cannot open file $file\n";
    sar("sar $year " . ($mon - 1) . " $mday");
    close INP;

    exit(0);
}

# Not loading a file.

$sys  = shift @ARGV; # system to monitor
$incr = shift @ARGV; # timeshift to prevent all system aggregating in thesame minute

if (!defined($sys) || !defined($incr) || $sys eq "" || $incr eq "" || scalar(@ARGV) > 0)
{
    logdie "Usage: $0 <systemname> <incr>\n";
}

open (STDIN, "</dev/null");
open (STDOUT, ">>$PGDIR/logs/" . $sys . ".log");
open (STDERR, ">&STDOUT");

STDOUT->autoflush(1);
STDERR->autoflush(1);

$get_sar = 0;
$get_uptime = 0;
$get_netstat = 0;
$get_iostat = 0;
$get_vmstat = 0;
$get_proc = 0;

logmsg "perfgatherd started for $sys\n";

$agg_count = 1 + $incr % 5;

getconfig();

system("rm $PGDIR/tmp/*" . $sys . "*.inp > /dev/null 2>/dev/null"); # remove old inp file

$SIG{CHLD} = 'IGNORE';    # prevent zombies
while (1)
{
    my ($tmpfile, $tm, $mday, $mon, $year, $tmday, $cmd, $tstamp, $hr2, $min2, $hr, $min, $dummy);

    $tm = time;
    sleep (60 - time % 60);
    sleep(4);  # just to be sure

    chomp($tmpfile = `date '+%Y%m%d%H%M'`);
    $tmpfile = "$PGDIR/tmp/$tmpfile.$sys.inp";

    if ($gathertype eq "r")
    {
        $cmd = "$rsh $sys \"date '+%Y %m %d %H %M'; echo -_-_-; echo uptime; uptime";
        if ($get_netstat)
        {
            $cmd .= "; echo -_-_-; echo netstat; netstat -in";
        }

        if ($get_iostat)
        {
            $cmd .= "; echo -_-_-; echo iostat; cat perfgraph/tmp/iostat.$sys";
        }

        if ($get_vmstat)
        {
            $cmd .= "; echo -_-_-; echo vmstat; cat perfgraph/tmp/vmstat.$sys";
        }

        $cmd .= "; echo -_-_-; echo user; perfgraph/perfuser $sys 2>/dev/null";

        if ($get_proc)
        {
            $cmd .= "; echo -_-_-; echo proc; cd /proc; cat net/dev; echo -_-_-; cat stat";
            if ($systype eq "linux2_2")
            {
                $cmd .= "; echo -_-_-; cat meminfo";
                $cmd .= "; echo -_-_-; cat sys/fs/file-max";
                $cmd .= "; cat sys/fs/file-nr";
                $cmd .= "; cat sys/fs/inode-max";
                $cmd .= "; cat sys/fs/inode-nr";
            }
        }

        # Note: sar better be the last rsh command
        if ($get_sar)
        {
            # Go back in time to catch clock missyncs
            ($dummy,$min,$hour,$mday,$mon,$year,$dummy,$dummy,$dummy) = localtime($tm - 16*60);
    
            $year += 1900;
            $tmday = $mday;
            $tmday = "0" . $mday if $mday < 10;
            $cmd .= "; echo -_-_-; echo sar $year $mon $mday; sar -A -f /var/adm/sa/sa" . 
                    $tmday . " -s " . $hour . ":" . $min;
        }
        $cmd .= "; echo -_-_-; echo end; echo\" > $tmpfile < /dev/null";

        # If reading the data takes more than 45 seconds, timeout
        eval
        {
            local $SIG{ALRM} = sub { die "alarm\n" };
            alarm 45;

            system($cmd);

            alarm 0;
        };

        if ($@ eq "alarm\n")
        {
            logmsg "Timeout while gathering data via rsh\n";
            unlink $tmpfile;
            $tmpfile = "";
        }
    }

    if ($gathertype eq "d")
    {
        if ($systype eq "NT4")
        {
            $cmd = $C_NT4;
        }
        else
        {
            $cmd  = $C_UPTIME;
            $cmd .= $C_NETSTAT if $get_netstat;
            $cmd .= $C_IOSTAT if $get_iostat;
            $cmd .= $C_VMSTAT if $get_vmstat;
            $cmd .= $C_USER;
            $cmd .= $C_PROC1 if $systype eq "linux2_0";
            $cmd .= $C_PROC2 if $systype eq "linux2_2";
            $cmd .= $C_SAR if $get_sar;
        }
        $cmd .= "\n";

        $client = IO::Socket::INET->new( Proto     => "tcp",
                                         PeerAddr  => $sys,
                                         PeerPort  => $sysmanswd_port
                                       );
        if (defined($client) && $client)
        {
            open OUT, ">$tmpfile" or logdie "Cannot open file $tmpfile for writing\n";

            # If reading the data takes more than 45 seconds, timeout
            eval
            {
                local $SIG{ALRM} = sub { die "alarm\n" };
                my $ok;

                alarm 45;

                $client->autoflush(1);
                if (<$client>)		# read welcome line if allowed
                {
                    print $client $cmd;
                    $ok = <$client>;        # wait for 'ok\n'
                    print $client $sys . "\n";

                    while (defined($buffer = <$client>))
                    {
                        print OUT $buffer;
                    }
                }
                else
                {
                    logmsg "Connection refused by sysmanswd?\n";
                    unlink $tmpfile;
                    $tmpfile = "";
                }

                alarm 0;
                close OUT;
            };

            if ($@ eq "alarm\n")
            {
                close OUT;
                logmsg "Timeout while gathering data via sysmanswd\n";
                unlink $tmpfile;
                $tmpfile = "";
            }
        }
        else
        {
            logmsg "Is the client system down, or is sysmanswd not running?\n";
            $tmpfile = "";
        }
    }

    @flist = (@flist, $tmpfile) if ($tmpfile ne "");

    if (-e "$PGDIR/tmp/backup.lock")
    {
        $backup = 1;
        undef $conn;   # release database connection
    } else
    {
        $backup = 0;
    }

    if (-e "$PGDIR/tmp/$sys.lock")
    {
        $vacuuming = 1;
        undef $conn;   # release database connection
    } else
    {
        $vacuuming = 0;
    }

    if ($vacuuming)
    {
        # Check whether done, or stale lock
        if (open(LCK, "$PGDIR/tmp/$sys.lock"))
        {
            my ($proc, $thissystem);

            chomp($proc = <LCK>);
            chomp($thissystem = `uname`);
            if ($thissystem eq "Linux")
            {
                chomp($running = `ps ax|grep $proc|grep pgadmin|grep -v grep`);
            }
            else
            {
                chomp($running = `ps -ef|grep $proc|grep pgadmin|grep -v grep`);
            }
            if ($running eq "")
            {
                $vacuuming = 0;
                # Stale lock file
                logmsg "Removing stale lock file\n";
                unlink "$PGDIR/tmp/$sys.lock";
            }
        }
        else
        {
            # Lock file gone
            logmsg "no vacuuming (anymore)\n";
            $vacuuming = 0;
        }
    }

    if (! $vacuuming && ! $backup)
    {
        if (! defined($conn))
        {
            $conn = Pg::connectdb("dbname = " . $sys);
            if ($conn->status == PGRES_CONNECTION_BAD)
            {
                logdie "(main) Cannot reopen database connection: " . $conn->errorMessage;
            }
        }

        foreach $tmpfile (@flist)
        {
            open INP, $tmpfile or logdie "Cannot open file $tmpfile\n";
            $tstamp = gettstamp;
            if ($tstamp > 0)
            {
                # skip first -_-_-
                <INP>;
                do
                {
                    $part = <INP>;
                    chomp($part) if defined($part);
        
                    uptime($tstamp)         if defined($part) && ($part =~ "^uptime");
                    netstat($tstamp)        if defined($part) && ($part =~ "^netstat");
                    iostat($tstamp)         if defined($part) && ($part =~ "^iostat");
                    vmstat($tstamp)         if defined($part) && ($part =~ "^vmstat");
                    proc($tstamp)           if defined($part) && ($part =~ "^proc");
                    usertbl($tstamp)        if defined($part) && ($part =~ "^user");
                    sar($part)              if defined($part) && ($part =~ "^sar");
                    nt4($tstamp)            if defined($part) && ($part =~ "^NT4");
        
                } while (defined($part) && $part ne "end");
            }
        
            close INP;
            unlink $tmpfile;
        }
        undef @flist;

        $agg_count++;
        if ($agg_count > 5)
        {
            # Every 5 minutes, aggregate
            $agg_count = 1;
            agg();
        }
    }
}
