Annotation of loncom/configuration/Checksumming.pm, revision 1.9

1.1       raeburn     1: # The LearningOnline Network with CAPA
                      2: # Checksum installed LON-CAPA modules and some configuration files
                      3: #
1.9     ! raeburn     4: # $Id: Checksumming.pm,v 1.8 2017/06/30 14:53:39 raeburn Exp $
1.1       raeburn     5: #
                      6: # The LearningOnline Network with CAPA
                      7: #
                      8: # Copyright Michigan State University Board of Trustees
                      9: #
                     10: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     11: #
                     12: # LON-CAPA is free software; you can redistribute it and/or modify
                     13: # it under the terms of the GNU General Public License as published by
                     14: # the Free Software Foundation; either version 2 of the License, or
                     15: # (at your option) any later version.
                     16: #
                     17: # LON-CAPA is distributed in the hope that it will be useful,
                     18: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     19: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     20: # GNU General Public License for more details.
                     21: #
                     22: # You should have received a copy of the GNU General Public License
                     23: # along with LON-CAPA; if not, write to the Free Software
                     24: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     25: #
                     26: # /home/httpd/html/adm/gpl.txt
                     27: #
                     28: # http://www.lon-capa.org/
                     29: #
                     30: 
                     31: package LONCAPA::Checksumming;
                     32: 
                     33: use strict;
                     34: use lib '/home/httpd/lib/perl/';
                     35: use Apache::lonlocal();
                     36: use Apache::loncommon();
