Annotation of loncom/loncron, revision 1.125

1.1       albertel    1: #!/usr/bin/perl
                      2: 
1.47      albertel    3: # Housekeeping program, started by cron, loncontrol and loncron.pl
                      4: #
1.125   ! raeburn     5: # $Id: loncron,v 1.124 2020/05/09 19:17:33 raeburn Exp $
1.47      albertel    6: #
                      7: # Copyright Michigan State University Board of Trustees
                      8: #
                      9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     10: #
                     11: # LON-CAPA is free software; you can redistribute it and/or modify
                     12: # it under the terms of the GNU General Public License as published by
                     13: # the Free Software Foundation; either version 2 of the License, or
                     14: # (at your option) any later version.
                     15: #
                     16: # LON-CAPA is distributed in the hope that it will be useful,
                     17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19: # GNU General Public License for more details.
                     20: #
                     21: # You should have received a copy of the GNU General Public License
                     22: # along with LON-CAPA; if not, write to the Free Software
                     23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     24: #
                     25: # /home/httpd/html/adm/gpl.txt
                     26: #
                     27: # http://www.lon-capa.org/
1.1       albertel   28: #
1.24      www        29: 
                     30: $|=1;
1.48      albertel   31: use strict;
1.1       albertel   32: 
1.26      harris41   33: use lib '/home/httpd/lib/perl/';
                     34: use LONCAPA::Configuration;
1.96      raeburn    35: use LONCAPA::Checksumming;
1.89      raeburn    36: use LONCAPA;
1.116     raeburn    37: use LONCAPA::LWPReq;
1.72      albertel   38: use Apache::lonnet;
1.79      raeburn    39: use Apache::loncommon;
1.26      harris41   40: 
1.1       albertel   41: use IO::File;
                     42: use IO::Socket;
1.48      albertel   43: use HTML::Entities;
1.49      albertel   44: use Getopt::Long;
1.104     raeburn    45: use GDBM_File;
                     46: use Storable qw(thaw);
1.114     raeburn    47: use File::ReadBackwards;
1.117     raeburn    48: use File::Copy;
1.123     raeburn    49: use Sys::Hostname::FQDN();
                     50: 
1.46      albertel   51: #globals
                     52: use vars qw (%perlvar %simplestatus $errors $warnings $notices $totalcount);
                     53: 
                     54: my $statusdir="/home/httpd/html/lon-status";
                     55: 
1.1       albertel   56: 
                     57: # --------------------------------------------------------- Output error status
                     58: 
1.46      albertel   59: sub log {
                     60:     my $fh=shift;
                     61:     if ($fh) {	print $fh @_  }
                     62: }
                     63: 
1.1       albertel   64: sub errout {
                     65:    my $fh=shift;
1.46      albertel   66:    &log($fh,(<<ENDERROUT));
1.48      albertel   67:      <table border="2" bgcolor="#CCCCCC">
1.1       albertel   68:      <tr><td>Notices</td><td>$notices</td></tr>
                     69:      <tr><td>Warnings</td><td>$warnings</td></tr>
                     70:      <tr><td>Errors</td><td>$errors</td></tr>
1.48      albertel   71:      </table><p><a href="#top">Top</a></p>
1.1       albertel   72: ENDERROUT
                     73: }
                     74: 
1.73      albertel   75: sub rotate_logfile {
                     76:     my ($file,$fh,$description) = @_;
                     77:     my $size=(stat($file))[7];
                     78:     if ($size>40000) {
                     79: 	&log($fh,"<p>Rotating $description ...</p>");
                     80: 	rename("$file.2","$file.3");
                     81: 	rename("$file.1","$file.2");
                     82: 	rename("$file","$file.1");
1.125   ! raeburn    83:     }
1.73      albertel   84: }
                     85: 
1.42      albertel   86: sub start_daemon {
1.50      albertel   87:     my ($fh,$daemon,$pidfile,$args) = @_;
1.44      albertel   88:     my $progname=$daemon;
1.71      albertel   89:     if ($daemon eq 'lonc') {
1.125   ! raeburn    90: 	$progname='loncnew';
1.44      albertel   91:     }
1.51      albertel   92:     my $error_fname="$perlvar{'lonDaemons'}/logs/${daemon}_errors";
1.73      albertel   93:     &rotate_logfile($error_fname,$fh,'error logs');
1.74      albertel   94:     if ($daemon eq 'lonc') {
                     95: 	&clean_sockets($fh);
                     96:     }
1.51      albertel   97:     system("$perlvar{'lonDaemons'}/$progname 2>$perlvar{'lonDaemons'}/logs/${daemon}_errors");
1.60      albertel   98:     sleep 1;
1.42      albertel   99:     if (-e $pidfile) {
1.48      albertel  100: 	&log($fh,"<p>Seems like it started ...</p>");
1.42      albertel  101: 	my $lfh=IO::File->new("$pidfile");
                    102: 	my $daemonpid=<$lfh>;
                    103: 	chomp($daemonpid);
1.62      albertel  104: 	if ($daemonpid =~ /^\d+$/ && kill 0 => $daemonpid) {
1.42      albertel  105: 	    return 1;
                    106: 	} else {
                    107: 	    return 0;
                    108: 	}
                    109:     }
1.48      albertel  110:     &log($fh,"<p>Seems like that did not work!</p>");
1.42      albertel  111:     $errors++;
                    112:     return 0;
                    113: }
                    114: 
                    115: sub checkon_daemon {
1.59      albertel  116:     my ($fh,$daemon,$maxsize,$send,$args)=@_;
1.42      albertel  117: 
1.63      albertel  118:     my $result;
1.48      albertel  119:     &log($fh,'<hr /><a name="'.$daemon.'" /><h2>'.$daemon.'</h2><h3>Log</h3><p style="white-space: pre;"><tt>');
1.57      albertel  120:     printf("%-15s ",$daemon);
1.110     raeburn   121:     if ($fh) {
                    122:         if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
                    123: 	    if (open(DFH,"tail -n25 $perlvar{'lonDaemons'}/logs/$daemon.log|")) {
1.125   ! raeburn   124: 	        while (my $line=<DFH>) {
1.110     raeburn   125: 	            &log($fh,"$line");
                    126: 	            if ($line=~/INFO/) { $notices++; }
                    127: 	            if ($line=~/WARNING/) { $notices++; }
                    128: 	            if ($line=~/CRITICAL/) { $warnings++; }
                    129: 	        }
                    130: 	        close (DFH);
                    131:             }
                    132:         }
                    133:         &log($fh,"</tt></p>");
1.42      albertel  134:     }
1.125   ! raeburn   135: 
1.42      albertel  136:     my $pidfile="$perlvar{'lonDaemons'}/logs/$daemon.pid";
1.125   ! raeburn   137:  
1.42      albertel  138:     my $restartflag=1;
1.46      albertel  139:     my $daemonpid;
1.42      albertel  140:     if (-e $pidfile) {
                    141: 	my $lfh=IO::File->new("$pidfile");
1.46      albertel  142: 	$daemonpid=<$lfh>;
1.42      albertel  143: 	chomp($daemonpid);
1.62      albertel  144: 	if ($daemonpid =~ /^\d+$/ && kill 0 => $daemonpid) {
1.46      albertel  145: 	    &log($fh,"<h3>$daemon at pid $daemonpid responding");
1.59      albertel  146: 	    if ($send) { &log($fh,", sending $send"); }
1.46      albertel  147: 	    &log($fh,"</h3>");
1.59      albertel  148: 	    if ($send eq 'USR1') { kill USR1 => $daemonpid; }
                    149: 	    if ($send eq 'USR2') { kill USR2 => $daemonpid; }
1.42      albertel  150: 	    $restartflag=0;
1.59      albertel  151: 	    if ($send eq 'USR2') {
1.63      albertel  152: 		$result = 'reloaded';
1.59      albertel  153: 		print "reloaded\n";
                    154: 	    } else {
1.63      albertel  155: 		$result = 'running';
1.59      albertel  156: 		print "running\n";
                    157: 	    }
1.42      albertel  158: 	} else {
                    159: 	    $errors++;
1.46      albertel  160: 	    &log($fh,"<h3>$daemon at pid $daemonpid not responding</h3>");
1.42      albertel  161: 	    $restartflag=1;
1.46      albertel  162: 	    &log($fh,"<h3>Decided to clean up stale .pid file and restart $daemon</h3>");
1.42      albertel  163: 	}
                    164:     }
                    165:     if ($restartflag==1) {
                    166: 	$simplestatus{$daemon}='off';
                    167: 	$errors++;
1.57      albertel  168: 	my $kadaemon=$daemon;
                    169: 	if ($kadaemon eq 'lonmemcached') { $kadaemon='memcached'; }
1.101     raeburn   170: 	&log($fh,'<br /><font color="red">Killall '.$daemon.': '.
1.57      albertel  171: 	    `killall $kadaemon 2>&1`.' - ');
1.60      albertel  172: 	sleep 1;
1.46      albertel  173: 	&log($fh,unlink($pidfile).' - '.
1.57      albertel  174: 	    `killall -9 $kadaemon 2>&1`.
1.101     raeburn   175: 	    '</font><br />');
1.107     raeburn   176:         if ($kadaemon eq 'loncnew') {
                    177:             &clean_lonc_childpids();
                    178:         }
1.46      albertel  179: 	&log($fh,"<h3>$daemon not running, trying to start</h3>");
1.110     raeburn   180: 
1.50      albertel  181: 	if (&start_daemon($fh,$daemon,$pidfile,$args)) {
1.46      albertel  182: 	    &log($fh,"<h3>$daemon at pid $daemonpid responding</h3>");
1.42      albertel  183: 	    $simplestatus{$daemon}='restarted';
1.63      albertel  184: 	    $result = 'started';
1.42      albertel  185: 	    print "started\n";
                    186: 	} else {
                    187: 	    $errors++;
1.46      albertel  188: 	    &log($fh,"<h3>$daemon at pid $daemonpid not responding</h3>");
1.48      albertel  189: 	    &log($fh,"<p>Give it one more try ...</p>");
1.42      albertel  190: 	    print " ";
1.50      albertel  191: 	    if (&start_daemon($fh,$daemon,$pidfile,$args)) {
1.46      albertel  192: 		&log($fh,"<h3>$daemon at pid $daemonpid responding</h3>");
1.42      albertel  193: 		$simplestatus{$daemon}='restarted';
1.63      albertel  194: 		$result = 'started';
1.42      albertel  195: 		print "started\n";
                    196: 	    } else {
1.63      albertel  197: 		$result = 'failed';
1.42      albertel  198: 		print " failed\n";
                    199: 		$simplestatus{$daemon}='failed';
                    200: 		$errors++; $errors++;
1.46      albertel  201: 		&log($fh,"<h3>$daemon at pid $daemonpid not responding</h3>");
1.48      albertel  202: 		&log($fh,"<p>Unable to start $daemon</p>");
1.42      albertel  203: 	    }
                    204: 	}
1.110     raeburn   205:         if ($fh) {
                    206: 	    if (-e "$perlvar{'lonDaemons'}/logs/$daemon.log"){
                    207: 	        &log($fh,"<p><pre>");
                    208: 	        if (open(DFH,"tail -n100 $perlvar{'lonDaemons'}/logs/$daemon.log|")) {
                    209: 	            while (my $line=<DFH>) { 
                    210: 		        &log($fh,"$line");
                    211: 		        if ($line=~/WARNING/) { $notices++; }
                    212: 		        if ($line=~/CRITICAL/) { $notices++; }
                    213: 	            }
                    214: 	            close (DFH);
                    215:                 }
                    216: 	        &log($fh,"</pre></p>");
                    217:             }
1.42      albertel  218: 	}
                    219:     }
