X-Git-Url: https://defaria.com/gitweb/?a=blobdiff_plain;f=clients%2FLynuxWorks%2Fbin%2Fecrd;fp=clients%2FLynuxWorks%2Fbin%2Fecrd;h=40e40573a1b7c1770dca429002a73dc8dc2ea1f4;hb=a8c84d2892f07a6863b68a11eb0a4a79ffd71fb5;hp=0000000000000000000000000000000000000000;hpb=95384f94f88aceeb5eef2d322210ba4a438b6512;p=clearscm.git diff --git a/clients/LynuxWorks/bin/ecrd b/clients/LynuxWorks/bin/ecrd new file mode 100644 index 0000000..40e4057 --- /dev/null +++ b/clients/LynuxWorks/bin/ecrd @@ -0,0 +1,564 @@ +#!/usr/bin/perl +################################################################################ +# +# File: ecrd: ECR Daemon +# Description: This script implements a daemon that handles requests for +# queries about information on ECRs contained in the Quintus +# database. In addition to lessoning the amount of time it takes +# for database opens, access to Quintus data is only available +# on certain machines. Additionally, for Perl to access this +# Informix database the Informix version of DBD would need to be +# locally installed. By calling this daemon instead clients need +# not have to install Informix and then code all the necessary +# code to access Quintus data as well as have to understand the +# structure of the database. Instead clients need only say "Give +# me what you got on ECR #". +# Author: Andrew@DeFaria.com +# Created: Tue Feb 15 09:54:59 PST 2005 +# Modified: +# Language: Perl +# +# (c) Copyright 2005, LynuxWorks, all rights reserved. +# +################################################################################ +use strict; +use warnings; + +use IO::Socket; +use Net::hostent; +use POSIX qw(setsid); +use DBI; + +my $ecrdb = "lynxmigr1"; +my $port = (!defined $ENV {ECRDPORT}) ? 1500 : $ENV {ECRDPORT}; + +# Global variables +my $DB; +my $ecrserver; +my $ecrclient; +my $sth; +my $statement; + +# Options +my $verbose; +my $debug; +my $daemon_mode; +my $quiet_mode; +my $multithreaded; +my $timeout = 10; + +# ECR translations. Note the Quintus database stores certain choice lists as +# enumerations. They I guess they are configurable. The right thing to do +# would be to figure out how to look up the definition given the number. But +# we are gonna cheat here and hard code a few important enumerations. +my @defstatus = ( + "Open", + "Closed", + "Fixed", + "Not a bug", + "Obsolete", + "Defered", + "Duplicate" +); +my @state = ( + "Reported", + "Assigned", + "Selected", + "Resolved", + "Integrated", + "Retired", + "Reviewed", + "Pending Review" +); +my @priority = ( + "Low", + "Medium", + "High", + "Critical" +); +my @severity = ( + "Low", + "Medium", + "High", + "Critical" +); + +# Pid +my $pid = $$; + +my $me = `basename $0`; +chomp $me; +my $ecrdversion = "1.3"; + +my @all_fields = ( + "productdefect", # integer + "componentdefect", # integer + "defectdefectdup", # integer + "workgroupdefect", # integer + "reporterdefect", # integer + "resolverdefect", # integer + "confirmerdefect", # integer + "buildversdefect", # integer + "rpt_versdefect", # integer + "res_versdefect", # integer + "conf_versdefect", # integer + "state", # integer + "resolverstatus", # integer + "confirmerstatus", # integer + "escstatus", # integer + "owner", # integer + "severity", # integer + "priority", # integer + "summary", # varchar(80,0) + "datereported", # datetime year to second + "dateresolved", # datetime year to second +# "description", # text +# Note: Some descriptions fields are huge containing things like +# uuencoded tar files! They are so huge that they cause this server +# to fail (not sure why - it shouldn't but it does. So this hack +# returns only the first 50K of description to avoid that problem. + "description [1,50000]", # text + "cclist", # varchar(80,0) + "dateconfirmed", # datetime year to second + "datemodified", # datetime year to second + "fix_by_date", # date + "fix_by_version", # integer + "history", # text + "likelihood", # integer + "estfixtime", # datetime year to second + "actfixtime", # datetime year to second + "resolution", # text + "businessimpact", # integer + "origin", # integer + "docimpact", # integer + "report_platform", # integer + "resolve_platform", # integer + "confirm_platform", # integer + "test_file", # varchar(64,0) + "visibility", # integer + "misc", # varchar(80,0) + "defecttype", # integer + "defstatus", # integer + "customertext", # text + "modifiedby", # varchar(20,0) + "classification", # integer + "datefixed" # datetime year to second +); + +# Forwards +sub CloseDB; +sub GetRequest; + +sub timestamp { + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + + $mday = "0$mday" if $mday < 10; + $mon = "0$mon" if $mon < 10; + $hour = "0$hour" if $hour < 10; + $min = "0$min" if $min < 10; + $year += 1900; + + return "$mon/$mday/$year $hour:$min"; +} # timestamp + +sub log_message { + print "[$pid] " . timestamp . " @_\n" if defined $verbose; +} # log_message + +sub log_error { + print STDERR "[$pid] " . timestamp . " ERROR: @_\n" +} # log_error + +sub log_warning { + print STDERR "[$pid] " . timestamp . " WARNING: @_\n" +} # log_error + +sub debug { + print "[$pid] " . timestamp . " @_\n" if defined $debug; +} # debug + +sub verbose { + print "[$pid] " . timestamp . " @_\n" if !defined $quiet_mode; +} # verbose + +sub DBError { + my $msg = shift; + my $statement = shift; + + if (!defined $DB) { + print "Catostrophic error: DB undefined!\n"; + exit 1; + } # if + + print $msg . "\nError #" . $DB->err . " " . $DB->errstr . "\n"; + print "SQL Statement: $statement\n" if defined $statement; + + exit $DB->err; +} # DBError + +sub timeout { + debug "After $timeout seconds of inactivity client timed out"; + + my $hostinfo = gethostbyaddr ($ecrclient->peeraddr); + my $host = $hostinfo->name || $ecrclient->peerhost; + debug "Closing connection to $host"; + + # Close client's connection + close $ecrclient; + + # Set up signal handlers again + $SIG{ALRM} = \&timeout; + $SIG{INT} = $SIG{QUIT} = 23234 +\&interrupt; + GetRequest; +} # timeout + +sub interrupt { + log_warning "Interrupted - closing down..."; + close $ecrserver; + verbose "Connection closed"; + CloseDB; + + exit; +} # interrupt + +sub GetClientAck { + my $client = shift; + my $clientresp; + + debug "ENTER: GetClientAck"; + alarm $timeout; + while (defined $client and defined ($clientresp = <$client>)) { + chomp $clientresp; + chop $clientresp if $clientresp =~ /\r/; + if ($clientresp eq "ACK") { + return + } # if + log_warning "Received $clientresp from client - expected ACK"; + } # while + debug "EXIT: GetClientAck"; +} # GetClientAck + +sub GetClientCmd { + my $client = shift; + my $clientresp; + + alarm $timeout; + while (defined $client and defined ($clientresp = <$client>)) { + chomp $clientresp; + return $clientresp; + } # while +} # GetClientResponse + +sub SendClientAck { + my $client = shift; + + debug "ENTER: SendClientAck"; + print $client "ACK\n"; + debug "EXIT: SendClientAck"; +} # SendClientAck + +sub SendClientResponse { + my $client = shift; + my $response = shift; + + print $client "$response\n"; +} # SendClientResponse + +sub EnterDaemonMode { + my $logfile = shift; + my $errorlog = shift; + + $logfile = "/dev/null" if $logfile eq ""; + $errorlog = "/dev/null" if $errorlog eq ""; + + # Change the current directory to / + chdir '/' + or die "$me: Error: Can't chdir to / ($!)"; + + # Turn off umask + umask 0; + + # Redirect STDIN to /dev/null + open STDIN, '/dev/null' + or die "$me: Error: Can't redirect /dev/null ($!)"; + + # Redirect STDOUT to logfile + open STDOUT, ">>$logfile" + or die "$me: Error: Can't redirect stdout to $logfile ($!)"; + + # Redirect STDERR to errorlog + open STDERR, ">>$errorlog" + or die "$me: Error: Can't redirect stderr to $errorlog ($!)"; + + # Now fork the daemon + defined (my $pid = fork) + or die "$me: Error: Can't create daemon ($!)"; + + # Now the parent exits + exit if $pid; + + # Set process to be session leader + setsid + or die "$me: Error: Can't start a new session ($!)"; +} # EnterDaemonMode + +sub OpenDB { + # Connect to database. Note this is using anonymous access (read only) + $DB = DBI->connect("DBI:Informix:$ecrdb") + or DBError "Unable to open database"; + log_message "Opened $ecrdb database"; + + # Setup our select statement with placeholders + $statement = "select "; + + # Build up the field list + my $first_time = 1; + foreach (@all_fields) { + if ($first_time) { + $first_time = 0; + $statement .= $_; + } else { + $statement .= ",$_"; + } # if + } # foreach + + # Now add the table and condition + $statement .= " from defect where pkey=?"; + + $sth = $DB->prepare ($statement) + or DBError "Unable to prepare statement", $statement; +} # OpenDB + +sub CloseDB { + $DB->disconnect () + or DBError "Unable to disconnect from database!"; + verbose "Closed $ecrdb database"; +} # CloseDB + +sub Usage { + my $msg = shift; + + print "$msg\n\n" if defined $msg; + + print "Usage: $me [ -D ] [ -v ] [ -d ] [-p ] [ -m ] [ -q ]\n\n"; + print "Where:\t-D\tEnter Daemon mode\n"; + print "\t-v\tVerbose mode (Default off)\n"; + print "\t-d\tDebug mode (Default off)\n"; + print "\t-p\tPort number to use (Default 1500)\n"; + print "\t-m\tMultithreaded (Default off)\n"; + print "\t-q\tQuiet mode (Default on)\n"; + exit 1; +} # Usage + +sub GetECRRecord { + my $ecr = shift; + + if ($ecr =~ /\D/) { + log_error "ECR $ecr is not numeric!"; + return (); + } # if + + my %fields; + my $record; + my $value; + + $sth->execute ($ecr) + or DBError "Unable to execute statement", $statement; + + my $row = $sth->fetchrow_arrayref; + + if (!defined $row) { + # @row is empty if there was no ECR by that number + log_error "ECR $ecr not found!"; + return (); + } # if + + my @rows = @{$row}; + foreach (@all_fields) { + my $value = shift @rows; + + # Transform newlines to "\n" so the field is treated as one large field + $value =~ s/\n/\\n/g if defined $value; + + # Perform some choice list field translations. Again this would be + # better done by doing database lookups to translate the enums... + $value = $defstatus [$value] if /defstatus/ and defined $value; + $value = $state [$value] if /state/ and defined $value; + $value = $priority [$value] if /priority/ and defined $value; + $value = $severity [$value] if /severity/ and defined $value; + # Fix description field back + if (/^description/) { + $_ = "description"; + } # if + $fields {$_} = $value + } # foreach + + return %fields; +} # GetECRRecord + +sub ServiceClient { + my $ecrclient = shift; + + # Service this client + my $hostinfo = gethostbyaddr ($ecrclient->peeraddr); + my $host = $hostinfo->name || $ecrclient->peerhost; + + verbose "Connect from $host"; + log_message "Waiting for command from $host"; + while () { + GetClientAck ($ecrclient); + $_ = GetClientCmd ($ecrclient); + next unless /\S/; # Skip blank requests + last if /quit|exit/i; + + if (/\*/) { + log_message "$host requests a list of all ECR #'s"; + SendClientAck ($ecrclient); + ReturnAllECRNbrs ($ecrclient); + SendClientAck ($ecrclient); + next; + } # if + + log_message "$host requests information about ECR $_"; + SendClientAck ($ecrclient); + my %fields = GetECRRecord $_; + + if (%fields) { + SendClientResponse ($ecrclient, "ecr: $_"); + while (my ($key, $value) = each (%fields)) { + $value = !defined $value ? "" : $value; + SendClientResponse ($ecrclient, "$key: $value"); + } # while + } else { + SendClientResponse ($ecrclient, "ECR $_ was not found"); + } # if + SendClientAck ($ecrclient); + } # while + + verbose "Closing connection from $host at client's request"; + close $ecrclient; +} # ServiceClient + +sub Funeral { + my $childpid = wait; + $SIG{CHLD} = \&Funeral; + log_message "Child has died" . ($? ? " with status $?" : ""); +} # Funeral + +sub GetRequest { + # Now wait for an incoming request + while ($ecrclient = $ecrserver->accept ()) { + my $hostinfo = gethostbyaddr ($ecrclient->peeraddr); + my $host = $hostinfo->name || $ecrclient->peerhost; + log_message "$host is requesting service"; + if (defined ($multithreaded)) { + my $childpid; + + log_message "Spawning child to handle request"; + + die "$me: ERROR: Can't fork: %!" unless defined ($childpid = fork ()); + + if ($childpid) { + # In parent - set up for clean up of child process + log_message "Parent produced child ($childpid)"; + $SIG{CHLD} = \&Funeral; + log_message "Parent looking for another request to service"; + } else { + # In child process - ServiceClient + $pid = $$; + debug "Child [$pid] has been born"; + ServiceClient ($ecrclient); + log_message "Child finished servicing requests"; + kill ("TERM", $$); + exit; + } # if + } else { + ServiceClient ($ecrclient); + } # if + } # while + + close ($ecrserver); +} # GetRequest + +sub ProcessRequests { + # The subroutine handles processing of requests by using a socket to + # communicate with clients. + $ecrserver = IO::Socket::INET->new ( + Proto => 'tcp', + LocalPort => $port, + Listen => SOMAXCONN, + Reuse => 1 + ); + + die "$me: Error: Could not create socket ($!)\n" unless $ecrserver; + + verbose "ECR DB Server (ecrd V$ecrdversion) accepting clients on port $port"; + + GetRequest; +} # ProcessRequests + +sub ReturnAllECRNbrs { + my $ecrclient = shift; + + my $statement = "select pkey from defect"; + + my $sth = $DB->prepare ($statement) + or DBError "Unable to prepare statement", $statement; + + $sth->execute () + or DBError "Unable to execute statement", $statement; + + log_message "Returning all ECR numbers..."; + while (my @row = $sth->fetchrow_array) { + SendClientResponse ($ecrclient, $row [0]); + } # while + + log_message "All ECR numbers returned"; +} # ReturnAllECRNbrs + +# Start main code +# Reopen STDOUT. +open STDOUT, ">-" or die "Unable to reopen STDOUT\n"; + +# Set unbuffered output +$| = 1; + +while ($ARGV [0]) { + if ($ARGV [0] eq "-D") { + $daemon_mode = 1; + } elsif ($ARGV [0] eq "-v") { + $verbose = 1; + undef ($quiet_mode); + } elsif ($ARGV [0] eq "-d") { + $debug = 1; + undef ($quiet_mode); + } elsif ($ARGV [0] eq "-m") { + $multithreaded = 1; + } elsif ($ARGV [0] eq "-q") { + $quiet_mode = 1; + undef ($verbose); + } elsif ($ARGV [0] eq "-p") { + shift @ARGV; + Usage "Must specify a port # after -p" if (!defined $ARGV [0]); + $port = $ARGV[0]; + } else { + Usage "Unknown parameter found: " . $ARGV[0]; + } # if + + shift @ARGV; +} # while + +my $tmp = (!defined $ENV {TMP}) ? "/tmp" : $ENV {TMP}; +my $ecrd_logfile = "$tmp/$me.log"; +my $ecrd_errfile = "$tmp/$me.err"; + +EnterDaemonMode ($ecrd_logfile, $ecrd_logfile) if defined ($daemon_mode); + +OpenDB; + +# Set up signal handlers +$SIG{ALRM} = \&timeout; +$SIG{INT} = $SIG{QUIT} = \&interrupt; + +ProcessRequests;