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