1.125   ! raeburn   220: 
1.46      albertel  221:     my $fname="$perlvar{'lonDaemons'}/logs/$daemon.log";
1.73      albertel  222:     &rotate_logfile($fname,$fh,'logs');
1.42      albertel  223: 
                    224:     &errout($fh);
1.63      albertel  225:     return $result;
1.42      albertel  226: }
1.1       albertel  227: 
1.46      albertel  228: # --------------------------------------------------------------------- Machine
                    229: sub log_machine_info {
                    230:     my ($fh)=@_;
1.48      albertel  231:     &log($fh,'<hr /><a name="machine" /><h2>Machine Information</h2>');
1.46      albertel  232:     &log($fh,"<h3>loadavg</h3>");
1.125   ! raeburn   233: 
1.46      albertel  234:     open (LOADAVGH,"/proc/loadavg");
                    235:     my $loadavg=<LOADAVGH>;
                    236:     close (LOADAVGH);
1.125   ! raeburn   237:  
1.46      albertel  238:     &log($fh,"<tt>$loadavg</tt>");
1.125   ! raeburn   239: 
1.46      albertel  240:     my @parts=split(/\s+/,$loadavg);
                    241:     if ($parts[1]>4.0) {
                    242: 	$errors++;
                    243:     } elsif ($parts[1]>2.0) {
                    244: 	$warnings++;
                    245:     } elsif ($parts[1]>1.0) {
                    246: 	$notices++;
                    247:     }
1.13      harris41  248: 
1.46      albertel  249:     &log($fh,"<h3>df</h3>");
                    250:     &log($fh,"<pre>");
1.14      harris41  251: 
1.46      albertel  252:     open (DFH,"df|");
1.125   ! raeburn   253:     while (my $line=<DFH>) {
        !           254: 	&log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  255: 	@parts=split(/\s+/,$line);
                    256: 	my $usage=$parts[4];
                    257: 	$usage=~s/\W//g;
1.125   ! raeburn   258: 	if ($usage>90) {
1.46      albertel  259: 	    $warnings++;
1.125   ! raeburn   260: 	    $notices++;
1.46      albertel  261: 	} elsif ($usage>80) {
                    262: 	    $warnings++;
                    263: 	} elsif ($usage>60) {
                    264: 	    $notices++;
1.31      albertel  265: 	}
1.46      albertel  266: 	if ($usage>95) { $warnings++; $warnings++; $simplestatus{'diskfull'}++; }
1.1       albertel  267:     }
1.46      albertel  268:     close (DFH);
                    269:     &log($fh,"</pre>");
1.1       albertel  270: 
                    271: 
1.46      albertel  272:     &log($fh,"<h3>ps</h3>");
                    273:     &log($fh,"<pre>");
                    274:     my $psproc=0;
1.1       albertel  275: 
1.53      albertel  276:     open (PSH,"ps aux --cols 140 |");
1.125   ! raeburn   277:     while (my $line=<PSH>) {
        !           278: 	&log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  279: 	$psproc++;
                    280:     }
                    281:     close (PSH);
                    282:     &log($fh,"</pre>");
1.1       albertel  283: 
1.46      albertel  284:     if ($psproc>200) { $notices++; }
                    285:     if ($psproc>250) { $notices++; }
1.1       albertel  286: 
1.61      albertel  287:     &log($fh,"<h3>distprobe</h3>");
                    288:     &log($fh,"<pre>");
1.98      raeburn   289:     &log($fh,&encode_entities(&LONCAPA::distro(),'<>&"'));
1.61      albertel  290:     &log($fh,"</pre>");
                    291: 
1.46      albertel  292:     &errout($fh);
                    293: }
1.1       albertel  294: 
1.46      albertel  295: sub start_logging {
1.43      albertel  296:     my $fh=IO::File->new(">$statusdir/newstatus.html");
                    297:     my %simplestatus=();
1.46      albertel  298:     my $now=time;
                    299:     my $date=localtime($now);
1.125   ! raeburn   300:  
1.46      albertel  301: 
                    302:     &log($fh,(<<ENDHEADERS));
1.101     raeburn   303: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                    304: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
1.1       albertel  305: <head>
                    306: <title>LON Status Report $perlvar{'lonHostID'}</title>
1.101     raeburn   307: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
1.1       albertel  308: </head>
1.3       www       309: <body bgcolor="#AAAAAA">
1.48      albertel  310: <a name="top" />
1.1       albertel  311: <h1>LON Status Report $perlvar{'lonHostID'}</h1>
                    312: <h2>$date ($now)</h2>
                    313: <ol>
1.48      albertel  314: <li><a href="#configuration">Configuration</a></li>
                    315: <li><a href="#machine">Machine Information</a></li>
                    316: <li><a href="#tmp">Temporary Files</a></li>
                    317: <li><a href="#tokens">Session Tokens</a></li>
1.102     raeburn   318: <li><a href="#webdav">WebDAV Session Tokens</a></li>
1.48      albertel  319: <li><a href="#httpd">httpd</a></li>
                    320: <li><a href="#lonsql">lonsql</a></li>
                    321: <li><a href="#lond">lond</a></li>
                    322: <li><a href="#lonc">lonc</a></li>
                    323: <li><a href="#lonnet">lonnet</a></li>
                    324: <li><a href="#connections">Connections</a></li>
                    325: <li><a href="#delayed">Delayed Messages</a></li>
                    326: <li><a href="#errcount">Error Count</a></li>
1.1       albertel  327: </ol>
1.48      albertel  328: <hr />
                    329: <a name="configuration" />
1.1       albertel  330: <h2>Configuration</h2>
                    331: <h3>PerlVars</h3>
1.48      albertel  332: <table border="2">
1.1       albertel  333: ENDHEADERS
                    334: 
1.46      albertel  335:     foreach my $varname (sort(keys(%perlvar))) {
1.48      albertel  336: 	&log($fh,"<tr><td>$varname</td><td>".
                    337: 	     &encode_entities($perlvar{$varname},'<>&"')."</td></tr>\n");
1.43      albertel  338:     }
1.48      albertel  339:     &log($fh,"</table><h3>Hosts</h3><table border='2'>");
1.72      albertel  340:     my %hostname = &Apache::lonnet::all_hostnames();
                    341:     foreach my $id (sort(keys(%hostname))) {
                    342: 	my $role = (&Apache::lonnet::is_library($id) ? 'library'
                    343: 		                                     : 'access');
1.46      albertel  344: 	&log($fh,
1.72      albertel  345: 	    "<tr><td>$id</td><td>".&Apache::lonnet::host_domain($id).
                    346: 	    "</td><td>".$role.
                    347: 	    "</td><td>".&Apache::lonnet::hostname($id)."</td></tr>\n");
                    348:     }
1.101     raeburn   349:     &log($fh,"</table><h3>Spare Hosts</h3>");
                    350:     if (keys(%Apache::lonnet::spareid) > 0) {
                    351:         &log($fh,"<ul>");
                    352:         foreach my $type (sort(keys(%Apache::lonnet::spareid))) {
                    353: 	    &log($fh,"<li>$type\n<ol>");
                    354: 	    foreach my $id (@{ $Apache::lonnet::spareid{$type} }) {
                    355: 	        &log($fh,"<li>$id</li>\n");
                    356: 	    }
                    357: 	    &log($fh,"</ol>\n</li>\n");
                    358:         }
                    359:         &log($fh,"</ul>\n");
                    360:     } else {
                    361:         &log($fh,"No spare hosts specified<br />\n");
1.43      albertel  362:     }
1.46      albertel  363:     return $fh;
                    364: }
1.11      www       365: 
                    366: # --------------------------------------------------------------- clean out tmp
