Annotation of loncom/configuration/Checksumming.pm, revision 1.8
1.1 raeburn 1: # The LearningOnline Network with CAPA
2: # Checksum installed LON-CAPA modules and some configuration files
3: #
1.8 ! raeburn 4: # $Id: Checksumming.pm,v 1.7 2016/02/20 20:58:59 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: }
91: foreach my $key (sort(keys(%versions))) {
92: next if ($key =~ /\.lpmlsave$/);
93: my $sum;
94: if (open(my $fh,"<$key")) {
95: binmode $fh;
1.7 raeburn 96: my $sha_obj = Digest::SHA->new();
1.1 raeburn 97: $sha_obj->addfile($fh);
98: $sum = $sha_obj->hexdigest;
99: close($fh);
100: $chksums{$key} = $sum;
101: }
102: $output .= "$key,$versions{$key},$sum\n";
103: }
104: }
105: if ($lontabdir ne '') {
106: if (open(my $tabfh,">$lontabdir/lonchksums.tab")) {
107: print $tabfh '# Last written: '.localtime(time)."\n";
108: print $tabfh "$output\n";
109: close($tabfh);
110: }
111: }
112: return (\%chksums,\%versions);
113: }
114:
115: sub compare_checksums {
116: my ($target,$lonhost,$version,$serversums,$serverversions) = @_;
1.2 raeburn 117: my ($message,$numchg,$linefeed);
1.3 raeburn 118: if ($target eq 'web') {
1.2 raeburn 119: $linefeed = '<br />';
120: } else {
121: $linefeed = "\n";
122: }
1.5 raeburn 123: if (!$Apache::lonlocal::lh) {
124: &Apache::lonlocal::get_language_handle();
125: }
1.1 raeburn 126: if ((ref($serversums) eq 'HASH') && (keys(%{$serversums}))) {
127: my $checksums = &Apache::lonnet::fetch_dns_checksums();
128: my (%extra,%missing,%diffs,%stdsums,%stdversions);
129: if (ref($checksums) eq 'HASH') {
130: if (ref($checksums->{'sums'}) eq 'HASH') {
131: %stdsums = %{$checksums->{'sums'}};
132: }
133: if (ref($checksums->{'versions'}) eq 'HASH') {
134: %stdversions = %{$checksums->{'versions'}};
135: }
136: if (keys(%stdsums)) {
137: foreach my $key (keys(%stdsums)) {
138: if (exists($serversums->{$key})) {
139: if ($serversums->{$key} ne $stdsums{$key}) {
140: $diffs{$key} = 1;
141: $numchg ++;
142: }
143: } else {
1.4 raeburn 144: unless ((-e $key) && (-B $key)) {
145: $missing{$key} = 1;
146: $numchg ++;
147: }
1.1 raeburn 148: }
149: }
150: foreach my $key (keys(%{$serversums})) {
151: unless (exists($stdsums{$key})) {
152: $extra{$key} = 1;
153: $numchg ++;
154: }
155: }
156: }
157: if ($numchg) {
1.2 raeburn 158: $message =
1.1 raeburn 159: &Apache::lonlocal::mt('[quant,_1,difference was,differences were] found'.
1.2 raeburn 160: ' between LON-CAPA modules installed on your server [_2]'.
161: ' and those expected for the LON-CAPA version you are'.
162: ' currently running.',$numchg,"($lonhost)$linefeed");
1.1 raeburn 163: if ($target eq 'web') {
164: $message = '<p>'.$message.'</p>';
165: } else {
166: $message .= "\n\n";
167: }
168: my (@diffversion,@modified);
169: if (keys(%diffs) > 0) {
170: foreach my $file (sort(keys(%diffs))) {
171: if ($serverversions->{$file} ne $stdversions{$file}) {
172: push(@diffversion,$file);
173: } else {
174: push(@modified,$file);
175: }
176: }
177: if (@diffversion > 0) {
1.2 raeburn 178: my $text =
179: &Apache::lonlocal::mt('The following [quant,_1,file is a,files are]'.
1.1 raeburn 180: ' different version(s) from that expected for LON-CAPA [_2]:',
181: scalar(@diffversion),$version);
182: if ($target eq 'web') {
183: $message .= '<p>'.$text.'</p>'.
184: &Apache::loncommon::start_data_table().
185: &Apache::loncommon::start_data_table_header_row()."\n".
186: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
187: '<th>'.&Apache::lonlocal::mt('Server version').'</th>'."\n".
188: '<th>'.&Apache::lonlocal::mt('Expected version').'</th>'."\n".
189: &Apache::loncommon::end_data_table_header_row()."\n";
190: } else {
191: $message .= "$text\n";
192: }
193: foreach my $file (sort(@diffversion)) {
194: my $revnum = $stdversions{$file};
195: if ($target eq 'web') {
196: $message .= &Apache::loncommon::start_data_table_row().
1.2 raeburn 197: '<td>'.$file.'</td>'."\n".
1.1 raeburn 198: '<td>'.$serverversions->{$file}.'</td>'."\n".
199: '<td>'.$revnum.'</td>'."\n".
200: &Apache::loncommon::end_data_table_row()."\n";
201: } else {
202: $message .= $file.' '.
203: &Apache::lonlocal::mt('(local rev: [_1])',
204: $serverversions->{$file});
205: if ($revnum) {
206: $message .= '; '.
207: &Apache::lonlocal::mt('(expected rev: [_1])',
208: $revnum);
209: }
210: $message .= "\n";
211: }
212: }
1.2 raeburn 213: if ($target eq 'web') {
214: $message .= &Apache::loncommon::end_data_table().'<br />';
215: } else {
216: $message .= "\n";
217: }
1.1 raeburn 218: }
219: if (@modified > 0) {
1.2 raeburn 220: my $text =
1.1 raeburn 221: &Apache::lonlocal::mt('The following [quant,_1,file appears,files appear]'.
222: ' to have been modified locally:',scalar(@modified));
223: if ($target eq 'web') {
224: $message .= '<p>'.$text.'</p>'.
225: &Apache::loncommon::start_data_table().
226: &Apache::loncommon::start_data_table_header_row()."\n".
227: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
228: '<th>'.&Apache::lonlocal::mt('Version').'</th>'."\n".
229: &Apache::loncommon::end_data_table_header_row()."\n";
230: } else {
231: $message .= "$text\n";
232: }
233: foreach my $file (sort(@modified)) {
234: if ($target eq 'web') {
235: $message .= &Apache::loncommon::start_data_table_row()."\n".
236: '<td>'.$file.'</td>'."\n".
237: '<td>'.$serverversions->{$file}.'</td>'."\n".
238: &Apache::loncommon::end_data_table_row()."\n";
239: } else {
240: $message .= $file.' '.
241: &Apache::lonlocal::mt('(local rev: [_1])',
242: $serverversions->{$file}).
243: "\n";
244: }
245: }
1.2 raeburn 246: if ($target eq 'web') {
247: $message .= &Apache::loncommon::end_data_table().'<br />';
248: } else {
249: $message .= "\n";
250: }
1.1 raeburn 251: }
252: }
253: if (keys(%missing) > 0) {
254: my $text =
255: &Apache::lonlocal::mt('The following [quant,_1,local file appears,local files appear]'.
256: ' to be missing:',scalar(keys(%missing)));
257: if ($target eq 'web') {
258: $message .= '<p>'.$text.'</p>'.
259: &Apache::loncommon::start_data_table().
260: &Apache::loncommon::start_data_table_header_row()."\n".
261: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
262: '<th>'.&Apache::lonlocal::mt('Expected version').'</th>'."\n".
263: &Apache::loncommon::end_data_table_header_row()."\n";
264: } else {
265: $message .= "$text\n";
266: }
267: foreach my $file (sort(keys(%missing))) {
268: my $revnum = $stdversions{$file};
269: if ($target eq 'web') {
1.6 raeburn 270: $message .= &Apache::loncommon::start_data_table_row()."\n".
271: '<td>'.$file.'</td>'."\n".
1.1 raeburn 272: '<td>'.$revnum.'</td>'."\n".
273: &Apache::loncommon::end_data_table_row()."\n";
274: } else {
275: $message .= $file;
276: if ($revnum) {
277: $message .= ' '.
278: &Apache::lonlocal::mt('(expected rev: [_1])',
279: $revnum);
280: }
281: $message .= "\n";
282: }
283: }
1.2 raeburn 284: if ($target eq 'web') {
285: $message .= &Apache::loncommon::end_data_table();
286: } else {
287: $message .= "\n";
288: }
1.1 raeburn 289: }
290: if (keys(%extra) > 0) {
291: my $text =
292: &Apache::lonlocal::mt('The following [quant,_1,file is,files are]'.
293: ' not required by the release you have installed:',
294: scalar(keys(%extra)));
295: if ($target eq 'web') {
296: $message .= '<p>'.$text.'</p>'.
297: &Apache::loncommon::start_data_table().
298: &Apache::loncommon::start_data_table_header_row()."\n".
299: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
300: '<th>'.&Apache::lonlocal::mt('Version').'</th>'."\n".
301: &Apache::loncommon::end_data_table_header_row()."\n";
302: } else {
303: $message .= "$text\n";
304: }
305: foreach my $file (sort(keys(%extra))) {
306: if ($target eq 'web') {
1.6 raeburn 307: $message .= &Apache::loncommon::start_data_table_row()."\n".
308: '<td>'.$file.'</td>'."\n".
1.1 raeburn 309: '<td>'.$serverversions->{$file}.'</td>'."\n".
310: &Apache::loncommon::end_data_table_row()."\n";
311: } else {
312: $message .= $file.' '.
313: &Apache::lonlocal::mt('(local rev: [_1])',
314: $serverversions->{$file}).
315: "\n";
316: }
317: }
1.2 raeburn 318: if ($target eq 'web') {
319: $message .= &Apache::loncommon::end_data_table().'<br />';
320: } else {
321: $message .= "\n";
322: }
1.1 raeburn 323: }
324: } else {
325: $message = &Apache::lonlocal::mt('No differences detected between installed files and files expected for LON-CAPA [_1]',$version);
326: }
327: } else {
328: $message = &Apache::lonlocal::mt('No comparison attempted - failed to retrieve checksums for installed files.');
329: }
330: } else {
331: $message = &Apache::lonlocal::mt('No comparison attempted - failed to retrieve checksums for installed files.');
332: }
333: unless ($message) {
334: $message = &Apache::lonlocal::mt('LON-CAPA module check found no file changes.')."\n";
335: }
336: return ($message,$numchg);
337: }
338:
339: 1;
340:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>