# The LearningOnline Network with CAPA
# Checksum installed LON-CAPA modules and some configuration files
#
# $Id: Checksumming.pm,v 1.9 2018/10/24 18:16:14 raeburn Exp $
#
# The LearningOnline Network with CAPA
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
package LONCAPA::Checksumming;
use strict;
use lib '/home/httpd/lib/perl/';
use Apache::lonlocal();
use Apache::loncommon();
use Digest::SHA;
sub get_checksums {
my ($distro,$londaemons,$lonlib,$lonincludes,$lontabdir) = @_;
my $output;
my (%versions,%chksums);
my $dirh;
my $revtag = '$Id:';
my @paths;
if ($londaemons) {
push(@paths,($londaemons.'/*',
$londaemons.'/debug/*.pl'));
}
if ($lonlib) {
push(@paths,($lonlib.'/perl/Apache/*.pm',
$lonlib.'/perl/Apache/localize/*.pm',
$lonlib.'/perl/LONCAPA/*.pm',
$lonlib.'/perl/AlgParser.pm',
$lonlib.'/perl/LONCAPA.pm',
$lonlib.'/perl/Safe.pm',
$lonlib.'/perl/*-std.pm',
$lonlib.'/perl/HTML/*.pm',
$lonlib.'/perl/Safe.pm'));
}
if ($lonincludes) {
push(@paths,$lonincludes.'/*.lcpm');
}
push(@paths,('/home/httpd/cgi-bin/*.pl','/home/httpd/cgi-bin/*.png'));
my $confdir = '/etc/httpd/conf';
if ($distro =~ /^(ubuntu|debian)(\d+)$/) {
$confdir = '/etc/apache2';
} elsif ($distro =~ /^sles(\d+)$/) {
if ($1 >= 10) {
$confdir = '/etc/apache2';
}
} elsif ($distro =~ /^suse(\d+\.\d+)$/) {
if ($1 >= 10.0) {
$confdir = '/etc/apache2';
}
}
push(@paths,("$confdir/loncapa_apache.conf","$confdir/startup.pl"));
if ($lontabdir) {
push(@paths,$lontabdir.'/mydesk.tab');
}
if (@paths) {
my $pathstr = join (' ',@paths);
if (open($dirh,"grep '$revtag' $pathstr 2>&1 |")) {
while (my $line=<$dirh>) {
if ($line =~ m{^([^#]+):#\s\$Id:\s[\w.]+,v\s([\d.]+)\s}) {
$versions{$1} = $2;
}
}
close($dirh);
}
if ($londaemons) {
my @binaries = qw (apachereload lchttpdlogs lcinstallfile lciptables lcnfsoff lcnfson lcpasswd lcuserdel pwchange);
foreach my $file (@binaries) {
next if ($versions{"$londaemons/$file"});
if (-B "$londaemons/$file") {
if (-T $londaemons.'/.'.$file) {
if (open(my $fh,'<',$londaemons.'/.'.$file)) {
while (my $line=<$fh>) {
if ($line =~ m{^#\s\$Id:\s[\w.]+,v\s([\d.]+)\s}) {
$versions{"$londaemons/$file"} = $1;
last;
}
}
close($fh);
}
if ($versions{"$londaemons/$file"}) {
if (open(my $fh,'<',$londaemons.'/.'.$file)) {
binmode $fh;
my $sha_obj = Digest::SHA->new();
$sha_obj->addfile($fh);
$chksums{"$londaemons/$file"} = $sha_obj->hexdigest;
close($fh);
}
}
}
}
}
}
foreach my $key (sort(keys(%versions))) {
next if ($key =~ /\.lpmlsave$/);
unless (exists($chksums{$key})) {
if (open(my $fh,"<$key")) {
binmode $fh;
my $sha_obj = Digest::SHA->new();
$sha_obj->addfile($fh);
$chksums{$key} = $sha_obj->hexdigest;
close($fh);
}
}
$output .= "$key,$versions{$key},$chksums{$key}\n";
}
}
if ($lontabdir ne '') {
if (open(my $tabfh,">$lontabdir/lonchksums.tab")) {
print $tabfh '# Last written: '.localtime(time)."\n";
print $tabfh "$output\n";
close($tabfh);
}
}
return (\%chksums,\%versions);
}
sub compare_checksums {
my ($target,$lonhost,$version,$serversums,$serverversions) = @_;
my ($message,$numchg,$linefeed);
if ($target eq 'web') {
$linefeed = '
';
} else {
$linefeed = "\n";
}
if (!$Apache::lonlocal::lh) {
&Apache::lonlocal::get_language_handle();
}
if ((ref($serversums) eq 'HASH') && (keys(%{$serversums}))) {
my $checksums = &Apache::lonnet::fetch_dns_checksums();
my (%extra,%missing,%diffs,%stdsums,%stdversions);
if (ref($checksums) eq 'HASH') {
if (ref($checksums->{'sums'}) eq 'HASH') {
%stdsums = %{$checksums->{'sums'}};
}
if (ref($checksums->{'versions'}) eq 'HASH') {
%stdversions = %{$checksums->{'versions'}};
}
if (keys(%stdsums)) {
foreach my $key (keys(%stdsums)) {
if (exists($serversums->{$key})) {
if ($serversums->{$key} ne $stdsums{$key}) {
$diffs{$key} = 1;
$numchg ++;
}
} else {
$missing{$key} = 1;
$numchg ++;
}
}
foreach my $key (keys(%{$serversums})) {
unless (exists($stdsums{$key})) {
$extra{$key} = 1;
$numchg ++;
}
}
}
if ($numchg) {
$message =
&Apache::lonlocal::mt('[quant,_1,difference was,differences were] found'.
' between LON-CAPA modules installed on your server [_2]'.
' and those expected for the LON-CAPA version you are'.
' currently running.',$numchg,"($lonhost)$linefeed");
if ($target eq 'web') {
$message = '
'.$message.'
'; } else { $message .= "\n\n"; } my (@diffversion,@modified); if (keys(%diffs) > 0) { foreach my $file (sort(keys(%diffs))) { if ($serverversions->{$file} ne $stdversions{$file}) { push(@diffversion,$file); } else { push(@modified,$file); } } if (@diffversion > 0) { my $text = &Apache::lonlocal::mt('The following [quant,_1,file is a,files are]'. ' different version(s) from that expected for LON-CAPA [_2]:', scalar(@diffversion),$version); if ($target eq 'web') { $message .= ''.$text.'
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()."\n". ''.$text.'
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()."\n". ''.$text.'
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()."\n". ''.$text.'
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()."\n". '