1.46      albertel  367: sub clean_tmp {
                    368:     my ($fh)=@_;
1.48      albertel  369:     &log($fh,'<hr /><a name="tmp" /><h2>Temporary Files</h2>');
1.82      raeburn   370:     my ($cleaned,$old,$removed) = (0,0,0);
                    371:     my %errors = (
                    372:                      dir       => [],
                    373:                      file      => [],
                    374:                      failopen  => [],
                    375:                  );
                    376:     my %error_titles = (
                    377:                          dir       => 'failed to remove empty directory:',
                    378:                          file      => 'failed to unlike stale file',
                    379:                          failopen  => 'failed to open file or directory'
                    380:                        );
                    381:     ($cleaned,$old,$removed) = &recursive_clean_tmp('',$cleaned,$old,$removed,\%errors);
                    382:     &log($fh,"Cleaned up: ".$cleaned." files; removed: $removed empty directories; (found: $old old checkout tokens)");
                    383:     foreach my $key (sort(keys(%errors))) {
                    384:         if (ref($errors{$key}) eq 'ARRAY') {
                    385:             if (@{$errors{$key}} > 0) {
                    386:                 &log($fh,"Error during cleanup ($error_titles{$key}):<ul><li>".
                    387:                      join('</li><li><tt>',@{$errors{$key}}).'</tt></li></ul><br />');
                    388:             }
                    389:         }
                    390:     }
                    391: }
                    392: 
                    393: sub recursive_clean_tmp {
                    394:     my ($subdir,$cleaned,$old,$removed,$errors) = @_;
                    395:     my $base = "$perlvar{'lonDaemons'}/tmp";
                    396:     my $path = $base;
                    397:     next if ($subdir =~ m{\.\./});
                    398:     next unless (ref($errors) eq 'HASH');
                    399:     unless ($subdir eq '') {
                    400:         $path .= '/'.$subdir;
                    401:     }
                    402:     if (opendir(my $dh,"$path")) {
                    403:         while (my $file = readdir($dh)) {
                    404:             next if ($file =~ /^\.\.?$/);
                    405:             my $fname = "$path/$file";
                    406:             if (-d $fname) {
                    407:                 my $innerdir;
                    408:                 if ($subdir eq '') {
                    409:                     $innerdir = $file;
                    410:                 } else {
                    411:                     $innerdir = $subdir.'/'.$file;
                    412:                 }
                    413:                 ($cleaned,$old,$removed) = 
                    414:                      &recursive_clean_tmp($innerdir,$cleaned,$old,$removed,$errors);
                    415:                 my @doms = &Apache::lonnet::current_machine_domains();
1.125   ! raeburn   416: 
1.82      raeburn   417:                 if (open(my $dirhandle,$fname)) {
                    418:                     unless (($innerdir eq 'helprequests') ||
                    419:                             (($innerdir =~ /^addcourse/) && ($innerdir !~ m{/\d+$}))) {
                    420:                         my @contents = grep {!/^\.\.?$/} readdir($dirhandle);
1.125   ! raeburn   421:                                       join('&&',@contents)."\n";
1.82      raeburn   422:                         if (scalar(grep {!/^\.\.?$/} readdir($dirhandle)) == 0) {
                    423:                             closedir($dirhandle);
                    424:                             if ($fname =~ m{^\Q$perlvar{'lonDaemons'}\E/tmp/}) {
                    425:                                 if (rmdir($fname)) {
                    426:                                     $removed ++;
                    427:                                 } elsif (ref($errors->{dir}) eq 'ARRAY') {
                    428:                                     push(@{$errors->{dir}},$fname);
                    429:                                 }
                    430:                             }
                    431:                         }
                    432:                     } else {
                    433:                         closedir($dirhandle);
                    434:                     }
                    435:                 }
                    436:             } else {
                    437:                 my ($dev,$ino,$mode,$nlink,
                    438:                     $uid,$gid,$rdev,$size,
                    439:                     $atime,$mtime,$ctime,
                    440:                     $blksize,$blocks)=stat($fname);
                    441:                 my $now=time;
                    442:                 my $since=$now-$mtime;
                    443:                 if ($since>$perlvar{'lonExpire'}) {
                    444:                     if ($subdir eq '') {
                    445:                         my $line='';
                    446:                         if ($fname =~ /\.db$/) {
                    447:                             if (unlink($fname)) {
                    448:                                 $cleaned++;
                    449:                             } elsif (ref($errors->{file}) eq 'ARRAY') {
                    450:                                 push(@{$errors->{file}},$fname);
                    451:                             }
                    452:                         } elsif (open(PROBE,$fname)) {
                    453:                             my $line='';
                    454:                             $line=<PROBE>;
                    455:                             close(PROBE);
                    456:                             if ($line=~/^CHECKOUTTOKEN\&/) {
                    457:                                 if ($since>365*$perlvar{'lonExpire'}) {
                    458:                                     if (unlink($fname)) {
                    459:                                         $cleaned++; 
                    460:                                     } elsif (ref($errors->{file}) eq 'ARRAY') {
                    461:                                         push(@{$errors->{file}},$fname);
                    462:                                     }
                    463:                                 } else {
                    464:                                     $old++;
                    465:                                 }
                    466:                             } else {
                    467:                                 if (unlink($fname)) {
                    468:                                     $cleaned++;
                    469:                                 } elsif (ref($errors->{file}) eq 'ARRAY') {
                    470:                                     push(@{$errors->{file}},$fname);
                    471:                                 }
                    472:                             }
                    473:                         } elsif (ref($errors->{failopen}) eq 'ARRAY') {
1.125   ! raeburn   474:                             push(@{$errors->{failopen}},$fname);
1.82      raeburn   475:                         }
                    476:                     } else {
                    477:                         if (unlink($fname)) {
                    478:                             $cleaned++;
                    479:                         } elsif (ref($errors->{file}) eq 'ARRAY') {
                    480:                             push(@{$errors->{file}},$fname);
                    481:                         }
                    482:                     }
                    483:                 }
                    484:             }
                    485:         }
                    486:         closedir($dh);
                    487:     } elsif (ref($errors->{failopen}) eq 'ARRAY') {
                    488:         push(@{$errors->{failopen}},$path);
1.43      albertel  489:     }
1.82      raeburn   490:     return ($cleaned,$old,$removed);
1.46      albertel  491: }
1.11      www       492: 
                    493: # ------------------------------------------------------------ clean out lonIDs
