--- loncom/lond 2003/12/02 10:37:59 1.164
+++ loncom/lond 2003/12/22 12:01:54 1.168
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.164 2003/12/02 10:37:59 foxr Exp $
+# $Id: lond,v 1.168 2003/12/22 12:01:54 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -10,7 +10,7 @@
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
@@ -52,7 +52,7 @@ my $DEBUG = 0; # Non zero to ena
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.164 $'; #' stupid emacs
+my $VERSION='$Revision: 1.168 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid;
my $currentdomainid;
@@ -162,37 +162,42 @@ sub ReadManagerTable {
# Clean out the old table first..
- foreach my $key (keys %managers) {
- delete $managers{$key};
- }
-
- my $tablename = $perlvar{'lonTabDir'}."/managers.tab";
- if (!open (MANAGERS, $tablename)) {
- logthis('No manager table. Nobody can manage!!');
- return;
- }
- while(my $host = ) {
- chomp($host);
- if (!defined $hostip{$host}) { # This is a non cluster member
-
+ foreach my $key (keys %managers) {
+ delete $managers{$key};
+ }
+
+ my $tablename = $perlvar{'lonTabDir'}."/managers.tab";
+ if (!open (MANAGERS, $tablename)) {
+ logthis('No manager table. Nobody can manage!!');
+ return;
+ }
+ while(my $host = ) {
+ chomp($host);
+ if ($host =~ "^#") { # Comment line.
+ logthis(' Skipping line: '. "$host\n");
+ next;
+ }
+ if (!defined $hostip{$host}) { # This is a non cluster member
# The entry is of the form:
# cluname:hostname
# cluname - A 'cluster hostname' is needed in order to negotiate
# the host key.
# hostname- The dns name of the host.
#
-
- my($cluname, $dnsname) = split(/:/, $host);
- open(MGRPIPE, "/usr/bin/host $dnsname |") || die "Can't make host pipeline";
- my $dnsinfo = ;
- chomp $dnsinfo;
- close MGRPIPE;
- my($jname, $jhas, $jaddress, $hostip) = split(/ /, $dnsinfo);
- $managers{$hostip} = $cluname;
- } else {
- $managers{$hostip{$host}} = $host; # Use info from cluster tab if clumemeber
- }
- }
+ my($cluname, $dnsname) = split(/:/, $host);
+
+ my $ip = gethostbyname($dnsname);
+ if(defined($ip)) { # bad names don't deserve entry.
+ my $hostip = inet_ntoa($ip);
+ $managers{$hostip} = $cluname;
+ logthis(' registering manager '.
+ "$dnsname as $cluname with $hostip \n");
+ }
+ } else {
+ logthis(' existing host'." $host\n");
+ $managers{$hostip{$host}} = $host; # Use info from cluster tab if clumemeber
+ }
+ }
}
#
@@ -279,42 +284,30 @@ sub AdjustHostContents {
my $adjusted;
my $me = $perlvar{'lonHostID'};
- foreach my $line (split(/\n/,$contents)) {
+ foreach my $line (split(/\n/,$contents)) {
if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {
chomp($line);
my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
if ($id eq $me) {
- open(PIPE, " /usr/bin/host $name |") || die "Cant' make host pipeline";
- my $hostinfo = ;
- close PIPE;
-
- my ($hostname, $has, $address, $ipnew) = split(/ /,$hostinfo);
- &logthis(''.
- "hostname = $hostname me = $me, name = $name actual ip = $ipnew ");
-
- if ($hostname eq $name) { # Lookup succeeded..
- &logthis(' look up ok ');
- $ip = $ipnew;
- } else {
- &logthis(' Lookup failed: '
- .$hostname." ne $name ");
- }
+ my $ip = gethostbyname($name);
+ my $ipnew = inet_ntoa($ip);
+ $ip = $ipnew;
# Reconstruct the host line and append to adjusted:
- my $newline = "$id:$domain:$role:$name:$ip";
- if($maxcon ne "") { # Not all hosts have loncnew tuning params
- $newline .= ":$maxcon:$idleto:$mincon";
- }
- $adjusted .= $newline."\n";
+ my $newline = "$id:$domain:$role:$name:$ip";
+ if($maxcon ne "") { # Not all hosts have loncnew tuning params
+ $newline .= ":$maxcon:$idleto:$mincon";
+ }
+ $adjusted .= $newline."\n";
- } else { # Not me, pass unmodified.
- $adjusted .= $line."\n";
- }
+ } else { # Not me, pass unmodified.
+ $adjusted .= $line."\n";
+ }
} else { # Blank or comment never re-written.
$adjusted .= $line."\n"; # Pass blanks and comments as is.
}
- }
- return $adjusted;
+ }
+ return $adjusted;
}
#
# InstallFile: Called to install an administrative file:
@@ -483,7 +476,94 @@ sub ReinitProcess {
}
return 'ok';
}
+# Validate a line in a configuration file edit script:
+# Validation includes:
+# - Ensuring the command is valid.
+# - Ensuring the command has sufficient parameters
+# Parameters:
+# scriptline - A line to validate (\n has been stripped for what it's worth).
+#
+# Return:
+# 0 - Invalid scriptline.
+# 1 - Valid scriptline
+# NOTE:
+# Only the command syntax is checked, not the executability of the
+# command.
+#
+sub isValidEditCommand {
+ my $scriptline = shift;
+
+ # Line elements are pipe separated:
+
+ my ($command, $key, $newline) = split(/\|/, $scriptline);
+ &logthis(' isValideditCommand checking: '.
+ "Command = '$command', Key = '$key', Newline = '$newline' \n");
+
+ if ($command eq "delete") {
+ #
+ # key with no newline.
+ #
+ if( ($key eq "") || ($newline ne "")) {
+ return 0; # Must have key but no newline.
+ } else {
+ return 1; # Valid syntax.
+ }
+ } elsif (($command eq "append") || ($command eq "replace")) {
+ #
+ # key and newline:
+ #
+ if (($key eq "") || ($newline eq "")) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ return 0; # Invalid command.
+ }
+ return 0; # Should not get here!!!
+}
+
+#
+#
+# Called to edit a configuration table file
+# Parameters:
+# request - The entire command/request sent by lonc or lonManage
+# Return:
+# The reply to send to the client.
+#
+sub EditFile {
+ my $request = shift;
+
+ # Split the command into it's pieces: edit:filetype:script
+
+ my ($request, $filetype, $script) = split(/:/, $request,3); # : in script
+
+ # Check the pre-coditions for success:
+
+ if($request != "edit") { # Something is amiss afoot alack.
+ return "error:edit request detected, but request != 'edit'\n";
+ }
+ if( ($filetype ne "hosts") &&
+ ($filetype ne "domain")) {
+ return "error:edit requested with invalid file specifier: $filetype \n";
+ }
+
+ # Split the edit script and check it's validity.
+
+ my @scriptlines = split(/\n/, $script); # one line per element.
+ my $linecount = scalar(@scriptlines);
+ for(my $i = 0; $i < $linecount; $i++) {
+ chomp($scriptlines[$i]);
+ if(!isValidEditCommand($scriptlines[$i])) {
+ return "error:edit with bad script line: '$scriptlines[$i]' \n";
+ }
+ }
+
+ # Execute the edit operation.
+
+ return "ok\n";
+}
#
# Convert an error return code from lcpasswd to a string value.
#
@@ -513,6 +593,7 @@ sub catchexception {
my ($error)=@_;
$SIG{'QUIT'}='DEFAULT';
$SIG{__DIE__}='DEFAULT';
+ &status("Catching exception");
&logthis("CRITICAL: "
."ABNORMAL EXIT. Child $$ for server $thisserver died through "
."a crash with this error msg->[$error]");
@@ -523,6 +604,7 @@ sub catchexception {
}
sub timeout {
+ &status("Handling Timeout");
&logthis("CRITICAL: TIME OUT ".$$."");
&catchexception('Timeout');
}
@@ -579,6 +661,7 @@ my $children = 0; #
sub REAPER { # takes care of dead children
$SIG{CHLD} = \&REAPER;
+ &status("Handling child death");
my $pid = wait;
if (defined($children{$pid})) {
&logthis("Child $pid died");
@@ -587,25 +670,30 @@ sub REAPER { # ta
} else {
&logthis("Unknown Child $pid died");
}
+ &status("Finished Handling child death");
}
sub HUNTSMAN { # signal handler for SIGINT
+ &status("Killing children (INT)");
local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our children
kill 'INT' => keys %children;
&logthis("Free socket: ".shutdown($server,2)); # free up socket
my $execdir=$perlvar{'lonDaemons'};
unlink("$execdir/logs/lond.pid");
&logthis("CRITICAL: Shutting down");
+ &status("Done killing children");
exit; # clean up with dignity
}
sub HUPSMAN { # signal handler for SIGHUP
local($SIG{CHLD}) = 'IGNORE'; # we're going to kill our children
+ &status("Killing children for restart (HUP)");
kill 'INT' => keys %children;
&logthis("Free socket: ".shutdown($server,2)); # free up socket
&logthis("CRITICAL: Restarting");
my $execdir=$perlvar{'lonDaemons'};
unlink("$execdir/logs/lond.pid");
+ &status("Restarting self (HUP)");
exec("$execdir/lond"); # here we go again
}
@@ -667,6 +755,7 @@ sub ReloadApache {
# now be honored.
#
sub UpdateHosts {
+ &status("Reload hosts.tab");
logthis(' Updating connections ');
#
# The %children hash has the set of IP's we currently have children
@@ -691,10 +780,12 @@ sub UpdateHosts {
}
}
ReloadApache;
+ &status("Finished reloading hosts.tab");
}
sub checkchildren {
+ &status("Checking on the children (sending signals)");
&initnewstatus();
&logstatus();
&logthis('Going to check on the children');
@@ -709,6 +800,7 @@ sub checkchildren {
sleep 5;
$SIG{ALRM} = sub { die "timeout" };
$SIG{__DIE__} = 'DEFAULT';
+ &status("Checking on the children (waiting for reports)");
foreach (sort keys %children) {
unless (-e "$docdir/lon-status/londchld/$_.txt") {
eval {
@@ -726,6 +818,7 @@ sub checkchildren {
}
$SIG{ALRM} = 'DEFAULT';
$SIG{__DIE__} = \&catchexception;
+ &status("Finished checking children");
}
# --------------------------------------------------------------------- Logging
@@ -768,17 +861,20 @@ sub Reply {
# ------------------------------------------------------------------ Log status
sub logstatus {
+ &status("Doing logging");
my $docdir=$perlvar{'lonDocRoot'};
{
my $fh=IO::File->new(">>$docdir/lon-status/londstatus.txt");
print $fh $$."\t".$currenthostid."\t".$status."\t".$lastlog."\n";
$fh->close();
}
+ &status("Finished londstatus.txt");
{
my $fh=IO::File->new(">$docdir/lon-status/londchld/$$.txt");
print $fh $status."\n".$lastlog."\n".time;
$fh->close();
}
+ &status("Finished logging");
}
sub initnewstatus {
@@ -966,8 +1062,11 @@ ReadHostTable;
# along the connection.
while (1) {
+ &status('Starting accept');
$client = $server->accept() or next;
+ &status('Accepted '.$client.' off to spawn');
make_new_child($client);
+ &status('Finished spawning');
}
sub make_new_child {
@@ -976,6 +1075,7 @@ sub make_new_child {
my $sigset;
$client = shift;
+ &status('Starting new child '.$client);
&logthis(' Attempting to start child ('.$client.
")");
# block signal for fork
@@ -1204,22 +1304,41 @@ sub make_new_child {
}
#--------------------------------------------------------------------- reinit
} elsif($userinput =~ /^reinit/) { # Encoded and manager
- if (($wasenc == 1) && isManager) {
- my $cert = GetCertificate($userinput);
- if(ValidManager($cert)) {
- chomp($userinput);
- my $reply = ReinitProcess($userinput);
- print $client "$reply\n";
+ if (($wasenc == 1) && isManager) {
+ my $cert = GetCertificate($userinput);
+ if(ValidManager($cert)) {
+ chomp($userinput);
+ my $reply = ReinitProcess($userinput);
+ print $client "$reply\n";
+ } else {
+ print $client "refused\n";
+ }
} else {
- print $client "refused\n";
+ Reply($client, "refused\n", $userinput);
}
- } else {
- Reply($client, "refused\n", $userinput);
-
-
- }
+#------------------------------------------------------------------------- edit
+ } elsif ($userinput =~ /^edit/) { # encoded and manager:
+ if(($wasenc ==1) && (isManager)) {
+ my $cert = GetCertificate($userinput);
+ if(ValidManager($cert)) {
+ my($command, $filetype, $script) = split(/:/, $userinput);
+ if (($filetype eq "hosts") || ($filetype eq "domain")) {
+ if($script ne "") {
+ Reply($client, EditFile($userinput));
+ } else {
+ Reply($client,"refused\n",$userinput);
+ }
+ } else {
+ Reply($client,"refused\n",$userinput);
+ }
+ } else {
+ Reply($client,"refused\n",$userinput);
+ }
+ } else {
+ Reply($client,"refused\n",$userinput);
+ }
# ------------------------------------------------------------------------ auth
- } elsif ($userinput =~ /^auth/) { # Encoded and client only.
+ } elsif ($userinput =~ /^auth/) { # Encoded and client only.
if (($wasenc==1) && isClient) {
my ($cmd,$udom,$uname,$upass)=split(/:/,$userinput);
chomp($upass);