#!/usr/bin/perl -w eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}' if 0; # not running under some shell use strict; use Data::Dumper; use Schedg::SchedgTime; use POSIX qw(strftime setuid setgid getuid getgid geteuid getegid); use Digest::MD5; use File::Spec::Functions; use File::stat; use English; use Getopt::Long; ### DEFAULT OPTIONS my $progtitle = "Schedg_Client"; $0 = $progtitle . " " . join(" ",@ARGV); our ( $opt_server, $opt_filer, $opt_datadir, $opt_fatdir, $opt_sumdir, $opt_outdir, $opt_debug, $opt_sharc, $opt_hubname, $opt_soap, $opt_daemon, $opt_ssh, $opt_sshport, $opt_sshuser, $opt_configfile, $opt_user ); my $configs = { user => "schedg", server => "localhost", serverport => "43012", filer => "", filerport => "", datadir => "/tmp/Schedg/data/", fatdir => "/tmp/Schedg/data/fats/", sumdir => "/tmp/Schedg/data/sums/", outdir => "/tmp/Schedg/data/sums/", sharc => "/usr/bin/sharc", debug => "100", hubname => "", daemon => 0, soap => 1, ssh => 0, sshport => 22, sshuser => "schedg", }; ### my @options = qw( user=s configfile=s server=s filer=s datadir=s fatdir=s sumdir=s outdir=s debug=i sharc=s hubname=s ssh! sshport=i sshuser=s soap! daemon! ); my $return = GetOptions(@options); die "UNSuccessful argument parsing\n" unless ($return); if (defined($opt_configfile)) { die "Cannot find $opt_configfile\n" unless (-f $opt_configfile); ReadConfig($opt_configfile,$configs); } #Parse all of the options my $soap = (defined($opt_soap)) ? $opt_soap : $configs->{soap}; my $daemon = (defined($opt_daemon)) ? $opt_daemon : $configs->{daemon}; my $ssh = (defined($opt_ssh)) ? $opt_ssh : $configs->{ssh}; my $sshport = (defined($opt_sshport)) ? $opt_sshport : $configs->{sshport}; my $sshuser = (defined($opt_sshuser)) ? $opt_sshuser : $configs->{sshuser}; my $debug = (defined($opt_debug)) ? $opt_debug : $configs->{debug}; my $hubname = (defined($opt_hubname)) ? $opt_hubname : $configs->{hubname}; my $user = (defined($opt_user)) ? $opt_user : $configs->{user}; my $sharc = (defined($opt_sharc)) ? $opt_sharc : $configs->{sharc}; my $datadir = (defined($opt_datadir)) ? $opt_datadir : $configs->{datadir}; my $fatdir = (defined($opt_fatdir)) ? $opt_fatdir : $configs->{fatdir}; my $sumdir = (defined($opt_sumdir)) ? $opt_sumdir : $configs->{sumdir}; my $outdir = (defined($opt_outdir)) ? $opt_outdir : $configs->{outdir}; my $tmpsrvr = (defined($opt_server)) ? $opt_server : $configs->{server}; my $tmpfilr = (defined($opt_filer)) ? $opt_filer : $configs->{filer}; ## ## Quit if no hubname supplied ## die "No hubname specified\n" if ($hubname eq ""); ## ##Try and set user or die if not possible ## die "Do not run as root" if ($user eq "root"); my $uid = getpwnam($user); my $gid = getgrnam($user); die "Cannot get uid for $user" unless ($uid); die "Cannot get gid for $user" unless ($gid); die "Cannot setuid to 0" if ($uid eq 0); die "Cannot setgid to 0" if ($gid eq 0); setuid($uid); setgid($gid); $EUID = $uid; $EGID = $gid; die "Set UID failed" if (getuid() != $uid); die "Set GID failed" if (getgid() != $gid); die "Set EUID failed" if (geteuid() != $uid); die "Set EGID failed" if (getegid() != $gid); die "Cannot run as group root" if (getgid() == 0); die "Cannot run as user root" if (getuid() == 0); die "Cannot run as group root" if (getegid() == 0); die "Cannot run as user root" if (geteuid() == 0); ## ##die if sharc doesn't exist ## die "Cannot find sharc executable: $sharc" unless (-x $sharc); ## ##Verify Data Dir, must be writable ## $datadir .= "/" unless ($datadir =~ /\/$/); die "$datadir may not exist or may not have correct permissions" unless (-d $datadir && -r _ && -w _); ## ##Verify Fat Dir, set to DataDir if not exist ## $fatdir .= "/" unless ($fatdir =~ /\/$/); unless (-d $fatdir && -r _ && -w _) { print "Problem with $fatdir, setting to $datadir\n"; $fatdir = $datadir; } ## ##Verify SUM Dir, set to DataDir if not exist ## $sumdir .= "/" unless ($sumdir =~ /\/$/); unless (-d $sumdir && -r _ && -w _) { print "Problem with $sumdir, setting to $datadir\n"; $sumdir = $datadir; } ## ##Verify OUT Dir, set to sumdir if not exist ## $outdir .= "/" unless ($outdir =~ /\/$/); unless (-d $outdir && -r _ && -w _) { print "Problem with $outdir, setting to $sumdir\n"; $outdir = $sumdir; } ## ##Get Server ## $_ = $tmpsrvr; my ($server, $serverport) = (/(\S+):(\d+)/) ? ($1, $2) : ($_, $configs->{serverport}); ## ##Get Filer location ## $_ = $tmpfilr; my ($filer, $filerport) = (/(\S+):(\d+)/) ? ($1, $2) : ($_, $configs->{filerport}); $filer = $server if ($filer eq ""); $filerport = $serverport+1 if ($filerport eq ""); ## ##Only use SSH if SOAP is enabled ## die "Must use soap if you want to use ssh" if ($ssh && !$soap); my $ssh1_pid; if ( $soap ) { if ($ssh) { $ssh1_pid = open(SSH1,"/usr/bin/ssh $sshuser\@$server -N -T -L $filerport:$filer:$filerport -L $serverport:$server:$serverport -p $sshport |"); $server = "localhost"; $filer = "localhost"; sleep(30); } require "SOAP/Lite.pm"; import SOAP::Lite +autodispatch => uri => 'http://schedgserver/Server', proxy => 'http://' . $server . ":" . $serverport, on_fault => sub { my ($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; }; } else { $ssh = 0; require "Schedg/Schedg.pm"; require "Schedg/Filer.pm"; } my $processid = $$; my $process_time = time(); print "Connecting to $server using $hubname\n"; my $Schedg = Schedg::Schedg->new($hubname); print "Calling releaseLocks\n"; $Schedg->releaseLocks(); undef $Schedg; do { if ($soap) { import SOAP::Lite +autodispatch => uri => 'http://schedgserver/Server', proxy => 'http://' . $server . ":" . $serverport, on_fault => sub { my ($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; }; } $Schedg = Schedg::Schedg->new($hubname); while ((my $sleeptime = $Schedg->setupJob()) != 0) { print "Sleeping for $sleeptime\n"; sleep($sleeptime); } my ($code, $port, $site, $comm, $file, $tasks, $sessions) = $Schedg->getAllJobInfo(); my $down = $tasks->{download}; my $dele = $tasks->{delete}; my $conf = $tasks->{configure}; my $curtime = time(); my $tmp_time = Schedg::SchedgTime->new("s",$curtime); $_ = $file->{filetemplate}; s/\+G/%G/g; s/\+g/%g/g; s/\+s/a/g; s/\..{1,5}$//g; my $localtemplate = $tmp_time->strftime($_); my $fatname = $localtemplate . ".fat"; my $sumname = $localtemplate . ".sum"; my $outname = $localtemplate . ".sharc"; my $fatfile = $fatdir . $fatname; my $sumfile = $sumdir . $sumname; my $outfile = $outdir . $outname; unlink $fatfile if (-f $fatfile); unlink $sumfile if (-f $sumfile); unlink $outfile if (-f $outfile); my $command_line = $sharc; $command_line .= " --debug $debug"; $command_line .= " --debugfile $outfile"; $command_line .= " --verifycode $code"; $command_line .= " --port \"$port->{device}\""; $comm->{baud} = $port->{baud} if ($comm->{baud} eq ""); $command_line .= " --baud \"$comm->{baud}\""; $command_line .= " --filetemplate \"$file->{filetemplate}\""; $command_line .= " --datadir \"$datadir\""; $command_line .= " --fatfile \"$fatfile\""; $command_line .= " --sumfile \"$sumfile\""; foreach my $session (@{$sessions}) { my $start = $session->{start}; my $stop = $session->{stop}; my $mask = $session->{mask}; my $minsv = $session->{minsv}; my $sample = $session->{sample}; $command_line .= " --session \"$start,$stop,$sample,$mask,$minsv\""; } $command_line .= " --filetimefrom \"request start\""; SWITCH: for ($comm->{connecttype}) { /freewave/i && do { $command_line .= " --connectvia freewave --phonenumber \"$comm->{freewave}\""; $command_line .= " --Cfr $comm->{repeater1}" if ($comm->{repeater1} ne ""); $command_line .= ",$comm->{repeater2}" if ($comm->{repeater2} ne ""); last SWITCH; }; /pots/i && do { $command_line .= " --connectvia modem --phonenumber \"$port->{prefix}$comm->{area_code}$comm->{phone_num}\""; last SWITCH; }; } foreach my $downRef (@{$down}) { my $spanstart = strftime "%Y/0/%j:%T-", gmtime($downRef->{start_time}); my $spanstop = strftime "%Y/0/%j:%T", gmtime($downRef->{stop_time}); my $session = $downRef->{session}; my $span = $spanstart . $spanstop; $command_line .= " --download \"$span $session\""; } foreach my $deleteRef (@{$dele}) { my $spanstart = strftime "%Y/0/%j:%T-", gmtime($deleteRef->{start_time}); my $spanstop = strftime "%Y/0/%j:%T", gmtime($deleteRef->{stop_time}); my $span = $spanstart . $spanstop; $command_line .= " --purge \"$span\""; } my $output = ""; print "Running $command_line\n"; open(SHARC,"$command_line |"); my $tmp = ""; while(read(SHARC,$tmp,1)) { print $tmp; } close(SHARC); my $elaps = time() - $process_time; print "elapsed = $elaps\n"; my @downresults; my @delresults; if (open(SUM,"< $sumfile")) { while () { print; push(@downresults, $1) if (/DOWNLOAD RESULT:(.*)/); push(@delresults, $1) if (/DELETE RESULT:(.*)/); } } close(SUM); my $download = []; foreach (@downresults) { my @line = split; my $range = shift(@line); my $status = pop(@line); my @filenames = @line; my ($s, $e); if ($range =~ /(\d+)\/(\d+)-(\d+)\/(\d+)/) { my ($sw, $ss, $ew, $es) = ($1, $2, $3, $4); my $tmp = Schedg::SchedgTime->new("GWS",$sw, $ss); $s = $tmp->unix_seconds_since_epoch(); $tmp = Schedg::SchedgTime->new("GWS",$ew, $es); $e = $tmp->unix_seconds_since_epoch(); } if ($status eq "SUCCESS") { my $tmp = { start_time => $s, stop_time => $e, status => "success", numfiles => -1, files => [ ] }; foreach my $file (@filenames) { print "Checking file: $file\n"; my $ff = catfile($datadir, $file); my $sb = stat($ff); if (! $sb ) { print "Problem getting stat of $ff\n"; next; } next unless (open(MD5,"<$ff")); my $ctx = Digest::MD5->new; $ctx->addfile(*MD5); if ($sb->size > 0) { my $filetmp = { filename => $file, size => $sb->size, md5sum => $ctx->hexdigest, dir => $datadir }; push(@{$tmp->{files}}, $filetmp); $tmp->{numfiles} = $#{$tmp->{files}}; } } $return = filetransfer($code,$tmp,"data"); push(@{$download}, $tmp) if ($return == 0); } } $tmp = { start_time => $curtime, stop_time => $curtime, status => "success", numfiles => -1, files => [ ] }; foreach my $file ($sumname, $outname, $fatname) { my $tmpdir = ""; $tmpdir = $sumdir if ($file eq $sumname); $tmpdir = $outdir if ($file eq $outname); $tmpdir = $fatdir if ($file eq $fatname); print "Checking file: $file\n"; my $ff = catfile($tmpdir, $file); my $sb = stat($ff); if (! $sb ) { print "Problem getting stat of $ff\n"; next; } next unless (open(MD5,"<$ff")); my $ctx = Digest::MD5->new; $ctx->addfile(*MD5); if ($sb->size > 0) { my $filetmp = { filename => $file, size => $sb->size, md5sum => $ctx->hexdigest, dir => $tmpdir }; push(@{$tmp->{files}}, $filetmp); $tmp->{numfiles} = $#{$tmp->{files}}; } } my $return = filetransfer($code,$tmp,"status"); # push(@{$download}, $tmp) if ($return == 0); my $delete = []; foreach (@delresults) { my ($range, $status) = split; my ($s, $e); if ($range =~ /(\d+)\/(\d+)-(\d+)\/(\d+)/) { my ($sw, $ss, $ew, $es) = ($1, $2, $3, $4); my $tmp = Schedg::SchedgTime->new("GWS",$sw, $ss); $s = $tmp->unix_seconds_since_epoch(); $tmp = Schedg::SchedgTime->new("GWS",$ew, $es); $e = $tmp->unix_seconds_since_epoch(); } if ($status eq "SUCCESS") { my $tmp = { start_time => $s, stop_time => $e, status => "success", }; push(@{$delete}, $tmp); } } my $conf_status = { start_time => 0, stop_time => time() }; my $retval = { download => $download, delete => $delete, configure => [ $conf_status ], }; $Schedg->releaseJob($retval); } while ($daemon); if ($ssh) { kill 15, $ssh1_pid; waitpid($ssh1_pid,0); close(SSH1); sleep 5; } sleep 2; exit(); sub filetransfer { my $site = shift; my $info = shift; my $type = shift; return(0) if ($info->{numfiles} < 0); my $return = 1; my $start = $info->{start_time}; my $stop = $info->{stop_time}; if ( $soap ) { print "Setting Filer to $filer:$filerport\n"; import SOAP::Lite +autodispatch => uri => 'http://schedgserver/Filer', proxy => 'http://' . $filer . ":" . $filerport, on_fault => sub { my ($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; }; } foreach my $file (@{$info->{files}}) { my $info = { filename => $file->{filename}, size => $file->{size}, md5sum => $file->{md5sum}, type => $type, data => "" }; my $ff = catfile($file->{dir}, $info->{filename}); open(FH,"< $ff") or return(1); binmode(FH); while () { $info->{data} .= $_; } return(1) unless ($info->{size} == length($info->{data})); print "Calling Filer $site, $start, $stop, $info->{filename}\n"; $return = Schedg::Filer->new($site, $start, $stop, $info); } if ($soap) { print "Restoring server setting to $server:$serverport\n"; import SOAP::Lite +autodispatch => uri => 'http://schedgserver/Server', proxy => 'http://' . $server . ":" . $serverport, on_fault => sub { my ($soap, $res) = @_; die ref $res ? $res->faultstring : $soap->transport->status, "\n"; }; } return($return); } sub ReadConfig { my $configfile = shift; my $configs = shift; open(HI, "<$configfile") || die "cannot open config file: $configfile\n"; while () { my ($variable, $value) = split; $configs->{$variable} = $value if (exists($configs->{$variable})); } return(); } __END__