1.46      albertel  494: sub clean_lonIDs {
                    495:     my ($fh)=@_;
1.48      albertel  496:     &log($fh,'<hr /><a name="tokens" /><h2>Session Tokens</h2>');
1.46      albertel  497:     my $cleaned=0;
                    498:     my $active=0;
                    499:     while (my $fname=<$perlvar{'lonIDsDir'}/*>) {
1.122     raeburn   500:         my $now=time;
                    501:         if (-l $fname) {
                    502:             my $linkfname = readlink($fname);
                    503:             if (-f $linkfname) {
                    504:                 if ($linkfname =~ m{^$perlvar{'lonIDsDir'}/[^/]+\.id$}) {
                    505:                     my @data = stat($linkfname);
                    506:                     my $mtime = $data[9];
                    507:                     my $since=$now-$mtime;
                    508:                     if ($since>$perlvar{'lonExpire'}) {
                    509:                         if (unlink($linkfname)) {
                    510:                             $cleaned++;
                    511:                             &log($fh,"Unlinking $linkfname<br />");
                    512:                             unlink($fname);
                    513:                         }
                    514:                     }
                    515:                 }
                    516:             } else {
                    517:                unlink($fname);
                    518:             }
                    519:         } elsif (-f $fname) {
                    520:             my @data = stat($fname);
                    521:             my $mtime = $data[9];
                    522:             my $since=$now-$mtime;
                    523:             if ($since>$perlvar{'lonExpire'}) {
                    524:                 if (unlink($fname)) {
                    525:                     $cleaned++;
                    526:                     &log($fh,"Unlinking $fname<br />");
                    527:                 }
                    528:             } else {
                    529:                 $active++;
                    530:             }
                    531:         }
1.46      albertel  532:     }
1.48      albertel  533:     &log($fh,"<p>Cleaned up ".$cleaned." stale session token(s).</p>");
1.46      albertel  534:     &log($fh,"<h3>$active open session(s)</h3>");
                    535: }
1.43      albertel  536: 
1.115     raeburn   537: # -------------------------------------------------------- clean out balanceIDs
                    538: 
                    539: sub clean_balanceIDs {
                    540:     my ($fh)=@_;
                    541:     &log($fh,'<hr /><a name="balcookies" /><h2>Session Tokens</h2>');
                    542:     my $cleaned=0;
                    543:     my $active=0;
                    544:     if (-d $perlvar{'lonBalanceDir'}) {
1.124     raeburn   545:         while (my $fname=<$perlvar{'lonBalanceDir'}/*.id>) {
1.115     raeburn   546:             my ($dev,$ino,$mode,$nlink,
                    547:                 $uid,$gid,$rdev,$size,
                    548:                 $atime,$mtime,$ctime,
                    549:                 $blksize,$blocks)=stat($fname);
                    550:             my $now=time;
                    551:             my $since=$now-$mtime;
                    552:             if ($since>$perlvar{'lonExpire'}) {
                    553:                 $cleaned++;
                    554:                 &log($fh,"Unlinking $fname<br />");
                    555:                 unlink("$fname");
                    556:             } else {
                    557:                 $active++;
                    558:             }
                    559:         }
                    560:     }
                    561:     &log($fh,"<p>Cleaned up ".$cleaned." stale balancer files</p>");
                    562:     &log($fh,"<h3>$active unexpired balancer files</h3>");
                    563: }
                    564: 
1.102     raeburn   565: # ------------------------------------------------ clean out webDAV Session IDs
                    566: sub clean_webDAV_sessionIDs {
                    567:     my ($fh)=@_;
                    568:     if ($perlvar{'lonRole'} eq 'library') {
                    569:         &log($fh,'<hr /><a name="webdav" /><h2>WebDAV Session Tokens</h2>');
                    570:         my $cleaned=0;
                    571:         my $active=0;
                    572:         my $now = time;
                    573:         if (-d $perlvar{'lonDAVsessDir'}) {
                    574:             while (my $fname=<$perlvar{'lonDAVsessDir'}/*>) {
                    575:                 my @stats = stat($fname);
                    576:                 my $since=$now-$stats[9];
                    577:                 if ($since>$perlvar{'lonExpire'}) {
                    578:                     $cleaned++;
                    579:                     &log($fh,"Unlinking $fname<br />");
                    580:                     unlink("$fname");
                    581:                 } else {
                    582:                     $active++;
                    583:                 }
                    584:             }
                    585:             &log($fh,"<p>Cleaned up ".$cleaned." stale webDAV session token(s).</p>");
                    586:             &log($fh,"<h3>$active open webDAV session(s)</h3>");
                    587:         }
                    588:     }
                    589: }
                    590: 
1.119     raeburn   591: # ------------------------------------------------------------ clean out ltiIDs
                    592: 
                    593: sub clean_ltiIDs {
                    594:     my ($fh)=@_;
                    595:     &log($fh,'<hr /><a name="ltisessions" /><h2>LTI Session Pointers</h2>');
                    596:     my $cleaned=0;
                    597:     my $active=0;
                    598:     if (-d $perlvar{'ltiIDsDir'}) {
                    599:         while (my $fname=<$perlvar{'ltiIDsDir'}/*>) {
                    600:             my ($dev,$ino,$mode,$nlink,
                    601:                 $uid,$gid,$rdev,$size,
                    602:                 $atime,$mtime,$ctime,
                    603:                 $blksize,$blocks)=stat($fname);
                    604:             my $now=time;
                    605:             my $since=$now-$mtime;
                    606:             if ($since>$perlvar{'lonExpire'}) {
                    607:                 $cleaned++;
                    608:                 &log($fh,"Unlinking $fname<br />");
                    609:                 unlink("$fname");
                    610:             } else {
                    611:                 $active++;
                    612:             }
                    613:         }
                    614:     }
                    615:     &log($fh,"<p>Cleaned up ".$cleaned." old LTI session pointers.</p>");
                    616:     &log($fh,"<h3>$active unexpired LTI session pointers</h3>");
                    617: }
                    618: 
1.74      albertel  619: # ----------------------------------------------------------- clean out sockets
                    620: sub clean_sockets {
                    621:     my ($fh)=@_;
                    622:     my $cleaned=0;
                    623:     opendir(SOCKETS,$perlvar{'lonSockDir'});
                    624:     while (my $fname=readdir(SOCKETS)) {
                    625: 	next if (-d $fname 
1.80      www       626: 		 || $fname=~/(mysqlsock|maximasock|rsock|\Q$perlvar{'lonSockDir'}\E)/);
1.74      albertel  627: 	$cleaned++;
                    628: 	&log($fh,"Unlinking $fname<br />");
                    629: 	unlink("/home/httpd/sockets/$fname");
                    630:     }
                    631:     &log($fh,"<p>Cleaned up ".$cleaned." stale sockets.</p>");
                    632: }
                    633: 
1.11      www       634: 
1.1       albertel  635: # ----------------------------------------------------------------------- httpd
1.46      albertel  636: sub check_httpd_logs {
                    637:     my ($fh)=@_;
1.94      raeburn   638:     if (open(PIPE,"./lchttpdlogs|")) {
1.93      raeburn   639:         while (my $line=<PIPE>) {
                    640:             &log($fh,$line);
                    641:             if ($line=~/\[error\]/) { $notices++; }
                    642:         }
                    643:         close(PIPE);
1.46      albertel  644:     }
1.43      albertel  645:     &errout($fh);
1.46      albertel  646: }
1.1       albertel  647: 
                    648: # ---------------------------------------------------------------------- lonnet
                    649: 
1.48      albertel  650: sub rotate_lonnet_logs {
1.46      albertel  651:     my ($fh)=@_;
1.48      albertel  652:     &log($fh,'<hr /><a name="lonnet" /><h2>lonnet</h2><h3>Temp Log</h3><pre>');
1.100     bisitz    653:     print "Checking logs.\n";
1.43      albertel  654:     if (-e "$perlvar{'lonDaemons'}/logs/lonnet.log"){
                    655: 	open (DFH,"tail -n50 $perlvar{'lonDaemons'}/logs/lonnet.log|");
1.125   ! raeburn   656: 	while (my $line=<DFH>) {
1.48      albertel  657: 	    &log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  658: 	}
1.43      albertel  659: 	close (DFH);
                    660:     }
1.46      albertel  661:     &log($fh,"</pre><h3>Perm Log</h3><pre>");
1.125   ! raeburn   662: 
1.43      albertel  663:     if (-e "$perlvar{'lonDaemons'}/logs/lonnet.perm.log") {
                    664: 	open(DFH,"tail -n10 $perlvar{'lonDaemons'}/logs/lonnet.perm.log|");
1.125   ! raeburn   665: 	while (my $line=<DFH>) {
1.48      albertel  666: 	    &log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  667: 	}
1.43      albertel  668: 	close (DFH);
1.46      albertel  669:     } else { &log($fh,"No perm log\n") }
1.43      albertel  670: 
1.46      albertel  671:     my $fname="$perlvar{'lonDaemons'}/logs/lonnet.log";
1.73      albertel  672:     &rotate_logfile($fname,$fh,'lonnet log');
1.1       albertel  673: 
1.46      albertel  674:     &log($fh,"</pre>");
1.43      albertel  675:     &errout($fh);
1.46      albertel  676: }
                    677: 
1.73      albertel  678: sub rotate_other_logs {
                    679:     my ($fh) = @_;
1.83      raeburn   680:     my %logs = (
                    681:                   autoenroll          => 'Auto Enroll log',
                    682:                   autocreate          => 'Create Course log',
                    683:                   searchcat           => 'Search Cataloguing log',
                    684:                   autoupdate          => 'Auto Update log',
                    685:                   refreshcourseids_db => 'Refresh CourseIDs db log',
                    686:                );
                    687:     foreach my $item (keys(%logs)) {
                    688:         my $fname=$perlvar{'lonDaemons'}.'/logs/'.$item.'.log';
                    689:         &rotate_logfile($fname,$fh,$logs{$item});
                    690:     }
1.73      albertel  691: }
                    692: 
1.43      albertel  693: # ----------------------------------------------------------------- Connections
1.46      albertel  694: sub test_connections {
1.72      albertel  695:     my ($fh)=@_;
1.48      albertel  696:     &log($fh,'<hr /><a name="connections" /><h2>Connections</h2>');
1.100     bisitz    697:     print "Testing connections.\n";
1.48      albertel  698:     &log($fh,"<table border='2'>");
1.49      albertel  699:     my ($good,$bad)=(0,0);
1.72      albertel  700:     my %hostname = &Apache::lonnet::all_hostnames();
                    701:     foreach my $tryserver (sort(keys(%hostname))) {
1.43      albertel  702: 	print(".");
1.46      albertel  703: 	my $result;
1.72      albertel  704: 	my $answer=&Apache::lonnet::reply("ping",$tryserver);
1.43      albertel  705: 	if ($answer eq "$tryserver:$perlvar{'lonHostID'}") {
                    706: 	    $result="<b>ok</b>";
1.49      albertel  707: 	    $good++;
1.43      albertel  708: 	} else {
                    709: 	    $result=$answer;
                    710: 	    $warnings++;
1.49      albertel  711: 	    if ($answer eq 'con_lost') {
                    712: 		$bad++;
                    713: 		$warnings++;
1.50      albertel  714: 	    } else {
                    715: 		$good++; #self connection
1.49      albertel  716: 	    }
1.43      albertel  717: 	}
                    718: 	if ($answer =~ /con_lost/) { print(" $tryserver down\n"); }
1.46      albertel  719: 	&log($fh,"<tr><td>$tryserver</td><td>$result</td></tr>\n");
1.1       albertel  720:     }
1.46      albertel  721:     &log($fh,"</table>");
1.49      albertel  722:     print "\n$good good, $bad bad connections\n";
1.43      albertel  723:     &errout($fh);
1.46      albertel  724: }
                    725: 
                    726: 
1.1       albertel  727: # ------------------------------------------------------------ Delayed messages
1.46      albertel  728: sub check_delayed_msg {
1.114     raeburn   729:     my ($fh,$weightsref,$exclusionsref)=@_;
1.48      albertel  730:     &log($fh,'<hr /><a name="delayed" /><h2>Delayed Messages</h2>');
1.100     bisitz    731:     print "Checking buffers.\n";
1.46      albertel  732:     
                    733:     &log($fh,'<h3>Scanning Permanent Log</h3>');
1.1       albertel  734: 
1.46      albertel  735:     my $unsend=0;
1.114     raeburn   736:     my $ignored=0;
1.1       albertel  737: 
1.105     raeburn   738:     my %hostname = &Apache::lonnet::all_hostnames();
                    739:     my $numhosts = scalar(keys(%hostname));
1.114     raeburn   740:     my $checkbackwards = 0;
                    741:     my $checkfrom = 0;
                    742:     my $checkexcluded = 0;
                    743:     my (%bymachine,%weights,%exclusions,%serverhomes);
                    744:     if (ref($weightsref) eq 'HASH') {
                    745:         %weights = %{$weightsref};
                    746:     }
                    747:     if (ref($exclusionsref) eq 'HASH') {
                    748:         %exclusions = %{$exclusionsref};
                    749:         if (keys(%exclusions)) {
                    750:             $checkexcluded = 1;
                    751:             %serverhomes = &read_serverhomeIDs();
                    752:         }
                    753:     }
1.105     raeburn   754: 
1.114     raeburn   755: #
                    756: # For LON-CAPA 1.2.0 to 2.1.3 (release dates: 8/31/2004 and 3/31/2006) any
                    757: # entry logged in lonnet.perm.log for completion of a delayed (critical)
                    758: # transaction lacked the hostID for the remote node to which the command
                    759: # to be completed was sent.
                    760: #
                    761: # Because of this, exclusion of items in lonnet.perm.log for nodes which are
                    762: # no longer part of the cluster from adding to the overall "unsend" count
                    763: # needs additional effort besides the changes made in loncron rev. 1.105.
                    764: #
                    765: # For "S" (completion) events logging in LON-CAPA 1.2.0 through 2.1.3 included
                    766: # "LondTransaction=HASH(hexadecimal)->getClient() :$cmd, where the hexadecimal
                    767: # is a memory location, and $cmd is the command sent to the remote node.
                    768: #
                    769: # Starting with 2.2.0 (released 8/21/2006) logging for "S" (completion) events
                    770: # had sethost:$host_id:$cmd after LondTransaction=HASH(hexadecimal)->getClient()
                    771: #
                    772: # Starting with 2.4.1 (released 6/13/2007) logging for "S" replaced echoing the
                    773: # getClient() call with the result of the Transaction->getClient() call itself
                    774: # undef for completion of delivery of a delayed message.
                    775: #
                    776: # The net effect of these changes is that lonnet.perm.log is now accessed three
                    777: # times: (a) oldest record is checked, if earlier than release date for 2.5.0
                    778: # then (b) file is read backwards, with timestamp recorded for most recent
                    779: # instance of logged "S" event for "update" command without "sethost:$host_id:"
                    780: # then (c) file is read forward with records ignored which predate the timestamp
                    781: # recorded in (b), if one was found.
                    782: #
                    783: # In (c), when calculating the unsend total, i.e., the difference between delayed
                    784: # transactions ("D") and sent transactions ("S"), transactions are ignored if the
                    785: # target node is no longer in the cluster, and also (for "update" commands), if
                    786: # the target node is in the list of nodes excluded from the count, in the domain
                    787: # configuration for this machine's default domain.  The idea here is to remove
                    788: # delayed "update" commands for nodes for which inbound access to port 5663,
                    789: # is blocked, but are still part of the LON-CAPA network, (i.e., they can still
                    790: # replicate content from other nodes).
                    791: #
                    792: 
                    793:     my $dfh=IO::File->new("$perlvar{'lonDaemons'}/logs/lonnet.perm.log","r");
                    794:     if (defined($dfh)) {
                    795:         while (my $line=<$dfh>) {
                    796:             my ($time,$sdf,$rest)=split(/:/,$line,3);
                    797:             if ($time < 1541185772) {
                    798:                 $checkbackwards = 1;
                    799:             }
                    800:             last;
                    801:         }
                    802:         undef $dfh;
                    803:     } 
                    804: 
                    805:     if ($checkbackwards) {
                    806:         if (tie *BW, 'File::ReadBackwards', "$perlvar{'lonDaemons'}/logs/lonnet.perm.log") {
                    807:             while(my $line=<BW>) {
                    808:                 if ($line =~ /\QLondTransaction=HASH\E[^:]+:update:/) {
                    809:                     ($checkfrom) = split(/:/,$line,2);
                    810:                     last;
                    811:                 }
                    812:             }
                    813:             close(BW);
                    814:         }
1.1       albertel  815:     }
1.114     raeburn   816:     $dfh=IO::File->new("$perlvar{'lonDaemons'}/logs/lonnet.perm.log","r");
                    817:     if (defined($dfh)) {
                    818:         while (my $line=<$dfh>) {
                    819:             my ($time,$sdf,$rest)=split(/:/,$line,3);
                    820:             next unless (($sdf eq 'F') || ($sdf eq 'S') || ($sdf eq 'D'));
                    821:             next if (($checkfrom) && ($time <= $checkfrom));
                    822:             my ($dserv,$dcmd);
                    823:             if ($sdf eq 'S') {
                    824:                 my ($serva,$cmda,$servb,$cmdb) = split(/:/,$rest);
                    825:                 if ($cmda eq 'sethost') {
                    826:                     chomp($cmdb);
                    827:                     $dcmd = $cmdb;
                    828:                 } else {
                    829:                     $dcmd = $cmda;
                    830:                 }
                    831:                 if (($serva =~ /^LondTransaction/) || ($serva eq '')) {
                    832:                     unless (($servb eq '') || ($servb =~ m{^/})) {
                    833:                         $dserv = $servb;
                    834:                     }
                    835:                 } else {
                    836:                     $dserv = $serva;
                    837:                 }
                    838:             } else {
                    839:                 ($dserv,$dcmd) = split(/:/,$rest);
                    840:             }
                    841:             if ($sdf eq 'F') {
                    842:                 my $local=localtime($time);
                    843:                 &log($fh,"<b>Failed: $time, $dserv, $dcmd</b><br />");
                    844:                 $warnings++;
                    845:             }
                    846:             next if ((($dserv eq '') || ($dcmd eq '')) && ($sdf ne 'F'));
                    847:             if ($sdf eq 'S') {
                    848:                 if ($dcmd eq 'update') {
                    849:                     if ($hostname{$dserv}) {
                    850:                         if ($exclusions{$serverhomes{$hostname{$dserv}}}) {
                    851:                             $ignored --;
                    852:                         } else {
                    853:                             $unsend --;
                    854:                         }
                    855:                     }
                    856:                     if (exists($bymachine{$dserv})) {
                    857:                         $bymachine{$dserv} --;
                    858:                     } else {
                    859:                         $bymachine{$dserv} = -1;
                    860:                     }
                    861:                 } else {
                    862:                     if ($hostname{$dserv}) {
                    863:                         $unsend --;
                    864:                     }
                    865:                 }
                    866:             } elsif ($sdf eq 'D') {
                    867:                 if ($dcmd eq 'update') {
                    868:                     if ($hostname{$dserv}) {
                    869:                         if ($exclusions{$serverhomes{$hostname{$dserv}}}) {
                    870:                             $ignored ++;
                    871:                         } else {
                    872:                             $unsend ++;
                    873:                         }
                    874:                     }
                    875:                     if (exists($bymachine{$dserv})) {
                    876:                         $bymachine{$dserv} ++;
                    877:                     } else {
                    878:                         $bymachine{$dserv} = 1;
                    879:                     }
                    880:                 } else {
                    881:                     if ($hostname{$dserv}) {
                    882:                         $unsend ++;
                    883:                     }
                    884:                 }
                    885:             }
                    886:         }
                    887:         undef $dfh;
                    888:         my $nodest = 0;
                    889:         my $retired = 0;
                    890:         my %active;
                    891:         if (keys(%bymachine)) {
                    892:             unless ($checkexcluded) {
                    893:                 %serverhomes = &read_serverhomeIDs();
                    894:             }
                    895:             foreach my $key (keys(%bymachine)) {
                    896:                 if ($bymachine{$key} > 0) {
                    897:                     if ($hostname{$key}) {
                    898:                         $active{$serverhomes{$hostname{$key}}} += $bymachine{$key};
                    899:                     } else {
                    900:                         $retired ++;
                    901:                         $nodest += $bymachine{$key};
                    902:                     }
                    903:                 }
                    904:             }
                    905:         }
                    906:         if (keys(%active)) {
                    907:             &log($fh,"<p>Unsend messages by node, active (undegraded) nodes in cluster</p>\n");
                    908:             foreach my $key (sort(keys(%active))) {
                    909:                 &log($fh,&encode_entities("$key => $active{$key}",'<>&"')."\n");
                    910:             }
                    911:         }
                    912:         &log($fh,"<p>Total unsend messages: <b>$unsend</b> for ".scalar(keys(%active))." active (undegraded) nodes in cluster.</p>\n");
                    913:         if (keys(%exclusions) > 0) {
                    914:             &log($fh,"<p>Total incomplete updates <b>$ignored</b> for ".scalar(keys(%exclusions))." degraded nodes in cluster.</p>\n");
                    915:         }
                    916:         if ($retired) {
                    917:             &log($fh,"<p>Total unsent <b>$nodest</b> for $retired nodes no longer in cluster.</p>\n");
                    918:         }
                    919:         if ($unsend > 0) {
                    920:             $warnings=$warnings+$weights{'U'}*$unsend;
                    921:         }
1.95      raeburn   922:     }
1.1       albertel  923: 
1.43      albertel  924:     if ($unsend) { $simplestatus{'unsend'}=$unsend; }
1.48      albertel  925:     &log($fh,"<h3>Outgoing Buffer</h3>\n<pre>");
1.68      www       926: # list directory with delayed messages and remember offline servers
                    927:     my %servers=();
1.43      albertel  928:     open (DFH,"ls -lF $perlvar{'lonSockDir'}/delayed|");
1.68      www       929:     while (my $line=<DFH>) {
                    930:         my ($server)=($line=~/\.(\w+)$/);
                    931:         if ($server) { $servers{$server}=1; }
1.48      albertel  932: 	&log($fh,&encode_entities($line,'<>&"'));
1.46      albertel  933:     }
1.48      albertel  934:     &log($fh,"</pre>\n");
1.43      albertel  935:     close (DFH);
1.68      www       936: # pong to all servers that have delayed messages
                    937: # this will trigger a reverse connection, which should flush the buffers
1.95      raeburn   938:     foreach my $tryserver (sort(keys(%servers))) {
                    939:         if ($hostname{$tryserver} || !$numhosts) {
                    940:             my $answer;
                    941:             eval {
                    942:                 local $SIG{ ALRM } = sub { die "TIMEOUT" };
                    943:                 alarm(20);
                    944:                 $answer = &Apache::lonnet::reply("pong",$tryserver);
                    945:                 alarm(0);
                    946:             };
                    947:             if ($@ && $@ =~ m/TIMEOUT/) {
                    948:                 &log($fh,"Attempted pong to $tryserver timed out<br />");
1.100     bisitz    949:                 print "Time out while contacting: $tryserver for pong.\n";
1.95      raeburn   950:             } else {
                    951:                 &log($fh,"Pong to $tryserver: $answer<br />");
                    952:             }
1.91      raeburn   953:         } else {
1.95      raeburn   954:             &log($fh,"$tryserver has delayed messages, but is not part of the cluster -- skipping 'Pong'.<br />");
1.91      raeburn   955:         }
1.68      www       956:     }
1.46      albertel  957: }
1.1       albertel  958: 
1.46      albertel  959: sub finish_logging {
1.114     raeburn   960:     my ($fh,$weightsref)=@_;
                    961:     my %weights;
                    962:     if (ref($weightsref) eq 'HASH') {
                    963:         %weights = %{$weightsref};
                    964:     }
1.48      albertel  965:     &log($fh,"<a name='errcount' />\n");
1.113     raeburn   966:     $totalcount=($weights{'N'}*$notices)+($weights{'W'}*$warnings)+($weights{'E'}*$errors);
1.43      albertel  967:     &errout($fh);
1.46      albertel  968:     &log($fh,"<h1>Total Error Count: $totalcount</h1>");
                    969:     my $now=time;
                    970:     my $date=localtime($now);
1.48      albertel  971:     &log($fh,"<hr />$date ($now)</body></html>\n");
1.100     bisitz    972:     print "lon-status webpage updated.\n";
1.43      albertel  973:     $fh->close();
1.46      albertel  974: 
                    975:     if ($errors) { $simplestatus{'errors'}=$errors; }
                    976:     if ($warnings) { $simplestatus{'warnings'}=$warnings; }
                    977:     if ($notices) { $simplestatus{'notices'}=$notices; }
                    978:     $simplestatus{'time'}=time;
1.1       albertel  979: }
                    980: 
1.46      albertel  981: sub log_simplestatus {
1.73      albertel  982:     rename("$statusdir/newstatus.html","$statusdir/index.html");
1.46      albertel  983:     
1.43      albertel  984:     my $sfh=IO::File->new(">$statusdir/loncron_simple.txt");
                    985:     foreach (keys %simplestatus) {
                    986: 	print $sfh $_.'='.$simplestatus{$_}.'&';
                    987:     }
                    988:     print $sfh "\n";
                    989:     $sfh->close();
1.41      www       990: }
1.46      albertel  991: 
1.84      raeburn   992: sub write_loncaparevs {
1.100     bisitz    993:     print "Retrieving LON-CAPA version information.\n";
1.99      raeburn   994:     my %hostname = &Apache::lonnet::all_hostnames();
                    995:     my $output;
                    996:     foreach my $id (sort(keys(%hostname))) {
                    997:         if ($id ne '') {
                    998:             my $loncaparev;
                    999:             eval {
                   1000:                 local $SIG{ ALRM } = sub { die "TIMEOUT" };
                   1001:                 alarm(10);
                   1002:                 $loncaparev =
                   1003:                     &Apache::lonnet::get_server_loncaparev('',$id,1,'loncron');
                   1004:                 alarm(0);
                   1005:             };
                   1006:             if ($@ && $@ =~ m/TIMEOUT/) {
1.100     bisitz   1007:                 print "Time out while contacting lonHost: $id for version.\n";   
1.99      raeburn  1008:             }
                   1009:             if ($loncaparev =~ /^[\w.\-]+$/) {
                   1010:                 $output .= $id.':'.$loncaparev."\n";
                   1011:             }
                   1012:         }
                   1013:     }
                   1014:     if ($output) {
                   1015:         if (open(my $fh,">$perlvar{'lonTabDir'}/loncaparevs.tab")) {
                   1016:             print $fh $output;
                   1017:             close($fh);
                   1018:             &Apache::lonnet::load_loncaparevs();
                   1019:         }
                   1020:     }
                   1021:     return;
                   1022: }
                   1023: 
                   1024: sub write_serverhomeIDs {
1.100     bisitz   1025:     print "Retrieving LON-CAPA lonHostID information.\n";
1.99      raeburn  1026:     my %name_to_host = &Apache::lonnet::all_names();
                   1027:     my $output;
                   1028:     foreach my $name (sort(keys(%name_to_host))) {
                   1029:         if ($name ne '') {
                   1030:             if (ref($name_to_host{$name}) eq 'ARRAY') {
                   1031:                 my $serverhomeID;
1.90      raeburn  1032:                 eval {
                   1033:                     local $SIG{ ALRM } = sub { die "TIMEOUT" };
                   1034:                     alarm(10);
1.125   ! raeburn  1035:                     $serverhomeID =
1.99      raeburn  1036:                         &Apache::lonnet::get_server_homeID($name,1,'loncron');
1.90      raeburn  1037:                     alarm(0);
                   1038:                 };
                   1039:                 if ($@ && $@ =~ m/TIMEOUT/) {
1.99      raeburn  1040:                     print "Time out while contacting server: $name\n"; 
1.90      raeburn  1041:                 }
1.99      raeburn  1042:                 if ($serverhomeID ne '') {
                   1043:                     $output .= $name.':'.$serverhomeID."\n";
                   1044:                 } else {
                   1045:                     $output .= $name.':'.$name_to_host{$name}->[0]."\n";
1.84      raeburn  1046:                 }
                   1047:             }
                   1048:         }
                   1049:     }
1.99      raeburn  1050:     if ($output) {
                   1051:         if (open(my $fh,">$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {
                   1052:             print $fh $output;
                   1053:             close($fh);
                   1054:             &Apache::lonnet::load_serverhomeIDs();
1.85      raeburn  1055:         }
                   1056:     }
                   1057:     return;
                   1058: }
                   1059: 
1.96      raeburn  1060: sub write_checksums {
1.98      raeburn  1061:     my $distro = &LONCAPA::distro();
1.96      raeburn  1062:     if ($distro) {
                   1063:         print "Retrieving file version and checksumming.\n";
1.97      raeburn  1064:         my $numchksums = 0;
1.96      raeburn  1065:         my ($chksumsref,$versionsref) =
1.97      raeburn  1066:             &LONCAPA::Checksumming::get_checksums($distro,$perlvar{'lonDaemons'},
                   1067:                                                   $perlvar{'lonLib'},
                   1068:                                                   $perlvar{'lonIncludes'},
                   1069:                                                   $perlvar{'lonTabDir'});
1.96      raeburn  1070:         if (ref($chksumsref) eq 'HASH') {
                   1071:             $numchksums = scalar(keys(%{$chksumsref}));
                   1072:         }
                   1073:         print "File version retrieved and checksumming completed for $numchksums files.\n";
                   1074:     } else {
                   1075:         print "File version retrieval and checksumming skipped - could not determine Linux distro.\n"; 
                   1076:     }
1.97      raeburn  1077:     return;
1.96      raeburn  1078: }
                   1079: 
1.117     raeburn  1080: sub write_hostips {
                   1081:     my $lontabdir = $perlvar{'lonTabDir'};
                   1082:     my $defdom = $perlvar{'lonDefDomain'};
                   1083:     my $lonhost = $perlvar{'lonHostID'};
                   1084:     my $newfile = "$lontabdir/currhostips.tab";
                   1085:     my $oldfile = "$lontabdir/prevhostips.tab";
                   1086:     my (%prevhosts,%currhosts,%ipchange);
                   1087:     if ((-e $newfile) && (-s $newfile)) {
                   1088:         move($newfile,$oldfile);
                   1089:         chmod(0644,$oldfile);
                   1090:         if (open(my $fh,'<',$oldfile)) {
                   1091:             while (my $line=<$fh>) {
                   1092:                 chomp($line);
                   1093:                 if ($line =~ /^([^:]+):([\d.]+)$/) {
                   1094:                     $prevhosts{$1} = $2;
                   1095:                 }
                   1096:             }
                   1097:             close($fh);
                   1098:         }
                   1099:     }
                   1100:     my ($ip_info,$cached) =
                   1101:         &Apache::lonnet::is_cached_new('iphost','iphost');
                   1102:     if (!$cached) {
                   1103:         &Apache::lonnet::get_iphost();
                   1104:         ($ip_info,$cached) =
                   1105:         &Apache::lonnet::is_cached_new('iphost','iphost');
                   1106:     }
                   1107:     if (ref($ip_info) eq 'ARRAY') {
                   1108:         %currhosts = %{$ip_info->[1]};
                   1109:         if (open(my $fh,'>',$newfile)) {
                   1110:             foreach my $key (keys(%currhosts)) {
                   1111:                 print $fh "$key:$currhosts{$key}\n";
                   1112:             }
                   1113:             close($fh);
                   1114:             chmod(0644,$newfile);
                   1115:         }
                   1116:     }
                   1117:     if (keys(%prevhosts) && keys(%currhosts)) {
                   1118:         foreach my $key (keys(%prevhosts)) {
                   1119:             unless ($currhosts{$key} eq $prevhosts{$key}) {
1.121     raeburn  1120:                 $ipchange{$key} = $prevhosts{$key}.' | '.$currhosts{$key};
1.117     raeburn  1121:             }
                   1122:         }
                   1123:         foreach my $key (keys(%currhosts)) {
                   1124:             unless ($currhosts{$key} eq $prevhosts{$key}) {
1.121     raeburn  1125:                 $ipchange{$key} = $prevhosts{$key}.' | '.$currhosts{$key};
1.117     raeburn  1126:             }
                   1127:         }
                   1128:     }
                   1129:     if (&Apache::lonnet::domain($defdom,'primary') eq $lonhost) {
                   1130:         if (keys(%ipchange)) {
                   1131:             if (open(my $fh,'>>',$perlvar{'lonDaemons'}.'/logs/hostip.log')) {
                   1132:                print $fh "********************\n".localtime(time).' Changes --'."\n".
1.121     raeburn  1133:                          "| Hostname | Previous IP | New IP |\n".
                   1134:                          " --------------------------------- \n";
1.117     raeburn  1135:                foreach my $hostname (sort(keys(%ipchange))) {
1.121     raeburn  1136:                     print $fh "| $hostname | $ipchange{$hostname} |\n";
1.117     raeburn  1137:                 }
                   1138:                 print $fh "\n*******************\n\n";
                   1139:                 close($fh);
                   1140:             }
                   1141:             my $emailto = &Apache::loncommon::build_recipient_list(undef,
                   1142:                                    'hostipmail',$defdom);
                   1143:             if ($emailto) {
                   1144:                 my $subject = "LON-CAPA Hostname to IP change ($perlvar{'lonHostID'})";
                   1145:                 my $chgmail = "To: $emailto\n".
                   1146:                               "Subject: $subject\n".
                   1147:                               "Content-type: text/plain\; charset=UTF-8\n".
                   1148:                               "MIME-Version: 1.0\n\n".
                   1149:                               "Host/IP changes\n".
                   1150:                               " \n".
1.121     raeburn  1151:                               "| Hostname | Previous IP | New IP |\n".
                   1152:                               " --------------------------------- \n";
1.117     raeburn  1153:                 foreach my $hostname (sort(keys(%ipchange))) {
1.121     raeburn  1154:                     $chgmail .= "| $hostname | $ipchange{$hostname} |\n";
1.117     raeburn  1155:                 }
                   1156:                 $chgmail .= "\n\n";
                   1157:                 if (open(my $mailh, "|/usr/lib/sendmail -oi -t -odb")) {
                   1158:                     print $mailh $chgmail;
                   1159:                     close($mailh);
                   1160:                     print "Sending mail notification of hostname/IP changes.\n";
                   1161:                 }
                   1162:             }
                   1163:         }
                   1164:     }
                   1165:     return;
                   1166: }
                   1167: 
1.107     raeburn  1168: sub clean_nosslverify {
                   1169:     my ($fh) = @_;
1.125   ! raeburn  1170:     my %unlinked;
1.107     raeburn  1171:     if (-d "$perlvar{'lonSockDir'}/nosslverify") {
                   1172:         if (opendir(my $dh,"$perlvar{'lonSockDir'}/nosslverify")) {
                   1173:             while (my $fname=readdir($dh)) {
                   1174:                 next if ($fname =~ /^\.+$/);
                   1175:                 if (unlink("/home/httpd/sockets/nosslverify/$fname")) {
                   1176:                     &log($fh,"Unlinking $fname<br />");
                   1177:                     $unlinked{$fname} = 1;
                   1178:                 }
                   1179:             }
                   1180:             closedir($dh);
                   1181:         }
                   1182:     }
                   1183:     &log($fh,"<p>Removed ".scalar(keys(%unlinked))." nosslverify clients</p>");
                   1184:     return %unlinked;
                   1185: }
                   1186: sub clean_lonc_childpids {
                   1187:     my $childpiddir = "$perlvar{'lonDocRoot'}/lon-status/loncchld";
                   1188:     if (-d $childpiddir) {
                   1189:         if (opendir(my $dh,$childpiddir)) {
                   1190:             while (my $fname=readdir($dh)) {
                   1191:                 next if ($fname =~ /^\.+$/);
                   1192:                 unlink("$childpiddir/$fname");
                   1193:             }
                   1194:             closedir($dh);
                   1195:         }
                   1196:     }
                   1197: }
                   1198: 
1.104     raeburn  1199: sub write_connection_config {
1.113     raeburn  1200:     my ($domconf,%connectssl,%changes);
                   1201:     $domconf = &get_domain_config();
1.104     raeburn  1202:     if (ref($domconf) eq 'HASH') {
                   1203:         if (ref($domconf->{'ssl'}) eq 'HASH') {
                   1204:             foreach my $connect ('connto','connfrom') {
                   1205:                 if (ref($domconf->{'ssl'}->{$connect}) eq 'HASH') {
                   1206:                     my ($sslreq,$sslnoreq,$currsetting);
                   1207:                     my %contypes;
                   1208:                     foreach my $type ('dom','intdom','other') {
                   1209:                         $connectssl{$connect.'_'.$type} = $domconf->{'ssl'}->{$connect}->{$type};
                   1210:                     }
                   1211:                 }
                   1212:             }
                   1213:         }
                   1214:         if (keys(%connectssl)) {
1.107     raeburn  1215:             my %currconf; 
                   1216:             if (open(my $fh,'<',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
                   1217:                 while (my $line = <$fh>) {
                   1218:                     chomp($line);
                   1219:                     my ($name,$value) = split(/=/,$line);
                   1220:                     if ($value =~ /^(?:no|yes|req)$/) {
                   1221:                         if ($name =~ /^conn(to|from)_(dom|intdom|other)$/) {
                   1222:                             $currconf{$name} = $value;
                   1223:                         }
                   1224:                     }
                   1225:                 }
                   1226:                 close($fh);
                   1227:             }
                   1228:             if (open(my $fh,'>',"$perlvar{'lonTabDir'}/connectionrules.tab")) {
1.104     raeburn  1229:                 my $count = 0;
                   1230:                 foreach my $key (sort(keys(%connectssl))) { 
                   1231:                     print $fh "$key=$connectssl{$key}\n";
1.107     raeburn  1232:                     if (exists($currconf{$key})) {
                   1233:                         unless ($currconf{$key} eq $connectssl{$key}) {
                   1234:                             $changes{$key} = 1;
                   1235:                         }
                   1236:                     } else {
                   1237:                         $changes{$key} = 1;
                   1238:                     }
1.104     raeburn  1239:                     $count ++;
                   1240:                 }
                   1241:                 close($fh);
                   1242:                 print "Completed writing SSL options for lonc/lond for $count items.\n";
                   1243:             }
                   1244:         } else {
                   1245:             print "Writing of SSL options skipped - no connection rules in domain configuration.\n";
                   1246:         }
                   1247:     } else {
                   1248:         print "Retrieval of SSL options for lonc/lond skipped - no configuration data available for domain.\n";
                   1249:     }
1.107     raeburn  1250:     return %changes;
1.104     raeburn  1251: }
                   1252: 
                   1253: sub get_domain_config {
1.113     raeburn  1254:     my ($dom,$primlibserv,$isprimary,$url,%confhash);
                   1255:     $dom = $perlvar{'lonDefDomain'};
                   1256:     $primlibserv = &Apache::lonnet::domain($dom,'primary');
                   1257:     if ($primlibserv eq $perlvar{'lonHostID'}) {
                   1258:         $isprimary = 1;
                   1259:     } elsif ($primlibserv ne '') {
                   1260:         my $protocol = $Apache::lonnet::protocol{$primlibserv};
                   1261:         my $hostname = &Apache::lonnet::hostname($primlibserv);
                   1262:         unless ($protocol eq 'https') {
                   1263:             $protocol = 'http';
                   1264:         }
1.116     raeburn  1265:         $url = $protocol.'://'.$hostname.'/cgi-bin/listdomconfig.pl?primary='.$primlibserv.'&format=raw';
1.113     raeburn  1266:     }
1.104     raeburn  1267:     if ($isprimary) {
                   1268:         my $lonusersdir = $perlvar{'lonUsersDir'};
                   1269:         my $fname = $lonusersdir.'/'.$dom.'/configuration.db';
                   1270:         if (-e $fname) {
                   1271:             my $dbref=&LONCAPA::locking_hash_tie($fname,&GDBM_READER());
                   1272:             if (ref($dbref) eq 'HASH') {
                   1273:                 foreach my $key (sort(keys(%{$dbref}))) {
                   1274:                     my $value = $dbref->{$key};
                   1275:                     if ($value =~ s/^__FROZEN__//) {
                   1276:                         $value = thaw(&LONCAPA::unescape($value));
                   1277:                     } else {
                   1278:                         $value = &LONCAPA::unescape($value);
                   1279:                     }
                   1280:                     $confhash{$key} = $value;
                   1281:                 }
                   1282:                 &LONCAPA::locking_hash_untie($dbref);
                   1283:             }
                   1284:         }
                   1285:     } else {
1.116     raeburn  1286:         my $request=new HTTP::Request('GET',$url);
                   1287:         my $response=&LONCAPA::LWPReq::makerequest($primlibserv,$request,'',\%perlvar,5);
                   1288:         unless ($response->is_error()) {
                   1289:             my $content = $response->content;
                   1290:             if ($content) {
                   1291:                 my @pairs=split(/\&/,$content);
1.104     raeburn  1292:                 foreach my $item (@pairs) {
                   1293:                     my ($key,$value)=split(/=/,$item,2);
                   1294:                     my $what = &LONCAPA::unescape($key);
                   1295:                     if ($value =~ s/^__FROZEN__//) {
                   1296:                         $value = thaw(&LONCAPA::unescape($value));
                   1297:                     } else {
                   1298:                         $value = &LONCAPA::unescape($value);
                   1299:                     }
                   1300:                     $confhash{$what}=$value;
                   1301:                 }
                   1302:             }
                   1303:         }
                   1304:     }
                   1305:     return \%confhash;
                   1306: }
                   1307: 
                   1308: sub write_hosttypes {
                   1309:     my %intdom = &Apache::lonnet::all_host_intdom();
                   1310:     my %hostdom = &Apache::lonnet::all_host_domain();
                   1311:     my $dom = $hostdom{$perlvar{'lonHostID'}};
                   1312:     my $internetdom = $intdom{$perlvar{'lonHostID'}};
1.107     raeburn  1313:     my %changes;
1.104     raeburn  1314:     if (($dom ne '') && ($internetdom ne '')) {
                   1315:         if (keys(%hostdom)) {
1.107     raeburn  1316:             my %currhosttypes;
                   1317:             if (open(my $fh,'<',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
                   1318:                 while (my $line = <$fh>) {
                   1319:                     chomp($line);
                   1320:                     my ($name,$value) = split(/:/,$line);
                   1321:                     if (($name ne '') && ($value =~ /^(dom|intdom|other)$/)) {
                   1322:                         $currhosttypes{$name} = $value;
                   1323:                     }
                   1324:                 }
                   1325:                 close($fh);
                   1326:             }
                   1327:             if (open(my $fh,'>',"$perlvar{'lonTabDir'}/hosttypes.tab")) {
1.104     raeburn  1328:                 my $count = 0;
                   1329:                 foreach my $lonid (sort(keys(%hostdom))) {
                   1330:                     my $type = 'other';
                   1331:                     if ($hostdom{$lonid} eq $dom) {
1.125   ! raeburn  1332:                         $type = 'dom';
1.104     raeburn  1333:                     } elsif ($intdom{$lonid} eq $internetdom) {
                   1334:                         $type = 'intdom';
                   1335:                     }
                   1336:                     print $fh "$lonid:$type\n";
1.107     raeburn  1337:                     if (exists($currhosttypes{$lonid})) {
                   1338:                         if ($type ne $currhosttypes{$lonid}) {
                   1339:                             $changes{$lonid} = 1;
                   1340:                         }
                   1341:                     } else {
                   1342:                         $changes{$lonid} = 1;
                   1343:                     }
1.104     raeburn  1344:                     $count ++;
                   1345:                 }
                   1346:                 close($fh);
                   1347:                 print "Completed writing host type data for $count hosts.\n";
                   1348:             }
                   1349:         } else {
                   1350:             print "Writing of host types skipped - no hosts found.\n";
                   1351:         }
                   1352:     } else {
                   1353:         print "Writing of host types skipped - could not determine this host's LON-CAPA domain or 'internet' domain.\n";
                   1354:     }
1.107     raeburn  1355:     return %changes;
1.104     raeburn  1356: }
                   1357: 
1.106     raeburn  1358: sub update_revocation_list {
1.107     raeburn  1359:     my ($result,$changed) = &Apache::lonnet::fetch_crl_pemfile();
                   1360:     if ($result eq 'ok') {
1.106     raeburn  1361:         print "Certificate Revocation List (from CA) updated.\n";
                   1362:     } else {
                   1363:         print "Certificate Revocation List from (CA) not updated.\n";
                   1364:     }
1.107     raeburn  1365:     return $changed;
                   1366: }
                   1367: 
                   1368: sub reset_nosslverify_pids {
1.108     raeburn  1369:     my ($fh,%sslrem) = @_;
1.107     raeburn  1370:     &checkon_daemon($fh,'lond',40000,'USR2');
                   1371:     my $loncpidfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
                   1372:     my $loncppid;
                   1373:     if ((-e $loncpidfile) && (open(my $pfh,'<',$loncpidfile))) {
                   1374:         $loncppid=<$pfh>;
                   1375:         chomp($loncppid);
                   1376:         close($pfh);
                   1377:         if ($loncppid =~ /^\d+$/) {
                   1378:             my %pids_by_host;
                   1379:             my $docdir = $perlvar{'lonDocRoot'};
                   1380:             if (-d "$docdir/lon-status/loncchld") {
                   1381:                 if (opendir(my $dh,"$docdir/lon-status/loncchld")) {
                   1382:                     while (my $file = readdir($dh)) {
                   1383:                         next if ($file =~ /^\./);
                   1384:                         if (open(my $fh,'<',"$docdir/lon-status/loncchld/$file")) {
                   1385:                             my $record = <$fh>;
                   1386:                             chomp($record);
                   1387:                             close($fh);
                   1388:                             my ($remotehost,$authmode) = split(/:/,$record);
                   1389:                             $pids_by_host{$remotehost}{$authmode}{$file} = 1;
                   1390:                         }
                   1391:                     }
                   1392:                     closedir($dh);
                   1393:                     if (keys(%pids_by_host)) {
                   1394:                         foreach my $host (keys(%pids_by_host)) {
                   1395:                             if ($sslrem{$host}) {
                   1396:                                 if (ref($pids_by_host{$host}) eq 'HASH') {
                   1397:                                     if (ref($pids_by_host{$host}{'insecure'}) eq 'HASH') {
1.109     raeburn  1398:                                         if (keys(%{$pids_by_host{$host}{'insecure'}})) {
                   1399:                                             foreach my $pid (keys(%{$pids_by_host{$host}{'insecure'}})) {
1.107     raeburn  1400:                                                 if (open(PIPE,"ps -o ppid= -p $pid |")) {
                   1401:                                                     my $ppid = <PIPE>;
                   1402:                                                     chomp($ppid);
                   1403:                                                     close(PIPE);
                   1404:                                                     $ppid =~ s/(^\s+|\s+$)//g;
                   1405:                                                     if (($ppid == $loncppid) && (kill 0 => $pid)) {
                   1406:                                                         kill QUIT => $pid;
                   1407:                                                     }
                   1408:                                                 }
                   1409:                                             }
                   1410:                                         }
                   1411:                                     }
                   1412:                                 }
                   1413:                             }
                   1414:                         }
                   1415:                     }
                   1416:                 }
                   1417:             }
                   1418:         }
                   1419:     }
                   1420:     return;
1.106     raeburn  1421: }
                   1422: 
1.114     raeburn  1423: sub get_permcount_settings {
                   1424:     my ($domconf) = @_;
                   1425:     my ($defaults,$names) = &Apache::loncommon::lon_status_items();
                   1426:     my (%weights,$threshold,$sysmail,$reportstatus,%exclusions);
                   1427:     foreach my $type ('E','W','N','U') {
                   1428:         $weights{$type} = $defaults->{$type};
                   1429:     }
                   1430:     $threshold = $defaults->{'threshold'};
                   1431:     $sysmail = $defaults->{'sysmail'};
                   1432:     $reportstatus = 1;
                   1433:     if (ref($domconf) eq 'HASH') {
                   1434:         if (ref($domconf->{'contacts'}) eq 'HASH') {
                   1435:             if ($domconf->{'contacts'}{'reportstatus'} == 0) {
                   1436:                 $reportstatus = 0;
                   1437:             }
                   1438:             if (ref($domconf->{'contacts'}{'lonstatus'}) eq 'HASH') {
                   1439:                 if (ref($domconf->{'contacts'}{'lonstatus'}{weights}) eq 'HASH') {
                   1440:                     foreach my $type ('E','W','N','U') {
                   1441:                         if (exists($domconf->{'contacts'}{'lonstatus'}{weights}{$type})) {
                   1442:                             $weights{$type} = $domconf->{'contacts'}{'lonstatus'}{weights}{$type};
                   1443:                         }
                   1444:                     }
                   1445:                 }
                   1446:                 if (ref($domconf->{'contacts'}{'lonstatus'}{'excluded'}) eq 'ARRAY') {
                   1447:                     my @excluded = @{$domconf->{'contacts'}{'lonstatus'}{'excluded'}};
                   1448:                     if (@excluded) {
                   1449:                         map { $exclusions{$_} = 1; } @excluded;
                   1450:                     }
                   1451:                 }
                   1452:                 if (exists($domconf->{'contacts'}{'lonstatus'}{'threshold'})) {
                   1453:                     $threshold = $domconf->{'contacts'}{'lonstatus'}{'threshold'};
                   1454:                 }
                   1455:                 if (exists($domconf->{'contacts'}{'lonstatus'}{'sysmail'})) {
                   1456:                     $sysmail = $domconf->{'contacts'}{'lonstatus'}{'sysmail'};
                   1457:                 }
                   1458:             }
                   1459:         }
                   1460:     }
                   1461:     return ($threshold,$sysmail,$reportstatus,\%weights,\%exclusions);
                   1462: }
                   1463: 
                   1464: sub read_serverhomeIDs {
                   1465:     my %server;
                   1466:     if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") {
                   1467:         if (open(my $fh,'<',"$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {
                   1468:             while (<$fh>) {
                   1469:                 my($host,$id) = split(/:/);
                   1470:                 chomp($id);
                   1471:                 $server{$host} = $id;
                   1472:             }
                   1473:             close($fh);
                   1474:         }
                   1475:     }
                   1476:     return %server;
                   1477: }
                   1478: 
1.46      albertel 1479: sub send_mail {
1.113     raeburn  1480:     my ($sysmail,$reportstatus) = @_;
1.79      raeburn  1481:     my $defdom = $perlvar{'lonDefDomain'};
                   1482:     my $origmail = $perlvar{'lonAdmEMail'};
1.78      raeburn  1483:     my $emailto = &Apache::loncommon::build_recipient_list(undef,
                   1484:                                    'lonstatusmail',$defdom,$origmail);
1.113     raeburn  1485:     if (($totalcount>$sysmail) && ($reportstatus)) {
1.43      albertel 1486: 	$emailto.=",$perlvar{'lonSysEMail'}";
                   1487:     }
1.101     raeburn  1488:     my $from;
                   1489:     my $hostname=`/bin/hostname`;
                   1490:     chop($hostname);
                   1491:     $hostname=~s/[^\w\.]//g;
                   1492:     if ($hostname) {
                   1493:         $from = 'www@'.$hostname;
                   1494:     }
                   1495:     my $subj="LON: $perlvar{'lonHostID'} E:$errors W:$warnings N:$notices";
                   1496:     my $loncronmail = "To: $emailto\n".
                   1497:                       "From: $from\n".
                   1498:                       "Subject: ".$subj."\n".
                   1499:                       "Content-type: text/html\; charset=UTF-8\n".
                   1500:                       "MIME-Version: 1.0\n\n";
                   1501:     if (open(my $fh,"<$statusdir/index.html")) {
                   1502:         while (<$fh>) {
                   1503:             $loncronmail .= $_;
                   1504:         }
                   1505:         close($fh);
                   1506:     } else {
                   1507:         $loncronmail .= "Failed to read from http://$hostname/lon-status/index.html\n";
                   1508:     }
                   1509:     $loncronmail .= "\n\n";
                   1510:     if (open(my $mailh, "|/usr/lib/sendmail -oi -t -odb")) {
                   1511:         print $mailh $loncronmail;
                   1512:         close($mailh);
                   1513:         print "Sending mail.\n";
                   1514:     } else {
                   1515:         print "Sending mail failed.\n";
1.52      albertel 1516:     }
1.1       albertel 1517: }
1.46      albertel 1518: 
1.49      albertel 1519: sub usage {
                   1520:     print(<<USAGE);
1.100     bisitz   1521: loncron - housekeeping program that checks up on various parts of LON-CAPA
1.49      albertel 1522: 
                   1523: Options:
1.71      albertel 1524:    --help     Display 
1.49      albertel 1525:    --noemail  Do not send the status email
                   1526:    --justcheckconnections  Only check the current status of the lonc/d
                   1527:                                 connections, do not send emails do not
                   1528:                                 check if the daemons are running, do not
                   1529:                                 generate lon-status
                   1530:    --justcheckdaemons      Only check that all of the Lon-CAPA daemons are
                   1531:                                 running, do not send emails do not
                   1532:                                 check the lonc/d connections, do not
                   1533:                                 generate lon-status
1.59      albertel 1534:    --justreload            Only tell the daemons to reload the config files,
                   1535: 				do not send emails do not
                   1536:                                 check if the daemons are running, do not
                   1537:                                 generate lon-status
1.118     raeburn  1538:    --justiptables          Only update the dynamic iptables rules for the
                   1539:                                 lond port; do not send emails, do not
                   1540:                                 check if the daemons are running, do not
                   1541:                                 generate lon-status
1.49      albertel 1542: USAGE
                   1543: }
                   1544: 
1.46      albertel 1545: # ================================================================ Main Program
                   1546: sub main () {
1.71      albertel 1547:     my ($help,$justcheckdaemons,$noemail,$justcheckconnections,
1.118     raeburn  1548: 	$justreload,$justiptables);
1.49      albertel 1549:     &GetOptions("help"                 => \$help,
                   1550: 		"justcheckdaemons"     => \$justcheckdaemons,
                   1551: 		"noemail"              => \$noemail,
1.59      albertel 1552: 		"justcheckconnections" => \$justcheckconnections,
1.118     raeburn  1553: 		"justreload"           => \$justreload,
                   1554:                 "justiptables"         => \$justiptables
1.49      albertel 1555: 		);
                   1556:     if ($help) { &usage(); return; }
1.46      albertel 1557: # --------------------------------- Read loncapa_apache.conf and loncapa.conf
                   1558:     my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');
                   1559:     %perlvar=%{$perlvarref};
                   1560:     undef $perlvarref;
                   1561:     delete $perlvar{'lonReceipt'}; # remove since sensitive and not needed
                   1562:     delete $perlvar{'lonSqlAccess'}; # remove since sensitive and not needed
1.75      albertel 1563:     chdir($perlvar{'lonDaemons'});
1.46      albertel 1564: # --------------------------------------- Make sure that LON-CAPA is configured
                   1565: # I only test for one thing here (lonHostID).  This is just a safeguard.
                   1566:     if ('{[[[[lonHostID]]]]}' eq $perlvar{'lonHostID'}) {
                   1567: 	print("Unconfigured machine.\n");
                   1568: 	my $emailto=$perlvar{'lonSysEMail'};
1.123     raeburn  1569: 	my $hostname = Sys::Hostname::FQDN::fqdn();
                   1570: 	$hostname=~s/\.+/./g;
                   1571: 	$hostname=~s/\-+/-/g;
                   1572: 	$hostname=~s/[^\w\.-]//g; # make sure is safe to pass through shell
1.46      albertel 1573: 	my $subj="LON: Unconfigured machine $hostname";
1.112     raeburn  1574: 	system("echo 'Unconfigured machine $hostname.' |".
                   1575:                " mail -s '$subj' $emailto > /dev/null");
1.46      albertel 1576: 	exit 1;
                   1577:     }
                   1578: 
                   1579: # ----------------------------- Make sure this process is running from user=www
                   1580:     my $wwwid=getpwnam('www');
                   1581:     if ($wwwid!=$<) {
1.100     bisitz   1582: 	print("User ID mismatch. This program must be run as user 'www'.\n");
1.46      albertel 1583: 	my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
                   1584: 	my $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
1.112     raeburn  1585: 	system("echo 'User ID mismatch. loncron must be run as user www.' |".
                   1586:                " mail -s '$subj' $emailto > /dev/null");
1.46      albertel 1587: 	exit 1;
                   1588:     }
                   1589: 
1.72      albertel 1590: # -------------------------------------------- Force reload of host information
1.103     raeburn  1591:     my $nomemcache;
                   1592:     if ($justcheckdaemons) {
                   1593:         $nomemcache=1;
                   1594:         my $memcachepidfile="$perlvar{'lonDaemons'}/logs/memcached.pid";
                   1595:         my $memcachepid;
                   1596:         if (-e $memcachepidfile) {
                   1597:             my $memfh=IO::File->new($memcachepidfile);
                   1598:             $memcachepid=<$memfh>;
                   1599:             chomp($memcachepid);
                   1600:             if ($memcachepid =~ /^\d+$/ && kill 0 => $memcachepid) {
                   1601:                 undef($nomemcache);
                   1602:             }
                   1603:         }
                   1604:     }
1.118     raeburn  1605:     if (!$justiptables) {
                   1606:         &Apache::lonnet::load_hosts_tab(1,$nomemcache);
                   1607:         &Apache::lonnet::load_domain_tab(1,$nomemcache);
                   1608:         &Apache::lonnet::get_iphost(1,$nomemcache);
                   1609:     }
1.46      albertel 1610: 
1.125   ! raeburn  1611: # ----------------------------------------- Force firewall update for lond port
1.81      raeburn  1612: 
                   1613:     if ((!$justcheckdaemons) && (!$justreload)) {
                   1614:         my $now = time;
                   1615:         my $tmpfile = $perlvar{'lonDaemons'}.'/tmp/lciptables_iphost_'.
                   1616:                       $now.$$.int(rand(10000));
                   1617:         if (open(my $fh,">$tmpfile")) {
                   1618:             my %iphosts = &Apache::lonnet::get_iphost();
                   1619:             foreach my $key (keys(%iphosts)) {
                   1620:                 print $fh "$key\n";
                   1621:             }
                   1622:             close($fh);
1.89      raeburn  1623:             if (&LONCAPA::try_to_lock('/tmp/lock_lciptables')) {
                   1624:                 my $execpath = $perlvar{'lonDaemons'}.'/lciptables';
                   1625:                 system("$execpath $tmpfile");
1.125   ! raeburn  1626:                 unlink('/tmp/lock_lciptables');  # Remove the lock file.
1.89      raeburn  1627:             }
1.88      raeburn  1628:             unlink($tmpfile);
1.81      raeburn  1629:         }
                   1630:     }
                   1631: 
1.46      albertel 1632: # ---------------------------------------------------------------- Start report
                   1633: 
                   1634:     $errors=0;
                   1635:     $warnings=0;
                   1636:     $notices=0;
                   1637: 
1.125   ! raeburn  1638: 
1.49      albertel 1639:     my $fh;
1.118     raeburn  1640:     if (!$justcheckdaemons && !$justcheckconnections && !$justreload && !$justiptables) {
1.72      albertel 1641: 	$fh=&start_logging();
1.49      albertel 1642: 
                   1643: 	&log_machine_info($fh);
                   1644: 	&clean_tmp($fh);
                   1645: 	&clean_lonIDs($fh);
1.115     raeburn  1646:         &clean_balanceIDs($fh);
1.102     raeburn  1647:         &clean_webDAV_sessionIDs($fh);
1.119     raeburn  1648:         &clean_ltiIDs($fh);
1.49      albertel 1649: 	&check_httpd_logs($fh);
                   1650: 	&rotate_lonnet_logs($fh);
1.73      albertel 1651: 	&rotate_other_logs($fh);
1.49      albertel 1652:     }
1.118     raeburn  1653:     if (!$justcheckconnections && !$justreload && !$justiptables) {
1.76      albertel 1654: 	&checkon_daemon($fh,'lonmemcached',40000);
1.49      albertel 1655: 	&checkon_daemon($fh,'lonsql',200000);
1.63      albertel 1656: 	if ( &checkon_daemon($fh,'lond',40000,'USR1') eq 'running') {
                   1657: 	    &checkon_daemon($fh,'lond',40000,'USR2');
                   1658: 	}
1.71      albertel 1659: 	&checkon_daemon($fh,'lonc',40000,'USR1');
1.70      raeburn  1660:         &checkon_daemon($fh,'lonmaxima',40000);
1.80      www      1661:         &checkon_daemon($fh,'lonr',40000);
1.49      albertel 1662:     }
1.59      albertel 1663:     if ($justreload) {
1.107     raeburn  1664:         &clean_nosslverify($fh);
1.104     raeburn  1665:         &write_connection_config();
                   1666:         &write_hosttypes();
1.107     raeburn  1667:         &update_revocation_list(); 
1.59      albertel 1668: 	&checkon_daemon($fh,'lond',40000,'USR2');
1.71      albertel 1669: 	&checkon_daemon($fh,'lonc',40000,'USR2');
1.59      albertel 1670:     }
1.63      albertel 1671:     if ($justcheckconnections) {
1.72      albertel 1672: 	&test_connections($fh);
1.49      albertel 1673:     }
1.118     raeburn  1674:     if (!$justcheckdaemons && !$justcheckconnections && !$justreload && !$justiptables) {
1.114     raeburn  1675:         my $domconf = &get_domain_config();
                   1676:         my ($threshold,$sysmail,$reportstatus,$weightsref,$exclusionsref) =
                   1677:             &get_permcount_settings($domconf);
                   1678: 	&check_delayed_msg($fh,$weightsref,$exclusionsref);
1.87      raeburn  1679:         &write_loncaparevs();
                   1680:         &write_serverhomeIDs();
1.97      raeburn  1681: 	&write_checksums();
1.117     raeburn  1682:         &write_hostips();
1.107     raeburn  1683:         my %sslrem = &clean_nosslverify($fh);
                   1684:         my %conchgs = &write_connection_config();
                   1685:         my %hosttypechgs = &write_hosttypes();
                   1686:         my $hadcrlchg = &update_revocation_list();
1.108     raeburn  1687:         if ((keys(%conchgs) > 0) || (keys(%hosttypechgs) > 0) ||
1.107     raeburn  1688:             $hadcrlchg || (keys(%sslrem) > 0)) {
                   1689:             &checkon_daemon($fh,'lond',40000,'USR2');
1.108     raeburn  1690:             &reset_nosslverify_pids($fh,%sslrem);
1.107     raeburn  1691:         }
1.114     raeburn  1692:         &finish_logging($fh,$weightsref);
                   1693:         &log_simplestatus();
                   1694:         if ($totalcount>$threshold && !$noemail) { &send_mail($sysmail,$reportstatus); }
1.49      albertel 1695:     }
1.46      albertel 1696: }
                   1697: 
                   1698: &main();
1.1       albertel 1699: 1;
                   1700: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.