1.7       raeburn    37: use Digest::SHA;
1.1       raeburn    38: 
                     39: sub get_checksums {
                     40:     my ($distro,$londaemons,$lonlib,$lonincludes,$lontabdir) = @_;
                     41:     my $output;
                     42:     my (%versions,%chksums);
                     43:     my $dirh;
                     44:     my $revtag = '$Id:';
                     45:     my @paths;
                     46:     if ($londaemons) {
                     47:         push(@paths,($londaemons.'/*',
                     48:                      $londaemons.'/debug/*.pl'));
                     49:     }
                     50:     if ($lonlib) {
                     51:         push(@paths,($lonlib.'/perl/Apache/*.pm',
                     52:                      $lonlib.'/perl/Apache/localize/*.pm',
                     53:                      $lonlib.'/perl/LONCAPA/*.pm',
                     54:                      $lonlib.'/perl/AlgParser.pm',
                     55:                      $lonlib.'/perl/LONCAPA.pm',
                     56:                      $lonlib.'/perl/Safe.pm',
                     57:                      $lonlib.'/perl/*-std.pm',
                     58:                      $lonlib.'/perl/HTML/*.pm',
                     59:                      $lonlib.'/perl/Safe.pm'));
                     60:     }
                     61:     if ($lonincludes) {
                     62:         push(@paths,$lonincludes.'/*.lcpm');
                     63:     }
                     64:     push(@paths,('/home/httpd/cgi-bin/*.pl','/home/httpd/cgi-bin/*.png'));
                     65:     my $confdir = '/etc/httpd/conf';
                     66:     if ($distro =~ /^(ubuntu|debian)(\d+)$/) {
                     67:         $confdir = '/etc/apache2';
                     68:     } elsif ($distro =~ /^sles(\d+)$/) {
                     69:         if ($1 >= 10) {
                     70:             $confdir = '/etc/apache2';
                     71:         }
                     72:     } elsif ($distro =~ /^suse(\d+\.\d+)$/) {
                     73:         if ($1 >= 10.0) {
                     74:             $confdir = '/etc/apache2';
                     75:         }
                     76:     }
                     77:     push(@paths,("$confdir/loncapa_apache.conf","$confdir/startup.pl"));
1.8       raeburn    78:     if ($lontabdir) {
                     79:         push(@paths,$lontabdir.'/mydesk.tab');
                     80:     }
1.1       raeburn    81:     if (@paths) {
                     82:         my $pathstr = join (' ',@paths);
1.5       raeburn    83:         if (open($dirh,"grep '$revtag' $pathstr 2>&1 |")) {
1.1       raeburn    84:             while (my $line=<$dirh>) {
                     85:                 if ($line =~ m{^([^#]+):#\s\$Id:\s[\w.]+,v\s([\d.]+)\s}) {
                     86:                     $versions{$1} = $2;
                     87:                 }
                     88:             }
                     89:             close($dirh);
                     90:         }
1.9     ! raeburn    91:         if ($londaemons) {
        !            92:             my @binaries = qw (apachereload lchttpdlogs lcinstallfile lciptables lcnfsoff lcnfson lcpasswd lcuserdel pwchange);
        !            93:             foreach my $file (@binaries) {
        !            94:                 next if ($versions{"$londaemons/$file"});
        !            95:                 if (-B "$londaemons/$file") {
        !            96:                     if (-T $londaemons.'/.'.$file) {
        !            97:                         if (open(my $fh,'<',$londaemons.'/.'.$file)) {
        !            98:                             while (my $line=<$fh>) {
        !            99:                                 if ($line =~ m{^#\s\$Id:\s[\w.]+,v\s([\d.]+)\s}) {
        !           100:                                     $versions{"$londaemons/$file"} = $1;
        !           101:                                     last;
        !           102:                                 }
        !           103:                             }
        !           104:                             close($fh);
        !           105:                         }
        !           106:                         if ($versions{"$londaemons/$file"}) {
        !           107:                             if (open(my $fh,'<',$londaemons.'/.'.$file)) {
        !           108:                                 binmode $fh;
        !           109:                                 my $sha_obj = Digest::SHA->new();
        !           110:                                 $sha_obj->addfile($fh);
        !           111:                                 $chksums{"$londaemons/$file"} = $sha_obj->hexdigest;
        !           112:                                 close($fh);
        !           113:                             }
        !           114:                         }
        !           115:                     }
        !           116:                 }
        !           117:             }
        !           118:         }
1.1       raeburn   119:         foreach my $key (sort(keys(%versions))) {
                    120:             next if ($key =~ /\.lpmlsave$/);
1.9     ! raeburn   121:             unless (exists($chksums{$key})) {
        !           122:                 if (open(my $fh,"<$key")) {
        !           123:                     binmode $fh;
        !           124:                     my $sha_obj = Digest::SHA->new();
        !           125:                     $sha_obj->addfile($fh);
        !           126:                     $chksums{$key} = $sha_obj->hexdigest;
        !           127:                     close($fh);
        !           128:                 }
1.1       raeburn   129:             }
1.9     ! raeburn   130:             $output .= "$key,$versions{$key},$chksums{$key}\n";
1.1       raeburn   131:         }
                    132:     }
                    133:     if ($lontabdir ne '') {
                    134:         if (open(my $tabfh,">$lontabdir/lonchksums.tab")) {
                    135:             print $tabfh '# Last written: '.localtime(time)."\n";
                    136:             print $tabfh "$output\n";
                    137:             close($tabfh);
                    138:         }
                    139:     }
                    140:     return (\%chksums,\%versions);
                    141: }
                    142: 
                    143: sub compare_checksums {
                    144:     my ($target,$lonhost,$version,$serversums,$serverversions) = @_;
1.2       raeburn   145:     my ($message,$numchg,$linefeed);
1.3       raeburn   146:     if ($target eq 'web') {
1.2       raeburn   147:         $linefeed = '<br />';
                    148:     } else {
                    149:         $linefeed = "\n";
                    150:     }
1.5       raeburn   151:     if (!$Apache::lonlocal::lh) {
                    152:         &Apache::lonlocal::get_language_handle();
                    153:     }
1.1       raeburn   154:     if ((ref($serversums) eq 'HASH') && (keys(%{$serversums}))) {
                    155:         my $checksums = &Apache::lonnet::fetch_dns_checksums();
                    156:         my (%extra,%missing,%diffs,%stdsums,%stdversions);
                    157:         if (ref($checksums) eq 'HASH') {
                    158:             if (ref($checksums->{'sums'}) eq 'HASH') {
                    159:                 %stdsums = %{$checksums->{'sums'}};
                    160:             }
                    161:             if (ref($checksums->{'versions'}) eq 'HASH') {
                    162:                 %stdversions = %{$checksums->{'versions'}};
                    163:             }
                    164:             if (keys(%stdsums)) {
                    165:                 foreach my $key (keys(%stdsums)) {
                    166:                     if (exists($serversums->{$key})) {
                    167:                         if ($serversums->{$key} ne $stdsums{$key}) {
                    168:                             $diffs{$key} = 1;
                    169:                             $numchg ++;
                    170:                         }
                    171:                     } else {
1.9     ! raeburn   172:                         $missing{$key} = 1;
        !           173:                         $numchg ++;
1.1       raeburn   174:                     }
                    175:                 }
                    176:                 foreach my $key (keys(%{$serversums})) {
                    177:                     unless (exists($stdsums{$key})) {
                    178:                         $extra{$key} = 1;
                    179:                         $numchg ++;
                    180:                     }
                    181:                 }
                    182:             }
                    183:             if ($numchg) {
1.2       raeburn   184:                 $message =
1.1       raeburn   185:                     &Apache::lonlocal::mt('[quant,_1,difference was,differences were] found'.
1.2       raeburn   186:                                           ' between LON-CAPA modules installed on your server [_2]'.
                    187:                                           ' and those expected for the LON-CAPA version you are'.
                    188:                                           ' currently running.',$numchg,"($lonhost)$linefeed");
1.1       raeburn   189:                 if ($target eq 'web') {
                    190:                     $message = '<p>'.$message.'</p>';
                    191:                 } else {
                    192:                     $message .= "\n\n";
                    193:                 }
                    194:                 my (@diffversion,@modified);
                    195:                 if (keys(%diffs) > 0) {
                    196:                     foreach my $file (sort(keys(%diffs))) {
                    197:                         if ($serverversions->{$file} ne $stdversions{$file}) {
                    198:                             push(@diffversion,$file);
                    199:                         } else {
                    200:                             push(@modified,$file);
                    201:                         }
                    202:                     }
                    203:                     if (@diffversion > 0) {
1.2       raeburn   204:                         my $text =
                    205:                             &Apache::lonlocal::mt('The following [quant,_1,file is a,files are]'.
1.1       raeburn   206:                                                   ' different version(s) from that expected for LON-CAPA [_2]:',
                    207:                                                   scalar(@diffversion),$version);
                    208:                         if ($target eq 'web') {
                    209:                             $message .= '<p>'.$text.'</p>'.
                    210:                                         &Apache::loncommon::start_data_table().
                    211:                                         &Apache::loncommon::start_data_table_header_row()."\n".
                    212:                                         '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
                    213:                                         '<th>'.&Apache::lonlocal::mt('Server version').'</th>'."\n".
                    214:                                         '<th>'.&Apache::lonlocal::mt('Expected version').'</th>'."\n".
                    215:                                         &Apache::loncommon::end_data_table_header_row()."\n";
                    216:                         } else {
                    217:                             $message .= "$text\n";
                    218:                         }
                    219:                         foreach my $file (sort(@diffversion)) {
                    220:                             my $revnum = $stdversions{$file};
                    221:                             if ($target eq 'web') {
                    222:                                 $message .=  &Apache::loncommon::start_data_table_row().
1.2       raeburn   223:                                              '<td>'.$file.'</td>'."\n".
1.1       raeburn   224:                                              '<td>'.$serverversions->{$file}.'</td>'."\n".
                    225:                                              '<td>'.$revnum.'</td>'."\n".
                    226:                                              &Apache::loncommon::end_data_table_row()."\n";
                    227:                             } else {
                    228:                                 $message .= $file.' '.
                    229:                                             &Apache::lonlocal::mt('(local rev: [_1])',
                    230:                                                                   $serverversions->{$file});
                    231:                                 if ($revnum) {
                    232:                                     $message .= '; '.
                    233:                                                 &Apache::lonlocal::mt('(expected rev: [_1])',
                    234:                                                                       $revnum);
                    235:                                 }
                    236:                                 $message .= "\n";
                    237:                             }
                    238:                         }
1.2       raeburn   239:                         if ($target eq 'web') {
                    240:                             $message .= &Apache::loncommon::end_data_table().'<br />';
                    241:                         } else {
                    242:                             $message .= "\n";
                    243:                         }
1.1       raeburn   244:                     }
                    245:                     if (@modified > 0) {
1.2       raeburn   246:                         my $text =
1.1       raeburn   247:                             &Apache::lonlocal::mt('The following [quant,_1,file appears,files appear]'.
                    248:                                                   ' to have been modified locally:',scalar(@modified));
                    249:                         if ($target eq 'web') {
                    250:                             $message .= '<p>'.$text.'</p>'.
                    251:                                         &Apache::loncommon::start_data_table().
                    252:                                         &Apache::loncommon::start_data_table_header_row()."\n".
                    253:                                         '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
                    254:                                         '<th>'.&Apache::lonlocal::mt('Version').'</th>'."\n".
                    255:                                         &Apache::loncommon::end_data_table_header_row()."\n";
                    256:                         } else {
                    257:                             $message .= "$text\n";
                    258:                         }
                    259:                         foreach my $file (sort(@modified)) {
                    260:                             if ($target eq 'web') {
                    261:                                 $message .= &Apache::loncommon::start_data_table_row()."\n".
                    262:                                             '<td>'.$file.'</td>'."\n".
                    263:                                             '<td>'.$serverversions->{$file}.'</td>'."\n".
                    264:                                             &Apache::loncommon::end_data_table_row()."\n";
                    265:                             } else {
                    266:                                 $message .= $file.' '.
                    267:                                             &Apache::lonlocal::mt('(local rev: [_1])',
                    268:                                                                   $serverversions->{$file}).
                    269:                                             "\n";
                    270:                             }
                    271:                         }
1.2       raeburn   272:                         if ($target eq 'web') {
                    273:                             $message .= &Apache::loncommon::end_data_table().'<br />';
                    274:                         } else {
                    275:                             $message .= "\n";
                    276:                         }
1.1       raeburn   277:                     }
                    278:                 }
                    279:                 if (keys(%missing) > 0) {
                    280:                     my $text = 
                    281:                         &Apache::lonlocal::mt('The following [quant,_1,local file appears,local files appear]'.
                    282:                                               ' to be missing:',scalar(keys(%missing))); 
                    283:                     if ($target eq 'web') {
                    284:                         $message .= '<p>'.$text.'</p>'.
                    285:                                     &Apache::loncommon::start_data_table().
                    286:                                     &Apache::loncommon::start_data_table_header_row()."\n".
                    287:                                     '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
                    288:                                     '<th>'.&Apache::lonlocal::mt('Expected version').'</th>'."\n".
                    289:                                     &Apache::loncommon::end_data_table_header_row()."\n";
                    290:                     } else {
                    291:                         $message .= "$text\n";
                    292:                     }
                    293:                     foreach my $file (sort(keys(%missing))) {
                    294:                         my $revnum = $stdversions{$file};
                    295:                         if ($target eq 'web') {
1.6       raeburn   296:                             $message .= &Apache::loncommon::start_data_table_row()."\n".
                    297:                                         '<td>'.$file.'</td>'."\n".
1.1       raeburn   298:                                         '<td>'.$revnum.'</td>'."\n".
                    299:                                         &Apache::loncommon::end_data_table_row()."\n";
                    300:                         } else {
                    301:                             $message .= $file;
                    302:                             if ($revnum) {
                    303:                                 $message .= ' '.
                    304:                                             &Apache::lonlocal::mt('(expected rev: [_1])',
                    305:                                                                   $revnum);
                    306:                             }
                    307:                             $message .= "\n";
                    308:                         }
                    309:                     }
1.2       raeburn   310:                     if ($target eq 'web') {
                    311:                         $message .= &Apache::loncommon::end_data_table();
                    312:                     } else {
                    313:                         $message .= "\n";
                    314:                     }
1.1       raeburn   315:                 }
                    316:                 if (keys(%extra) > 0) {
                    317:                     my $text = 
                    318:                         &Apache::lonlocal::mt('The following [quant,_1,file is,files are]'.
                    319:                                               ' not required by the release you have installed:',
                    320:                                               scalar(keys(%extra)));
                    321:                     if ($target eq 'web') {
                    322:                         $message .= '<p>'.$text.'</p>'.
                    323:                                     &Apache::loncommon::start_data_table().
                    324:                                     &Apache::loncommon::start_data_table_header_row()."\n".
                    325:                                     '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
                    326:                                     '<th>'.&Apache::lonlocal::mt('Version').'</th>'."\n".
                    327:                                     &Apache::loncommon::end_data_table_header_row()."\n";
                    328:                     } else {
                    329:                         $message .= "$text\n";
                    330:                     }
                    331:                     foreach my $file (sort(keys(%extra))) {
                    332:                         if ($target eq 'web') {
1.6       raeburn   333:                             $message .= &Apache::loncommon::start_data_table_row()."\n".
                    334:                                         '<td>'.$file.'</td>'."\n".
1.1       raeburn   335:                                         '<td>'.$serverversions->{$file}.'</td>'."\n".
                    336:                                         &Apache::loncommon::end_data_table_row()."\n";
                    337:                         } else {
                    338:                             $message .= $file.' '.
                    339:                                         &Apache::lonlocal::mt('(local rev: [_1])',
                    340:                                                               $serverversions->{$file}).
                    341:                                         "\n";
                    342:                         }
                    343:                     }
1.2       raeburn   344:                     if ($target eq 'web') {
                    345:                         $message .= &Apache::loncommon::end_data_table().'<br />';
                    346:                     } else {
                    347:                         $message .= "\n";
                    348:                     }
1.1       raeburn   349:                 }
                    350:             } else {
                    351:                 $message = &Apache::lonlocal::mt('No differences detected between installed files and files expected for LON-CAPA [_1]',$version);
                    352:             }
                    353:         } else {
                    354:             $message = &Apache::lonlocal::mt('No comparison attempted - failed to retrieve checksums for installed files.');
                    355:         }
                    356:     } else {
                    357:         $message = &Apache::lonlocal::mt('No comparison attempted - failed to retrieve checksums for installed files.');
                    358:     }
                    359:     unless ($message) {
                    360:         $message = &Apache::lonlocal::mt('LON-CAPA module check found no file changes.')."\n";
                    361:     }
                    362:     return ($message,$numchg);
                    363: }
                    364: 
                    365: 1;
                    366: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>