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

## -_- $Name: PerfGraph-2_4d $ % $Id: perfgraphd,v 1.23.2.2.2.1.2.6 2001/09/08 16:47:53 sietse Exp $

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

# If you had to rename perfgraph.cgi to some other name, or had to
# put it in another directory, change the value of the following
# variable into your path/filename. Change it also twice in
# perfgraph.html, and once in perfgraph.cgi!!

$PG_CGI = "/cgi-bin/pg.cgi?";

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

use IO::Socket;
use Net::hostent;
use Pg;
use GD;
use Time::Local;
use POSIX;

my $client;
my $perfdb;
my @systems;
my @timezone;

# 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);

# Colors
my $h_color = '#ff6666';
my $l_color = '#99ffcc';
my $r_color = '#ccccff';
my $r_color_low = '#9999cc';

my $style_top = "
      body { font-family: verdana, arial; font-size: 10pt; background: $h_color; }
      td { font-family: verdana, arial; font-size: 10pt; background: $h_color; }
      a { color: #0000ff; text-decoration: none; }
      a.link { color: #0000ff; text-decoration: none; }
      a.visited { color: #0000ff; text-decoration: none; }
      a.active d{ color: #0000ff; text-decoration: none; }
      h1 { font-size: 18pt; font-weight: bold; }
      h2 { font-size: 16pt; font-weight: bold; }
      h3 { font-size: 14pt; font-weight: bold; }
      h4 { font-size: 12pt; font-weight: bold; }
";
my $style_left = "
      body { font-family: verdana, arial; font-size: 10pt; background: $l_color; }
      td { font-family: verdana, arial; font-size: 10pt; background: $l_color; }
      a { color: #0000ff; text-decoration: none; }
      a.link { color: #0000ff; text-decoration: none; }
      a.visited { color: #0000ff; text-decoration: none; }
      a.active d{ color: #0000ff; text-decoration: none; }
      h1 { font-size: 18pt; font-weight: bold; }
      h2 { font-size: 16pt; font-weight: bold; }
      h3 { font-size: 14pt; font-weight: bold; }
      h4 { font-size: 12pt; font-weight: bold; }
";
my $style_right = "
      body { font-family: verdana, arial; font-size: 10pt; background: $r_color; }
      td { font-family: verdana, arial; font-size: 10pt; background: $r_color; }
      td.low { font-family: verdana, arial; font-size: 10pt; background: $r_color_low; }
      td.white { font-family: verdana, arial; font-size: 10pt; background: white; }
      a { color: #0000ff; text-decoration: none; }
      a.link { color: #0000ff; text-decoration: none; }
      a.visited { color: #0000ff; text-decoration: none; }
      a.active d{ color: #0000ff; text-decoration: none; }
      h1 { font-size: 18pt; font-weight: bold; }
      h2 { font-size: 16pt; font-weight: bold; }
      h3 { font-size: 14pt; font-weight: bold; }
      h4 { font-size: 12pt; font-weight: bold; }
";

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

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

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

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

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

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

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

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

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

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

sub srv_frame
{
    print "Content-type: text/html\n\n";
    print "<HTML>\n";
    print "<HEAD>\n";
      print "<TITLE>Perfgraph</TITLE>\n";
    print "</HEAD>\n";

    print "<frameset rows='70,*' frameborder='0' marginheigt='0' marginwidth='0'>\n";
    print "<frame src='${PG_CGI}header' name='header'>\n";
      print "<frameset cols='150,*' frameborder=1>\n";
        print "<frame src='${PG_CGI}syslist' name='left'>\n";
        print "<frame src='${PG_CGI}empty' name='right'>\n";
      print "</frameset>\n";
    print "</frameset>\n";
    print "</html>\n";

}

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

sub srv_help
{
    my ($item) = @_;
    my ($nread, $buffer, $HELP, $fnam, $fields);

    $HELP = 100;

    $fnam = $PGDIR . "/web/" . $item . ".hlp";
    open(HELP, "<" . $fnam) or logmsg "Cannot open help file $fnam: $!\n";

    # Fiend the number of fields
    $fields = 0;
    while (defined($line = <HELP>))
    {
        $fields++ if ($line =~ /^\@field/);
    }
    close HELP;

    if (!open(HELP, "<" . $fnam))
    {
        logmsg "Cannot open help file $fnam: $!\n";
        print "Content-type: text/html\n\n";
        print "<html>\n";
        print "<head>\n";
        print "<title>$line</title>\n";
        print "<style>\n$style_right</style>\n";
        print "</head>\n\n";

        print "<body vlink='#0000ff'>\n\n";

        print "<big><strong>No help found for $item</strong></big>\n";
        
        print "</body>\n";
        print "</html>\n";

        return;
    }

    # Find @title
    while (defined($line = <HELP>) && $line !~ /\@title/) {} ;
    return if !defined($line);
    chomp($line = <HELP>);

    print "Content-type: text/html\n\n";
    print "<html>\n";
    print "<head>\n";
    print "<title>$line</title>\n";
    print "<style>\n$style_right</style>\n";
    print "</head>\n\n";

    print "<body vlink='#0000ff'>\n\n";

    print "<big><big><big><em><strong>$line<br>&nbsp;</strong></em></big></big></big>\n";

    print "<table border='0' width='100%' cellpadding='4' cellspacing='4'>\n";
    print "  <tr>\n";
    print "    <td width='25%' valign='top' class='white'>\n";
    print "        <strong>General</strong>\n";
    print "    </td>\n";
    print "    <td width='75%' valign='top' colspan=2 class='white'>\n";

    while (defined($line = <HELP>) && $line !~ /^\@general/) {} ;
    return if !defined($line);
    while (defined($line = <HELP>) && $line !~ /^\@field/) 
    {
        print "       " . $line;
    }

    print "    </td>\n";
    print "  </tr>\n";

    print "  <tr>\n";
    print "    <td width='25%' valign='top' rowspan='" . $fields . "' class='white'>\n";
    print "        <strong>Field descriptions</strong>\n";
    print "    </td>\n";

    while (defined($line) && $line !~ /^\@source/)
    {
        if ($line !~ /^\@field/)
        {
            while (defined($line = <HELP>) && $line !~ /^\@field/) {}
        }
        return if !defined($line);
        $line = <HELP>;
        chomp($line);
        print "    <td width='20%' valign='top' class='white'>\n";
        print "        <b>" . $line . "</b>\n";
        print "    </td>\n";

        print "    <td width='65%' valign='top' class='white'>\n";
        while (defined($line = <HELP>) && $line !~ /^\@/)
        {
            chomp($line);
            print "        " . $line;
        }
        print "    </td>\n";

        print "  </tr>\n";
    }

    print "  <tr>\n";
    print "    <td width='25%' valign='top' class='white'>\n";
    print "        <strong>Source of data</strong>\n";
    print "    </td>\n";
    print "    <td width='75%' valign='top' colspan='2' class='white'>\n";

    while (defined($line = <HELP>))
    {
        print "       " . $line;
    }

    print "    </td>\n";
    print "  </tr>\n";

    print "</table>\n";

    print "</body>\n";
    print "</html>\n";

    close HELP;
}

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

sub srv_logo
{
    my ($nread, $buffer, $LOGO);

    $LOGO = 100;
    open(LOGO, "<$PGDIR/web/sysman.gif") or logmsg "Cannot open logo: $!\n";
    print "Content-type: image/gif\n\n";

    $nread = read LOGO, $buffer, 4096;
    syswrite STDOUT, $buffer, $nread;

    close LOGO;
}

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

sub srv_header
{
    if (!$ripper)
    {
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
    }

    print STDOUT "<HTML>
     <HEAD>
      <TITLE>System performance monitor grapher</TITLE>
      <style>\n$style_top</style>
     </HEAD>

     <body vlink='#0000ff'>
     <table width='100%', border=0, cellspacing=0, cellpadding=0>
       <tr>
         <td align='center' width='50%'><big><b>PerfGraph<b></big></td>
         <td align='center' width='50%'><a href='http://www.sysman.nl' target='_top'>
            <img src='${PG_CGI}logo' border=0></a></td>
       </tr>
     </table>
     </body>
    </HTML>
    \n";
}

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

sub srv_oldhtml
{
    if (!$ripper)
    {
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
    }

    print STDOUT "<HTML>
     <HEAD>
      <TITLE>System performance monitor grapher</TITLE>
      <style>\n$style_right</style>
     </HEAD>

     <body vlink='#0000ff'>
     <b>Please install the new version of perfgraph.html - copy it from ~perfgr/web to your web server.</b>
     </body>
    </HTML>
    \n";
}

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

sub srv_empty
{
    if (!$ripper)
    {
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
    }

    print STDOUT "<HTML>
     <HEAD>
      <TITLE>System performance monitor grapher</TITLE>
      <style>\n$style_right</style>
     </HEAD>

     <body vlink='#0000ff'>
     <b>Click on a system in the left pane.</b>
     </body>
    </HTML>
    \n";
}

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

sub srv_systems
{
    my @args = @_;

    if (!$ripper)
    {
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
    }

    print STDOUT "<HTML>
     <HEAD>
      <TITLE>System performance monitor grapher</TITLE>
      <style>\n$style_left</style>
     </HEAD>

     <body vlink='#0000ff'>
     <P ALIGN='CENTER'>

     Click on one of the systems: ";
    
    foreach $host (0 .. scalar(@systems) - 1)
    {
        print STDOUT "<BR>
              <A HREF=\"" . $PG_CGI . "table+" . $systems[$host][0] . "+" .
              (($systems[$host][2] eq "NT4") ? "NT" : "") .
              "sysload+s+-+hour+grp+nohist+5+recent" . ($ripper ? ".html" : "" ) . 
              "\" TARGET=\"right\">" .
               $systems[$host][3] . "</A>
        ";
    }

    print STDOUT "
     </body>
    </HTML>
    \n";
}

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

sub do_history
{
    my ($host, $table, $multiple, $whichmult, $grlen, $groups, $hist, $refresh,
        $hour, $day, $month, $year) = @_;
    my ($dummy, $d, $m, $y, $wd, $tm, $tstamps, $q, $deldays, $now, $datestr);

    $now = time;
    ($dummy, $dummy, $dummy, $d, $m, $y, $wd, $dummy, $dummy) = localtime($now);
    $y += 1900;
    $tm = timegm(0, 0, 0, $d, $m, $y);
    $m++;

    $q = "select * from tstamps";
    logdie "(do_history) Stopping\n" unless $tstamps = doq($conn, $q, PGRES_TUPLES_OK);
    $q = "select * from deldays";
    logdie "(do_history) Stopping\n" unless $deldays = doq($conn, $q, PGRES_TUPLES_OK);

    if ($grlen eq "hour")
    {
        $tm += 24 * 3600;
        do
        {
            $tm -= 24 * 3600;
            ($dummy, $dummy, $dummy, $d, $m, $y, $wd, $dummy, $dummy) = gmtime($tm);
            $y += 1900;
            $m++;
            printf STDOUT "<B>Date:</B> %02d/%02d/%04d - <B>Time:</B> ", $d, $m, $y;

            foreach $hr ("00", "06", "12", "18")
            {
                print STDOUT
                      "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                      $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups .
                      "+" . $hist . "+" . $refresh . "+" . $hr . "+" . $d . "+" . $m . "+" . $y .
                      "\" TARGET=\"right\">" .  $hr . ":00</A>\n";
            }
            print STDOUT "<BR>\n";

        } while ($tm > $tstamps->getvalue(0, 6) && $tm > $now - $deldays->getvalue(0, 0) * 24 * 3600);
    }

    if ($grlen eq "day")
    {
        my $cnt = 0;

        $tm += 24 * 3600;
        do
        {
            $tm -= 24 * 3600;
            ($dummy, $dummy, $dummy, $d, $m, $y, $wd, $dummy, $dummy) = gmtime($tm);
            $y += 1900;
            $m++;
            print STDOUT "<B>Date:</B> " if $cnt % 4 == 0;
            $datestr = sprintf "%02d/%02d/%04d", $d, $m, $y;

            print STDOUT
                  "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                  $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups .
                  "+" . $hist . "+" . $refresh . "+00+" . $d . "+" . $m . "+" . $y .
                  "\" TARGET=\"right\">" .  $datestr . "</A>\n";
            print STDOUT "<BR>\n" if $cnt % 4 == 3;
            $cnt++;
        } while ($tm > $tstamps->getvalue(0, 6) && $tm > $now - $deldays->getvalue(0, 1) * 24 * 3600);
    }

    if ($grlen eq "week")
    {
        $tm -= $wd * 24 * 3600;
        $tm += 7 * 24 * 3600;
        do
        {
            $tm -= 7 * 24 * 3600;
            ($dummy, $dummy, $dummy, $d, $m, $y, $wd, $dummy, $dummy) = gmtime($tm);
            $y += 1900;
            $m++;
            print STDOUT "<B>Week starting Sunday, </B> ";
            $datestr = sprintf "%02d/%02d/%04d", $d, $m, $y;

            print STDOUT
                  "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                  $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups .
                  "+" . $hist . "+" . $refresh . "+00+" . $d . "+" . $m . "+" . $y .
                  "\" TARGET=\"right\">" .  $datestr . "</A><BR>\n";
        } while ($tm > $tstamps->getvalue(0, 6) && $tm > $now - $deldays->getvalue(0, 2) * 24 * 3600);
    }

    if ($grlen eq "month")
    {
        my $cnt = 0;

        $m++;
        if ($m == 13) { $m = 1; $y++; }
        do
        {
            $m--;
            if ($m == 0) { $m = 12; $y--; }
            $tm = timegm(0, 0, 0, 1, $m-1, $y);

            print STDOUT "<B>Month:</B> " if $cnt % 4 == 0;
            $datestr = sprintf "%02d/%04d", $m, $y;

            print STDOUT
                  "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                  $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups .
                  "+" . $hist . "+" . $refresh . "+00+01" . "+" . $m . "+" . $y .
                  "\" TARGET=\"right\">" .  $datestr . "</A>\n";
            print STDOUT "<BR>\n" if $cnt % 4 == 3;
            $cnt++;
        } while ($tm > $tstamps->getvalue(0, 6) && $tm > $now - $deldays->getvalue(0, 3) * 24 * 3600);
    }

    if ($grlen eq "year")
    {
        $y++;
        do
        {
            $y--;
            $tm = timegm(0, 0, 0, 1, 0, $y);

            $datestr = sprintf "%04d", $y;

            print STDOUT "<B>Year:</B> " .
                  "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                  $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups .
                  "+" . $hist . "+" . $refresh . "+00+01+01" . "+" . $y .
                  "\" TARGET=\"right\">" .  $datestr . "</A><BR>\n";
        } while ($tm > $tstamps->getvalue(0, 6) && $tm > $now - $deldays->getvalue(0, 4) * 24 * 3600);
    }
}

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

sub srv_table
{
    my ($host, $table, $multiple, $whichmult, $grlen, $groups, $hist, $refresh,
        $hour, $day, $month, $year) = @_;
    my ($result, $q, $i, $tables, $tblflds, $mresult, $mult, $mline, $tmline, @graph_fields, $refr, $gl);
    my $help_ok = 0;

    if ($hour eq "recent")
    {
        $tmline = "recent";
    } else
    {
        $tmline = $hour . "+" . $day . "+" . $month . "+" . $year;
    }
 
    $q = "select tablename, description, multiple from tables, systems " .
         "where tables.systype = systems.systype and hostname='" . $host . "' " .
         "order by description";
    logdie "(srv_table) Stopping\n" unless $tables = doq($perfdb, $q, PGRES_TUPLES_OK);

    $q = "select fieldname,description,groupnum,fieldseq from fields,tables,systems " .
         "where fieldtable = '" . $table . "' and fieldtable=tablename and " .
         "tables.systype = systems.systype and hostname = '$host' order by groupnum,fieldseq";
    logdie "(srv_table) Stopping\n" unless $result = doq($perfdb, $q, PGRES_TUPLES_OK);

    foreach $i (0 .. 9) { $graph_fields[$i] = ""; }

    if ($multiple eq "s")
    {
        $tblflds = "gen+" . $table;
        foreach $i (1 .. $result->ntuples - 1)
        {
            @graph_fields[$result->getvalue($i, 2)] .= "+" . $result->getvalue($i, 0);
        }
    }

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

        $mline = "";
        $whichmult = $mresult->getvalue(0, 0) if $whichmult eq "-" && $mresult->ntuples > 0;
        foreach $mult ( 0 .. $mresult->ntuples - 1)
        {
            if ($mresult->getvalue($mult, 0) eq $whichmult)
            {
                $mline .= "<B>" . $mresult->getvalue($mult, 0) . "</B>";
                $tblflds = "mbm+" . $table . "+" . $mresult->getvalue($mult, 0);
            } else
            {
                $mline .= "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                   $multiple . "+" . $mresult->getvalue($mult, 0) . "+" . $grlen . "+" . $groups .
                   "+" . $hist . "+" . $refresh . "+" . $tmline . ($ripper ? ".html" : "" ) . 
                   "\" TARGET=\"right\">" .  $mresult->getvalue($mult, 0) . "</A>\n";
            }
            $mline .= " - " unless $mult == $mresult->ntuples - 1;
        }

        foreach $i (2 .. $result->ntuples - 1)
        {
            @graph_fields[$result->getvalue($i, 2)] .= "+" . $result->getvalue($i, 0);
        }
    }

    if (! $ripper)
    {
        print STDOUT "Refresh: " . ($refresh * 60) . "\n" if $refresh ne "never";
        print STDOUT "Expires: " . mk_expiry(time) . "\n";
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
    }

    print STDOUT "<HTML>
     <HEAD>
      <TITLE>System performance monitor grapher</TITLE>
      <style>\n$style_right</style>
     </HEAD>

     <body vlink='#0000ff'>
     <CENTER><H1>" . $nickname . " - " . $result->getvalue(0, 1) . "</H1>\n";

    foreach $i (0 .. $tables->ntuples - 1)
    {
        print STDOUT " - " if $i != 0;
        if ($tables->getvalue($i, 0) eq $table)
        {
            print STDOUT "<B> " . $tables->getvalue($i, 1) . " </B>";
        } else
        {
            print STDOUT "
                  <A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $tables->getvalue($i, 0) . "+" .
                       $tables->getvalue($i, 2) . "+-+" . $grlen . "+" . $groups . "+" . $hist . "+" .
                       $refresh . "+" . $tmline . ($ripper ? ".html" : "" ) . "\" TARGET=\"right\">" .
                       $tables->getvalue($i, 1) . "</A>";
        }
    }

    print STDOUT "<HR>\n";

    foreach $gl ("hour", "day", "week", "month", "year")
    {
        if ($grlen eq $gl)
        {
            print STDOUT "<B>" . $gl . "</B>";
        } else
        {
            print STDOUT     "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                              $multiple . "+" . $whichmult . "+" . $gl . "+" . $groups . "+" .
                              $hist . "+" . $refresh .  "+" . $tmline . ($ripper ? ".html" : "" ) . 
                              "\" TARGET=\"right\">" .  $gl . "</A>\n";
        }
        if ($gl ne "year") { print STDOUT " - "; }
    }

    print STDOUT "<HR>\n";

    if ($multiple eq "m")
    {
        print STDOUT $mline;
        print STDOUT "<HR>\n";
    }

    if (-f "$PGDIR/web/$table.hlp")
    {
        print STDOUT "<map name=\"" . $table . "\">\n";
        print STDOUT "<area shape=rect coords=\"64,156,580,190\" HREF=\"" .
                      $PG_CGI . "help+" . $table . ($ripper ? ".html" : "") .
                      "\" TARGET=\"right\">\n";
        print STDOUT "</map>\n";
        $help_ok = 1;
    }

    if ($multiple eq "s" || ($multiple eq "m" && $mresult->ntuples > 0))
    {
        if ($groups eq "grp")
        {
            foreach $i (1 .. 9)
            {
                next if $graph_fields[$i] eq "";
                print STDOUT " <img src=\"" . $PG_CGI . "draw+" . $host . "+-+" .
                              $tmline . "+600+200+" .
                              $grlen . "+" . $tblflds . $graph_fields[$i] .
                              ($ripper ? ".gif" : "" ) . "\"";
                if ($help_ok)
                {
                    print STDOUT " usemap=\"#" . $table . "\" border=\"0\"";
                }
                print STDOUT " ><HR>\n";
            }
        } else
        {
            $i = ($multiple eq "s") ? 1 : 2;
            while ($i < $result->ntuples)
            {
                print STDOUT " <img src=\"" . $PG_CGI . "draw+" . $host . "+-+" .
                              $tmline . "+600+200+" .
                              $grlen . "+" . $tblflds . "+" . $result->getvalue($i, 0) . 
                              ($ripper ? ".gif" : "" ) . "\"";
                if ($help_ok)
                {
                    print STDOUT " usemap=\"#" . $table .  "\" border=\"0\"";
                }
                print STDOUT " ><HR>\n";
                 $i++;
            }
        }
    } else
    {
        print STDOUT "Not being monitored.<HR>\n";
    }

    if ($hist eq "hist")
    {
        do_history(@_);
        print STDOUT "<HR>\n";
    }

    if ($ripper)
    {
        print STDOUT "<table border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">\n" .
                        "<tr>\n" .
                           "<td width=\"20%\">\n" .
                                  "<B>Separate graphs</B>\n" .
                           "<td width=\"40%\"><P align=\"center\">Refresh: ";
    }
    else
    {
        print STDOUT "<table border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">\n" .
                        "<tr>\n" .
                           "<td width=\"20%\">\n" .
    
                                  "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                                  $multiple . "+" . $whichmult . "+" . $grlen . "+" .
                                  (($groups eq "grp") ? "sep" : "grp") . "+" . $hist . "+" . $refresh .
                                  "+" . $tmline .  "\" TARGET=\"right\">" .
                                  (($groups eq "grp") ? "Separate graphs" : "Group graphs") . "</A>\n" .
                           "<td width=\"40%\"><P align=\"center\">Refresh: ";
    }

    foreach $refr ("1", "5", "15", "never")
    {
        if ($refr eq $refresh || $ripper)
        {
            print STDOUT     "<B>" . $refr . "</B>";
        } else
        {
            print STDOUT     "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                              $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups . "+" .
                              $hist . "+" . $refr .  "+" . $tmline .  "\" TARGET=\"right\">" .  $refr . "</A>\n";
        }
        print STDOUT         " - ";
    }

    if ($ripper)
    {
        print STDOUT "<B>now</B>\n";
    }
    else
    {
        print STDOUT         "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                              $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups . "+" .
                              $hist . "+" . $refresh . "+" . $tmline .  "\" TARGET=\"right\">now</A>\n";
    }

    if ($ripper)
    {
        print STDOUT      "<td width=\"20%\"><P align=\"right\">" .
                             "<B>History</B>" . "\n" .
                           "</td>\n" .
                        "</tr>\n" .
                      "</table>\n";
    }
    else
    {
        print STDOUT      "<td width=\"20%\"><P align=\"right\">" .

                                  "<A HREF=\"" . $PG_CGI . "table+" . $host . "+" . $table . "+" .
                                  $multiple . "+" . $whichmult . "+" . $grlen . "+" . $groups . "+" .
                                  (($hist eq "hist") ? "nohist+" . $refresh . "+recent"
                                                     : "hist+" . $refresh . "+" . $tmline) .
                                  "\" TARGET=\"right\">" .
                                  (($hist eq "hist") ? "Recent" : "History") . "</A>\n" .

                           "</td>\n" .
                        "</tr>\n" .
                      "</table>\n";
    }

    print STDOUT "<p>&nbsp\n";
    print STDOUT "</CENTER></body></HTML> \n";
}

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

sub usage()
{
  logdie "Usage called (meaning you made an illegal draw call)\n";
}

sub srv_draw
{
    my @args = @_;
    my $perfdb;
    my $conn;

    usage() if (scalar(@args) < 9);

    $system    = shift @args;
    $gif       = shift @args;
    $hour      = shift @args;

    if ($hour ne "recent")
    {
        usage() if (scalar(@args) < 9);

        $mday  = shift @args;
        $mon   = shift @args; $mon--;
        $year  = shift @args;
    }
    $width     = shift @args;
    $height    = shift @args;
    $graph_len = shift @args;
    $graph     = shift @args;
    $table     = shift @args;
    @rest      = @args;

    if ($hour eq "recent")
    {
        my $dummy;
        my $tm;

        $tm = time;
        if ($graph_len eq "hour")
        {
            $tm -= 5 * 3600;
            ($dummy,$dummy,$hour,$mday,$mon,$year,$dummy,$dummy,$dummy) = localtime($tm);
        } elsif ($graph_len eq "day")
        {
            $tm -= 23 * 3600;
            ($dummy,$dummy,$hour,$mday,$mon,$year,$dummy,$dummy,$dummy) = localtime($tm);
        } elsif ($graph_len eq "week")
        {
            $tm -= 6 * 24 * 3600;
            ($dummy,$dummy,$dummy,$mday,$mon,$year,$dummy,$dummy,$dummy) = localtime($tm);
            $hour = 0;
        } elsif ($graph_len eq "month")
        {
            $tm -= 28 * 24 * 3600;
            ($dummy,$dummy,$dummy,$mday,$mon,$year,$dummy,$dummy,$dummy) = localtime($tm);
            $hour = 0;
        } elsif ($graph_len eq "year")
        {
            $tm -= 330 * 24 * 3600;
            ($dummy,$dummy,$dummy,$dummy,$mon,$year,$dummy,$dummy,$dummy) = localtime($tm);
            $hour = 0;
            $mday = 1;
        }
    }

    # Create a new image
    $image = new GD::Image($width, $height);

    if ($graph eq "gen")  { graph_gen($image) }
    if ($graph eq "mbm")  { graph_mult_by_mult($image); }
    if ($graph eq "mbv")  { graph_mult_by_val($image); }
}

#
# Initialize stuff
#
sub initialize() {
    my(
       $seconds_on_graph    # how many seconds worth of information will be graphed
       );

    # calculate the number of seconds of information that will be displayed
    # 86400 is the number of seconds in a day
    $seconds_on_graph = 86400 / 4 if $graph_len eq "hour"; # for a 6-hour graph
    $seconds_on_graph = 86400 if ($graph_len eq "day");
    $seconds_on_graph = 86400 * 7 if ($graph_len eq "week");
    $seconds_on_graph = 86400 * 31 if ($graph_len eq "month");
    $seconds_on_graph = 86400 * 365 if ($graph_len eq "year");

    if ($graph_len eq "hour" || $graph_len eq "day")
    {
        $x_start_time = timegm(0,0,$hour,$mday,$mon,$year);
    } else
    {
        if ($graph_len eq "week")
        {
            $x_start_time = timegm(0,0,0,$mday,$mon,$year);
        } else
        {
            if ($graph_len eq "month")
            {
                $x_start_time = timegm(0,0,0,$mday,$mon,$year);
            } else
            {
                if ($graph_len eq "year")
                {
                    $x_start_time = timegm(0,0,0,1,$mon,$year);
                }
            }
        }
    }

    $x_end_time = $x_start_time + $seconds_on_graph;

    @gmtime = gmtime($x_start_time);
}

#
# Put a title on the graph, centered
#
sub add_title_to_graph($$) {
   my($image, $host) = @_;
   my($text, $title_x);

   $text = $host . " - ";
   $text .= strftime("%a, %b %e, %Y", @gmtime);
   $title_x = ($width - (length($text) * $title_font->width)) / 2;
   $image->string($title_font, $title_x, 0, $text, $title_color);
}

#
# Add a line to the legend (key).
#
sub add_to_legend($$$) {
   my($image, $text, $color) = @_;

   my($x, $y, $legend_graphic_length);

   $legend_graphic_length = 3;

   $x = ($num_lines_on_legend % 3) * (($width - $origin_x) / 3) + $origin_x;
   $y = ($height - $bottom_margin + 
          $legend_font->height *( int($num_lines_on_legend / 3) + 1));
   $y -= 2 * int($num_lines_on_legend / 3);
   $image->string($legend_font, $x, $y, $text, $color);
   $num_lines_on_legend++;
}

#
# Label the y-axis
#
sub label_y_axis($$)
{
    my($image, $max_y) = @_;
    my($delta, $val, $step, $py, $i, $max);

    $image->setStyle($dark_grey, gdTransparent, gdTransparent);

    if ($max_y == 0) { $max_y = 1; }
    elsif ($max_y < 0.5) { $max_y = 0.5; };

    $step = 10 ** (int (log($max_y) / log(10)));
    $step /= 2  if ($max_y / $step) < 5;
    $step /= 2  if ($max_y / $step) < 5;

    $numsteps = int($max_y / $step);
    $max = $numsteps * $step;
    $max += $step if $max_y > $max;

    $step2 = 10 ** (int (log($max) / log(10)));
    $step2 /= 2  if ($max / $step2) < 5;
    $step2 /= 2  if ($max / $step2) < 5;

    $y_scale = ($max - 0) / ($height - $top_margin - $bottom_margin);

    for ($i = 0; $i <= $max; $i += $step2 )
    {
        my $str;

        $py = ($height - $bottom_margin) - ($i / $y_scale);

        last if ($py < $top_margin);
        $str =                 "$i" if $step < 10000;
        $str =    ($i / 1000) . "k" if $step >= 10000 && $step < 10000000;
        $str = ($i / 1000000) . "M" if $step >= 10000000;

        $image->line($origin_x, $py, $width - $right_margin, , $py, gdStyled);

        $image->line($origin_x - 2, $py, $origin_x + 2, $py, $axis_color);
        $image->string($label_font,
                       $origin_x - 5 - length($str) * $label_font->width,
                       $py - $label_font->height / 2,
                       $str, $axis_color) unless $i == 0;
    }
}

#
# Put hash marks and labels on the graph
#
sub label_x_axis($)
{
    my($image) = shift @_;
    my(
       @start_date,
       $tic_time,
       $tic_offset,
       $tic_val,
       $time,
      );

    $x_scale = ($x_end_time - $x_start_time) /
               ($width - $left_margin - $right_margin);

    if ($graph_len eq "hour") {
       # Put a tick every hour, possibly label each one
       for ($tic_time = $x_start_time; $tic_time <= $x_end_time;
             $tic_time += 900)
       {
           if ($tic_time % 3600 == 0)
           {
               $tic_offset = ($tic_time - $x_start_time) + $hour * 3600;
               $tic_val = ($tic_offset / 3600) % 24 . ":00";
               label_x_axis_point($image, $tic_time, $tic_val, 2);
           } else
           {
               label_x_axis_point($image, $tic_time, "", 1);
           }
        }
    }
    if ($graph_len eq "day") {
       # Put a tick every 3 hours, possibly label each one
       for ($tic_time = $x_start_time; $tic_time <= $x_end_time;
             $tic_time += 3600)
       {
           if ($tic_time % (3 * 3600) == 0)
           {
               $tic_offset = ($tic_time - $x_start_time) + $hour * 3600;
               $tic_val = ($tic_offset / 3600) % 24 . ":00";
               label_x_axis_point($image, $tic_time, $tic_val, 2);
           } else
           {
               label_x_axis_point($image, $tic_time, "", 1);
           }
        }
    }
    if ($graph_len eq "week") {
       # Put a tick every day, possibly label each one
       for ($tic_time = $x_start_time; $tic_time <= $x_end_time;
             $tic_time += 12 * 3600)
       {
           if ($tic_time % (24*3600) == 0)
           {
               @start_date = split /\s+/, gmtime($tic_time);
               $tic_val = $start_date[1] . " " .  $start_date[2];
               label_x_axis_point($image, $tic_time, $tic_val, 2);
            } else
            {
               label_x_axis_point($image, $tic_time, "", 1);
            }
        }
    }
    if ($graph_len eq "month") {
       # Put a tick every week, possibly label each one
       for ($tic_time = $x_start_time; $tic_time <= $x_end_time;
             $tic_time += 24 * 3600)
       {
           if (($tic_time - $x_start_time) % 7 == 0)
           {
               @start_date = split /\s+/, gmtime($tic_time);
               $tic_val = $start_date[1] . " " .  $start_date[2];
               label_x_axis_point($image, $tic_time, $tic_val, 2);
            } else
            {
               label_x_axis_point($image, $tic_time, "", 1);
            }
        }
    } elsif ($graph_len eq "year")
    {
        # Put tics at the first of each month; label them on the 15th
        # This is really inefficient, but we have to go 1 hour at a time
        # because daylight savings time can throw us off.
        for ($tic_time = $x_start_time; $tic_time <= $x_end_time;
             $tic_time += 12 * 3600)
        {
            $tic_offset = ($tic_time - $x_start_time);
            if ($tic_offset == 0)
            {
                label_x_axis_point($image, $tic_time, "", 1);
            } else
            {
                $time = gmtime($tic_time);
                $time =~ tr/:/ /;
                @start_date = split /\s+/, $time;
                if ($start_date[2] == 1 && $start_date[3] == 12)
                {
                    label_x_axis_point($image, $tic_time, "", 2);
                } elsif ($start_date[2] == 15 && $start_date[3] == 12)
                {
                    $tic_val = substr($start_date[1],0,3);
                    label_x_axis_point($image, $tic_time, $tic_val, 0);
                }
            }
        }
    }
}

#
# Label a point on the x-axis
#
sub label_x_axis_point($$$$)
{
    my($image, $tic_time, $tic_val, $put_hash_mark) = @_;

    $x1 = $origin_x + (($tic_time - $x_start_time) / $x_scale);
    $y1 = ($height - $bottom_margin) + $hash_length;

    if ($put_hash_mark == 1) {
       $image->line($x1, $origin_y, $x1, $origin_y + $hash_length, $axis_color);
    }

    if ($put_hash_mark == 2)
    {
        $image->setStyle($dark_grey, gdTransparent, gdTransparent);
        $image->line($x1, $top_margin, $x1, $height - $bottom_margin, gdStyled);
        $image->line($x1, $origin_y, $x1, $origin_y + $hash_length, $axis_color);
    }

   if (length($tic_val)) {
      # Put the label on the graph. Center the text around the point
      $x1 = $origin_x + (($tic_time - $x_start_time) / $x_scale)
             - ((length($tic_val) * $label_font->width) / 2);
      $image->string($label_font, $x1, $y1, $tic_val, $axis_color);
   }
}

#
# Generate the graph
#
sub plot_data($$$$$$) {
   my($image, $color, $ltext, $draw_points, $plot_style, $q) = @_;
   my($prev_x1, $prev_y1, $sample, $x1, $y1);
   my(@points);

   Pg::doQuery($conn, $q, \@points);

   # Coordinates of the last point plotted
   $prev_x1 = -1;
   $prev_y1 = -1;

   add_to_legend($image, $ltext, $color);

   foreach $sample ( 0 .. $#points )
   {
      next if ($points[$sample][0] < $x_start_time || $points[$sample][0] > $x_end_time);

      # The x and y-coordinates of the data point
      $x1 = int($origin_x + (($points[$sample][0] - $x_start_time) / $x_scale));
      $y1 = int(($height - $bottom_margin) - ($points[$sample][$draw_points] / $y_scale));

      if ($plot_style eq "points") {
         # Plot the data point
         $image->setPixel($x1, $y1, $color);
      } elsif ($plot_style eq "lines") {
         if ($prev_x1 != -1) {
            # Plot the data point and connect it to the previous one
            $image->line($prev_x1, $prev_y1, $x1, $y1, $color) if (($x1 - $prev_x1) < $min_x_diff);
            # printf("%9d   %s   %5d   %5d   %5d\n",
            #        $sample_time, scalar(gmtime($points[$sample][0])), $prev_x1, $x1, $x1 - $prev_x1);
         }
         $prev_x1 = $x1;
         $prev_y1 = $y1;
      } elsif ($plot_style eq "impulses") {
         # Plot the data point
         if ($points[$sample][$draw_points] > 0) {
            # Don't draw on the x-axis if the value is > 0
            $image->line($x1, $height - $bottom_margin - 1, $x1, $y1, $color);
         } else {
            $image->line($x1, $height - $bottom_margin, $x1, $y1, $color);
         }
      }
   }
}

#
# Return the greater of two numbers
#
sub max($$) {
   my($a,$b) = @_;

   $a = 0 if $a eq "";
   $b = 0 if $b eq "";
   return ($a > $b ? $a : $b);
}

#
# Return the lesser of two numbers
#
sub min($$) {
   my($a,$b) = @_;

   return ($a < $b ? $a : $b);
}

sub mk_expiry($)
{
    my $tm = shift @_;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$idst);
    my $str;

    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$idst) = localtime($tm);
    $str = "Sunday " if $wday == 0;
    $str = "Monday " if $wday == 1;
    $str = "Tuesday " if $wday == 2;
    $str = "Wednesday " if $wday == 3;
    $str = "Thursday " if $wday == 4;
    $str = "Friday " if $wday == 5;
    $str = "Saterday " if $wday == 6;

    $str .= sprintf("%02d-" , $mday);

    $str .= "Jan-" if $mon == 0;
    $str .= "Feb-" if $mon == 1;
    $str .= "Mar-" if $mon == 2;
    $str .= "Apr-" if $mon == 3;
    $str .= "May-" if $mon == 4;
    $str .= "Jun-" if $mon == 5;
    $str .= "Jul-" if $mon == 6;
    $str .= "Aug-" if $mon == 7;
    $str .= "Sep-" if $mon == 8;
    $str .= "Oct-" if $mon == 9;
    $str .= "Nov-" if $mon == 10;
    $str .= "Dec-" if $mon == 11;

    $str .= sprintf ("%02d %02d:%02d:%02d %s", $year, $hour, $min, $sec, $timezone);

    return $str;
}

sub drawgif($)
{
    my $image = shift @_;
    my $exp;

    $exp = time;
    $exp +=  4*60 if $graph_len eq 'day';
    $exp += 17*60 if $graph_len eq 'week';
    $exp += 19*60 if $graph_len eq 'month';
    $exp += 58*60 if $graph_len eq 'year';

    if ($gif eq "-")
    {
        if (! $ripper)
        {
            print STDOUT "Pragma: no-cache\n";
            print STDOUT "Expires: " . mk_expiry($exp) . "\n";
            print STDOUT "Content-type: image/gif\n\n";
        }
        print STDOUT $image->gif;
    }
    else
    {
        open GIF, "> $gif" or logdie "(drawgif) Can't open $gif: $!\n";
        print GIF $image->gif;
        close GIF;
    }
}

#
# Create a new graph
#
sub initialize_graph($) {
   my($image) = shift @_;

   $num_lines_on_legend = 0;

   # Allocate colors
   $green        = $image->colorAllocate(  0, 255,   0);
   $blue         = $image->colorAllocate(  0,   0, 255);
   $brown        = $image->colorAllocate(165,  42,  42);
   $violet       = $image->colorAllocate(255,   0, 255);
   $red          = $image->colorAllocate(255,   0,   0);
   $purple       = $image->colorAllocate(160,  32, 240);
   $medium_green = $image->colorAllocate(  0, 200,   0);
   $navy_blue    = $image->colorAllocate(  0,   0,  80);
#   $dark_green   = $image->colorAllocate(  0,   6,  40);
   $dark_grey    = $image->colorAllocate(100, 100, 100);
#   $yellow       = $image->colorAllocate(255, 255,   0);
#   $ivory        = $image->colorAllocate(245, 245, 245);
#   $grey         = $image->colorAllocate(180, 180, 180);
   $olive        = $image->colorAllocate(107, 142,  35);
#   $white        = $image->colorAllocate(255, 255, 255);
   $black        = $image->colorAllocate(  0,   0,   0);
   $gray         = $image->colorAllocate(240, 240, 240);

   @colors = ($blue, $medium_green, $red, $violet, $brown, $purple,
              $green, $navy_blue, $olive);

   #====================================
   # Configurable parameters start here
   #====================================

   $axis_color       = $black;
   $background_color = $gray;
   $title_color      = $black;
 
   $label_font       = gdLargeFont;
   $legend_font      = gdLargeFont;
   $title_font       = gdLargeFont;

   # leave enough of a left margin to print 7 digits of info.
   $left_margin      = max(25, $label_font->width * 8);
   $right_margin     = 25;
   $top_margin       = 20;

   # Leave enough room in the bottom margin
   $bottom_margin = 60;

   # The minimum distance required between two points for the points
   # to be connected with a line.
   $min_x_diff = 10;

   # The length of a hash mark
   $hash_length = 4;
 
   #====================================
   # End of configurable parameters
   #====================================
 
   # Coordinates of the origin
   $origin_x = $left_margin;
   $origin_y = $height - $bottom_margin;

   # Set the background
   $image->filledRectangle(0, 0, $width, $height, $background_color);
   $system = $nickname if ($nickname !~ /^\s*$/);
   add_title_to_graph($image, $system);
 
   # Draw the y-axis
   $image->line($origin_x, $top_margin, $origin_x,
                $height - $bottom_margin, $axis_color);
 
   # Draw the x-axis
   $image->line($origin_x, $height - $bottom_margin,
                $width - $right_margin, $height - $bottom_margin, $axis_color);

   label_x_axis($image);
}

sub graph_mult_by_mult($)
{
    my $image = shift @_;
    my($i, $q, $max_y, $j, @rows, $mult, $m, $fields);

    $mult = shift @rest;
    @rows = @rest;

    initialize();
    initialize_graph($image);

    $q = "select fieldname,fieldshdesc from fields where fieldtable = '" . $table . "'";
    logdie "(graph_mult_by_mult) Stopping\n" unless $fields = doq($perfdb, $q, PGRES_TUPLES_OK);

    $table .= "_d" if $graph_len eq "day";
    $table .= "_w" if $graph_len eq "week";
    $table .= "_m" if $graph_len eq "month";
    $table .= "_y" if $graph_len eq "year";

    $max_y = 0;
    $q = "select max(" . $rows[0] . ")";
    for ($i = 1; $i < scalar(@rows); $i++)
    {
        $q .= ", max(" . $rows[$i] . ")";
    }
    $q .= " from " . $table . " where " . $fields->getvalue(1, 0) . " = '" . $mult . "'";
    $q .= " and tstamp >= " . $x_start_time;
    $q .= " and tstamp <= " . $x_end_time;
    logdie "(graph_mult_by_mult) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    for ($i = 0; $i < scalar(@rows); $i++)
    {
        $max_y = max($max_y, $result->getvalue(0, $i));
    }
    label_y_axis($image, $max_y);

    $q = "select tstamp";
    for ($i = 0; $i < scalar(@rows); $i++)
    {
        $q .= ", " . $rows[$i];
    }
    $q .= " from " . $table . " where " . $fields->getvalue(1, 0) . " = '" . $mult . "'";
    $q .= " and tstamp >= " . $x_start_time;
    $q .= " and tstamp <= " . $x_end_time;
    $q .= " order by tstamp";

    for ($i = 0; $i < scalar(@rows); $i++)
    {
        for ($j = 0; $rows[$i] ne $fields->getvalue($j, 0); $j++) {}
        plot_data($image, $colors[$i], $mult . " - " . $fields->getvalue($j, 1), $i + 1, "lines", $q);
    }
    drawgif($image);
}

sub graph_mult_by_val($)
{
    my $image = shift @_;
    my($i, $q, $max_y, $j, $row, @mult, @mult2, $m, $fields);

    $row = shift @rest;
    @mult = @mult2 = @rest;

    initialize();
    initialize_graph($image);

    $q = "select fieldname,fieldshdesc from fields where fieldtable = '" . $table . "'";
    logdie "(graph_mult_by_val) Stopping\n" unless $fields = doq($perfdb, $q, PGRES_TUPLES_OK);

    $table .= "_d" if $graph_len eq "day";
    $table .= "_w" if $graph_len eq "week";
    $table .= "_m" if $graph_len eq "month";
    $table .= "_y" if $graph_len eq "year";

    $max_y = 0;
    $q = "select max(" . $row . ")";
    $q .= " from " . $table . " where " . $fields->getvalue(1, 0) . " in ('" . (shift @mult) . "'";
    foreach $m (@mult)
    {
       $q .= ", '" . $m . "'";
    }
    $q .= ")";
    $q .= " and tstamp >= " . $x_start_time;
    $q .= " and tstamp <= " . $x_end_time;
    logdie "(graph_mult_by_val) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    $max_y = $result->getvalue(0, 0);
    label_y_axis($image, $max_y);

    $i = 0;
    foreach $m (@mult2)
    {
        $q = "select tstamp, " . $row;
        $q .= " from " . $table;
        $q .= " where tstamp >= " . $x_start_time;
        $q .= " and tstamp <= " . $x_end_time;
        $q .= " and " . $fields->getvalue(1, 0) . " = '" . $m . "'";
        $q .= " order by tstamp";

        for ($j = 0; $row ne $fields->getvalue($j, 0); $j++) {}
        plot_data($image, $colors[$i++], $m . " - " . $fields->getvalue($j, 1), 1, "lines", $q);
    }
    drawgif($image);
}

sub graph_gen($)
{
    my ($image) = @_;
    my($i, $q, $max_y, $j, $fields, $userfields);

    initialize();
    initialize_graph($image);

    if ($table eq "usertbl")
    {
        $q = "select fieldname,fieldshdesc from userfldnames";
        logdie "(graph_gen) Stopping\n" unless $fields = doq($conn, $q, PGRES_TUPLES_OK);
    }
    else
    {
        $q = "select fieldname,fieldshdesc from fields where fieldtable = '$table'";
        logdie "(graph_gen) Stopping\n" unless $fields = doq($perfdb, $q, PGRES_TUPLES_OK);
    }

    $table .= "_d" if $graph_len eq "day";
    $table .= "_w" if $graph_len eq "week";
    $table .= "_m" if $graph_len eq "month";
    $table .= "_y" if $graph_len eq "year";

    @rows = @rest;

    $max_y = 0;
    $q = "select max(" . $rows[0] . ")";
    for ($i = 1; $i < scalar(@rows); $i++)
    {
        $q .= ", max(" . $rows[$i] . ")";
    }
    $q .= " from " . $table . " where tstamp >= " . $x_start_time;
    $q .= " and tstamp <= " . $x_end_time;
    logdie "(graph_gen) Stopping\n" unless $result = doq($conn, $q, PGRES_TUPLES_OK);
    for ($i = 0; $i < scalar(@rows); $i++)
    {
        $max_y = max($max_y, $result->getvalue(0, $i));
    }
    label_y_axis($image, $max_y);

    $q = "select tstamp";
    for ($i = 0; $i < scalar(@rows); $i++)
    {
        $q .= ", " . $rows[$i];
    }
    $q .= " from " . $table;
    $q .= " where tstamp >= " . $x_start_time;
    $q .= " and tstamp <= " . $x_end_time;
    $q .= " order by tstamp";

    for ($i = 0; $i < scalar(@rows); $i++)
    {
        for ($j = 0; $rows[$i] ne $fields->getvalue($j, 0); $j++) {}
        plot_data($image, $colors[$i], $fields->getvalue($j, 1), $i + 1, "lines", $q);
    }
    drawgif($image);
}

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

sub get_config()
{
    my $q;
    my $i;
    my $result;

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

    # Find out what systems we have to serve
    $q = "select hostname,systype,nickname from systems";
    $result = $perfdb->exec($q);

    undef @systems;
    foreach $i (0 .. $result->ntuples - 1)
    {
        $systems[$i][0] = $result->getvalue($i, 0);
        $systems[$i][1] = Pg::connectdb("dbname = " . $systems[$i][0]);
        if ($systems[$i][1]->status == PGRES_CONNECTION_BAD)
        {
            logdie "Cannot open database connection: " . $systems[$i][1]->errorMessage . "\n";
        }
        $systems[$i][2] = $result->getvalue($i, 1);
        $systems[$i][3] = $result->getvalue($i, 2);
    }
    $timezone = `date +%Z`;
    chomp($timezone);

    $SIG{HUP} = \&get_config;
}

sub set_conn($)
{
    my $host = shift @_;
    my $i;

    undef $conn;

    foreach $i (0 .. scalar(@systems) - 1 )
    {
        $conn     = $systems[$i][1] if $systems[$i][0] eq $host;
        $nickname = $systems[$i][3] if $systems[$i][0] eq $host;
    }

    if (! defined($conn) )
    {
        print STDOUT "Content-type: text/html\n\n";
        print STDOUT "<HTML>
         <HEAD>
          <TITLE>System performance monitor grapher</TITLE>
          <style>\n$style_right</style>
         </HEAD>
    
         <body vlink='#0000ff'>
         The system '" . $nickname . "' does not exist.
         </body>
        </HTML>";

        return 0;
    }

    if (-e "$PGDIR/tmp/backup.lock")
    {
        print STDOUT "Refresh: " . (5 * 60) . "\n";
        print STDOUT "Expires: " . mk_expiry(time) . "\n";
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
        print STDOUT "<HTML>
         <HEAD>
          <TITLE>System performance monitor grapher</TITLE>
          <style>\n$style_right</style>
         </HEAD>
    
         <body vlink='#0000ff'>
         A backup is running on the PerfGraph collection server.
         Please try again later.
         </body>
        </HTML>";

        return 0;
    }

    if (-e "$PGDIR/tmp/$host.lock")
    {
        print STDOUT "Refresh: " . (5 * 60) . "\n";
        print STDOUT "Expires: " . mk_expiry(time) . "\n";
        print STDOUT "Pragma: no-cache\n";
        print STDOUT "Content-type: text/html\n\n";
        print STDOUT "<HTML>
         <HEAD>
          <TITLE>System performance monitor grapher</TITLE>
          <style>\n$style_right</style>
         </HEAD>
    
         <body vlink='#0000ff'>
         The system '" . $nickname . "' is being cleaned up.
         Please try again later.
         </body>
        </HTML>";

        return 0;
    }

    return 1;
}

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

get_config();
$save_pg_cgi = $PG_CGI;

open (STDERR, ">>$PGDIR/logs/perfgraphd.log");

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

logmsg "perfgraphd started\n";

while (1)
{
    $ln = <STDIN>;
    @args = split(" ", $ln);
    $action = shift @args;
    $ripper=0;  # will be set to 1 when getting data out of perfgraph for the Internet demo.
    $PG_CGI = $save_pg_cgi;

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

        if (not $action)                  { srv_frame; }
        elsif ($action =~ /helo/i)        { print STDOUT "SV-PERF\n"; }
        elsif ($action =~ /rip-empty/i)   { $PG_CGI=""; $ripper=1; srv_empty(@args); }
        elsif ($action =~ /rip-systems/i) { $PG_CGI=""; $ripper=1; srv_systems(@args); }
        elsif ($action =~ /rip-table/i)   { $PG_CGI=""; $ripper=1; set_conn($args[0]) && srv_table(@args); }
        elsif ($action =~ /rip-draw/i)    { $PG_CGI=""; $ripper=1; set_conn($args[0]) && srv_draw(@args); }
        elsif ($action =~ /rip-logo/i)    { $PG_CGI=""; $ripper=1; srv_logo; }
        elsif ($action =~ /header/i)      { srv_header(@args); }
        elsif ($action =~ /empty/i)       { srv_empty(@args); }
        elsif ($action =~ /syslist/i)     { srv_systems(@args); }
        elsif ($action =~ /systems/i)     { srv_oldhtml(@args); }
        elsif ($action =~ /table/i)       { set_conn($args[0]) && srv_table(@args); }
        elsif ($action =~ /draw/i)        { set_conn($args[0]) && srv_draw(@args); }
        elsif ($action =~ /help/i)        { srv_help(@args); }
        elsif ($action =~ /logo/i)        { srv_logo; }
        else  { logmsg "Unknown action '$action'\n" };
        print "__END__";

        alarm 0;
    };

    if ($@ eq "alarm\n")
    {
        logdie "Timeout while serving data - restart\n";
    }
}
