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>