Annotation of loncom/configuration/Checksumming.pm, revision 1.11
1.1 raeburn 1: # The LearningOnline Network with CAPA
2: # Checksum installed LON-CAPA modules and some configuration files
3: #
1.11 ! raeburn 4: # $Id: Checksumming.pm,v 1.10 2023/05/15 02:31:01 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',
1.11 ! raeburn 52: $lonlib.'/perl/Apache/math_parser/*.pm',
1.1 raeburn 53: $lonlib.'/perl/Apache/localize/*.pm',
54: $lonlib.'/perl/LONCAPA/*.pm',
55: $lonlib.'/perl/AlgParser.pm',
56: $lonlib.'/perl/LONCAPA.pm',
57: $lonlib.'/perl/Safe.pm',
58: $lonlib.'/perl/*-std.pm',
59: $lonlib.'/perl/HTML/*.pm',
60: $lonlib.'/perl/Safe.pm'));
61: }
62: if ($lonincludes) {
63: push(@paths,$lonincludes.'/*.lcpm');
64: }
65: push(@paths,('/home/httpd/cgi-bin/*.pl','/home/httpd/cgi-bin/*.png'));
66: my $confdir = '/etc/httpd/conf';
67: if ($distro =~ /^(ubuntu|debian)(\d+)$/) {
68: $confdir = '/etc/apache2';
69: } elsif ($distro =~ /^sles(\d+)$/) {
70: if ($1 >= 10) {
71: $confdir = '/etc/apache2';
72: }
73: } elsif ($distro =~ /^suse(\d+\.\d+)$/) {
74: if ($1 >= 10.0) {
75: $confdir = '/etc/apache2';
76: }
77: }
78: push(@paths,("$confdir/loncapa_apache.conf","$confdir/startup.pl"));
1.8 raeburn 79: if ($lontabdir) {
80: push(@paths,$lontabdir.'/mydesk.tab');
81: }
1.1 raeburn 82: if (@paths) {
83: my $pathstr = join (' ',@paths);
1.5 raeburn 84: if (open($dirh,"grep '$revtag' $pathstr 2>&1 |")) {
1.1 raeburn 85: while (my $line=<$dirh>) {
86: if ($line =~ m{^([^#]+):#\s\$Id:\s[\w.]+,v\s([\d.]+)\s}) {
87: $versions{$1} = $2;
88: }
89: }
90: close($dirh);
91: }
1.9 raeburn 92: if ($londaemons) {
93: my @binaries = qw (apachereload lchttpdlogs lcinstallfile lciptables lcnfsoff lcnfson lcpasswd lcuserdel pwchange);
94: foreach my $file (@binaries) {
95: next if ($versions{"$londaemons/$file"});
96: if (-B "$londaemons/$file") {
97: if (-T $londaemons.'/.'.$file) {
98: if (open(my $fh,'<',$londaemons.'/.'.$file)) {
99: while (my $line=<$fh>) {
100: if ($line =~ m{^#\s\$Id:\s[\w.]+,v\s([\d.]+)\s}) {
101: $versions{"$londaemons/$file"} = $1;
102: last;
103: }
104: }
105: close($fh);
106: }
107: if ($versions{"$londaemons/$file"}) {
108: if (open(my $fh,'<',$londaemons.'/.'.$file)) {
109: binmode $fh;
110: my $sha_obj = Digest::SHA->new();
111: $sha_obj->addfile($fh);
112: $chksums{"$londaemons/$file"} = $sha_obj->hexdigest;
113: close($fh);
114: }
115: }
116: }
117: }
118: }
119: }
1.1 raeburn 120: foreach my $key (sort(keys(%versions))) {
121: next if ($key =~ /\.lpmlsave$/);
1.9 raeburn 122: unless (exists($chksums{$key})) {
123: if (open(my $fh,"<$key")) {
124: binmode $fh;
125: my $sha_obj = Digest::SHA->new();
126: $sha_obj->addfile($fh);
127: $chksums{$key} = $sha_obj->hexdigest;
128: close($fh);
129: }
1.1 raeburn 130: }
1.9 raeburn 131: $output .= "$key,$versions{$key},$chksums{$key}\n";
1.1 raeburn 132: }
133: }
134: if ($lontabdir ne '') {
135: if (open(my $tabfh,">$lontabdir/lonchksums.tab")) {
136: print $tabfh '# Last written: '.localtime(time)."\n";
137: print $tabfh "$output\n";
138: close($tabfh);
139: }
140: }
141: return (\%chksums,\%versions);
142: }
143:
144: sub compare_checksums {
145: my ($target,$lonhost,$version,$serversums,$serverversions) = @_;
1.2 raeburn 146: my ($message,$numchg,$linefeed);
1.3 raeburn 147: if ($target eq 'web') {
1.2 raeburn 148: $linefeed = '<br />';
149: } else {
150: $linefeed = "\n";
151: }
1.5 raeburn 152: if (!$Apache::lonlocal::lh) {
153: &Apache::lonlocal::get_language_handle();
154: }
1.1 raeburn 155: if ((ref($serversums) eq 'HASH') && (keys(%{$serversums}))) {
156: my $checksums = &Apache::lonnet::fetch_dns_checksums();
157: my (%extra,%missing,%diffs,%stdsums,%stdversions);
158: if (ref($checksums) eq 'HASH') {
159: if (ref($checksums->{'sums'}) eq 'HASH') {
160: %stdsums = %{$checksums->{'sums'}};
161: }
162: if (ref($checksums->{'versions'}) eq 'HASH') {
163: %stdversions = %{$checksums->{'versions'}};
164: }
165: if (keys(%stdsums)) {
166: foreach my $key (keys(%stdsums)) {
167: if (exists($serversums->{$key})) {
168: if ($serversums->{$key} ne $stdsums{$key}) {
169: $diffs{$key} = 1;
170: $numchg ++;
171: }
172: } else {
1.9 raeburn 173: $missing{$key} = 1;
174: $numchg ++;
1.1 raeburn 175: }
176: }
177: foreach my $key (keys(%{$serversums})) {
178: unless (exists($stdsums{$key})) {
179: $extra{$key} = 1;
180: $numchg ++;
181: }
182: }
183: }
184: if ($numchg) {
1.2 raeburn 185: $message =
1.1 raeburn 186: &Apache::lonlocal::mt('[quant,_1,difference was,differences were] found'.
1.2 raeburn 187: ' between LON-CAPA modules installed on your server [_2]'.
188: ' and those expected for the LON-CAPA version you are'.
189: ' currently running.',$numchg,"($lonhost)$linefeed");
1.1 raeburn 190: if ($target eq 'web') {
191: $message = '<p>'.$message.'</p>';
192: } else {
193: $message .= "\n\n";
194: }
195: my (@diffversion,@modified);
196: if (keys(%diffs) > 0) {
197: foreach my $file (sort(keys(%diffs))) {
198: if ($serverversions->{$file} ne $stdversions{$file}) {
199: push(@diffversion,$file);
200: } else {
201: push(@modified,$file);
202: }
203: }
204: if (@diffversion > 0) {
1.2 raeburn 205: my $text =
206: &Apache::lonlocal::mt('The following [quant,_1,file is a,files are]'.
1.1 raeburn 207: ' different version(s) from that expected for LON-CAPA [_2]:',
208: scalar(@diffversion),$version);
209: if ($target eq 'web') {
210: $message .= '<p>'.$text.'</p>'.
211: &Apache::loncommon::start_data_table().
212: &Apache::loncommon::start_data_table_header_row()."\n".
213: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
214: '<th>'.&Apache::lonlocal::mt('Server version').'</th>'."\n".
215: '<th>'.&Apache::lonlocal::mt('Expected version').'</th>'."\n".
216: &Apache::loncommon::end_data_table_header_row()."\n";
217: } else {
218: $message .= "$text\n";
219: }
220: foreach my $file (sort(@diffversion)) {
221: my $revnum = $stdversions{$file};
222: if ($target eq 'web') {
223: $message .= &Apache::loncommon::start_data_table_row().
1.2 raeburn 224: '<td>'.$file.'</td>'."\n".
1.1 raeburn 225: '<td>'.$serverversions->{$file}.'</td>'."\n".
226: '<td>'.$revnum.'</td>'."\n".
227: &Apache::loncommon::end_data_table_row()."\n";
228: } else {
229: $message .= $file.' '.
230: &Apache::lonlocal::mt('(local rev: [_1])',
231: $serverversions->{$file});
232: if ($revnum) {
233: $message .= '; '.
234: &Apache::lonlocal::mt('(expected rev: [_1])',
235: $revnum);
236: }
237: $message .= "\n";
238: }
239: }
1.2 raeburn 240: if ($target eq 'web') {
241: $message .= &Apache::loncommon::end_data_table().'<br />';
242: } else {
243: $message .= "\n";
244: }
1.1 raeburn 245: }
246: if (@modified > 0) {
1.2 raeburn 247: my $text =
1.1 raeburn 248: &Apache::lonlocal::mt('The following [quant,_1,file appears,files appear]'.
249: ' to have been modified locally:',scalar(@modified));
250: if ($target eq 'web') {
251: $message .= '<p>'.$text.'</p>'.
252: &Apache::loncommon::start_data_table().
253: &Apache::loncommon::start_data_table_header_row()."\n".
254: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
255: '<th>'.&Apache::lonlocal::mt('Version').'</th>'."\n".
256: &Apache::loncommon::end_data_table_header_row()."\n";
257: } else {
258: $message .= "$text\n";
259: }
260: foreach my $file (sort(@modified)) {
261: if ($target eq 'web') {
262: $message .= &Apache::loncommon::start_data_table_row()."\n".
263: '<td>'.$file.'</td>'."\n".
264: '<td>'.$serverversions->{$file}.'</td>'."\n".
265: &Apache::loncommon::end_data_table_row()."\n";
266: } else {
267: $message .= $file.' '.
268: &Apache::lonlocal::mt('(local rev: [_1])',
269: $serverversions->{$file}).
270: "\n";
271: }
272: }
1.2 raeburn 273: if ($target eq 'web') {
274: $message .= &Apache::loncommon::end_data_table().'<br />';
275: } else {
276: $message .= "\n";
277: }
1.1 raeburn 278: }
279: }
280: if (keys(%missing) > 0) {
281: my $text =
282: &Apache::lonlocal::mt('The following [quant,_1,local file appears,local files appear]'.
283: ' to be missing:',scalar(keys(%missing)));
284: if ($target eq 'web') {
285: $message .= '<p>'.$text.'</p>'.
286: &Apache::loncommon::start_data_table().
287: &Apache::loncommon::start_data_table_header_row()."\n".
288: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
289: '<th>'.&Apache::lonlocal::mt('Expected version').'</th>'."\n".
290: &Apache::loncommon::end_data_table_header_row()."\n";
291: } else {
292: $message .= "$text\n";
293: }
294: foreach my $file (sort(keys(%missing))) {
295: my $revnum = $stdversions{$file};
296: if ($target eq 'web') {
1.6 raeburn 297: $message .= &Apache::loncommon::start_data_table_row()."\n".
298: '<td>'.$file.'</td>'."\n".
1.1 raeburn 299: '<td>'.$revnum.'</td>'."\n".
300: &Apache::loncommon::end_data_table_row()."\n";
301: } else {
302: $message .= $file;
303: if ($revnum) {
304: $message .= ' '.
305: &Apache::lonlocal::mt('(expected rev: [_1])',
306: $revnum);
307: }
308: $message .= "\n";
309: }
310: }
1.2 raeburn 311: if ($target eq 'web') {
312: $message .= &Apache::loncommon::end_data_table();
313: } else {
314: $message .= "\n";
315: }
1.1 raeburn 316: }
317: if (keys(%extra) > 0) {
318: my $text =
319: &Apache::lonlocal::mt('The following [quant,_1,file is,files are]'.
320: ' not required by the release you have installed:',
321: scalar(keys(%extra)));
322: if ($target eq 'web') {
323: $message .= '<p>'.$text.'</p>'.
324: &Apache::loncommon::start_data_table().
325: &Apache::loncommon::start_data_table_header_row()."\n".
326: '<th>'.&Apache::lonlocal::mt('File').'</th>'."\n".
327: '<th>'.&Apache::lonlocal::mt('Version').'</th>'."\n".
328: &Apache::loncommon::end_data_table_header_row()."\n";
329: } else {
330: $message .= "$text\n";
331: }
332: foreach my $file (sort(keys(%extra))) {
333: if ($target eq 'web') {
1.6 raeburn 334: $message .= &Apache::loncommon::start_data_table_row()."\n".
335: '<td>'.$file.'</td>'."\n".
1.1 raeburn 336: '<td>'.$serverversions->{$file}.'</td>'."\n".
337: &Apache::loncommon::end_data_table_row()."\n";
338: } else {
339: $message .= $file.' '.
340: &Apache::lonlocal::mt('(local rev: [_1])',
341: $serverversions->{$file}).
342: "\n";
343: }
344: }
1.2 raeburn 345: if ($target eq 'web') {
346: $message .= &Apache::loncommon::end_data_table().'<br />';
347: } else {
348: $message .= "\n";
349: }
1.1 raeburn 350: }
351: } else {
352: $message = &Apache::lonlocal::mt('No differences detected between installed files and files expected for LON-CAPA [_1]',$version);
353: }
354: } else {
355: $message = &Apache::lonlocal::mt('No comparison attempted - failed to retrieve checksums for installed files.');
356: }
357: } else {
358: $message = &Apache::lonlocal::mt('No comparison attempted - failed to retrieve checksums for installed files.');
359: }
360: unless ($message) {
361: $message = &Apache::lonlocal::mt('LON-CAPA module check found no file changes.')."\n";
362: }
363: return ($message,$numchg);
364: }
365:
366: 1;
367:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>