Annotation of loncom/build/CHECKRPMS, revision 1.20
1.11 raeburn 1: #!/usr/bin/perl
1.1 raeburn 2: #
3: # The LearningOnline Network with CAPA
4: # Checks status of RPM packages on system.
5: #
1.20 ! raeburn 6: # $Id: CHECKRPMS,v 1.19 2019/10/23 20:34:39 raeburn Exp $
1.13 raeburn 7: #
1.1 raeburn 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: =pod
32:
33: =head1 NAME
34:
1.19 raeburn 35: B<CHECKRPMS> - automated status report about RPMs (RHEL/Fedora/CentOS/Oracle Linux/SuSE/SLES)
1.11 raeburn 36: or debs (Debian/Ubuntu) on a system.
1.1 raeburn 37:
38: =head1 DESCRIPTION
39:
40: This file automates the process of checking for available updates
41: to LON-CAPA systems. distprobe is used to determine the Linux distribution.
42:
43: The utility which is used to complete the check depends on the distro:
44:
1.19 raeburn 45: fedora < 22; rhel (5, 6, 7); centos/scientific/oracle linux <=7 - yum
1.17 raeburn 46: fedora >= 22 - dnf
1.20 ! raeburn 47: rhel/centos/oracle/rocky/alma linux >= 8 - dnf
1.1 raeburn 48: suse 9.X and sles9 - you
1.19 raeburn 49: suse 10.2, 10.3, 11.X and 12.X; sles (>= 11) - zypper
50: sles10, suse10.1 - rug
1.1 raeburn 51: rhel 4 - up2date
1.11 raeburn 52: debian, ubuntu - apt-get
1.1 raeburn 53: others - check-rpms
54:
55: Created by amalgamating previous distribution-specific CHECKRPMS.dist files (where dist was one of: fedora, rhel, suse, sles10, default).
56:
57: Must be run as root or www.
58:
59: =cut
60:
61: use strict;
62: use lib '/home/httpd/lib/perl/';
63: use LONCAPA::Configuration;
1.10 raeburn 64: use Apache::loncommon();
1.1 raeburn 65:
66: my $tmpfile = '/tmp/CHECKRPMS.'.$$;
67: my $perlvar= LONCAPA::Configuration::read_conf('loncapa.conf');
1.14 raeburn 68: my $docroot = $perlvar->{'lonDocRoot'};
1.1 raeburn 69:
70: # Determine who we email
1.10 raeburn 71: my $defdom = $perlvar->{'lonDefDomain'};
72: my $origmail = $perlvar->{'lonAdmEMail'};
73: my $emailto = &Apache::loncommon::build_recipient_list(undef,
74: 'packagesmail',$defdom,$origmail);
1.1 raeburn 75: my $subj = $perlvar->{'lonHostID'};
76:
77: # Get Linux distro
78: open(PIPE, "$perlvar->{'lonDaemons'}/distprobe |");
79: my $distro = <PIPE>;
80: close(PIPE);
81:
82: undef($perlvar);
83:
84: my $hostname = `hostname`;
85: chomp($hostname);
86: open(TMPFILE,">$tmpfile");
87: print TMPFILE localtime(time).' '.$hostname."\n";
88: close(TMPFILE);
89:
1.15 raeburn 90: if ($docroot ne '') {
91: if (-e "$docroot/lon-status/checkrpms.txt") {
92: unlink("$docroot/lon-status/checkrpms.txt");
93: }
94: }
95:
1.1 raeburn 96: my ($cmd,$send,$addsubj);
1.17 raeburn 97: if ($distro =~ /^fedora(\d+)$/) {
98: my $version =$1;
99: if ($version > 21) {
100: $cmd = 'dnf update';
101: &prepare_msg($tmpfile,$cmd);
1.19 raeburn 102: ($send,$addsubj) = &check_with_yum_or_dnf($tmpfile,'dnf');
1.17 raeburn 103: } else {
104: $cmd = 'yum update';
105: &prepare_msg($tmpfile,$cmd);
1.19 raeburn 106: ($send,$addsubj) = &check_with_yum_or_dnf($tmpfile,'yum');
1.17 raeburn 107: }
1.6 albertel 108: } elsif ($distro =~ /^(suse|sles)9\.?\d?$/) {
1.1 raeburn 109: $cmd = 'you';
110: &prepare_msg($tmpfile,$cmd);
111: ($send,$addsubj) = &check_with_you($tmpfile);
1.11 raeburn 112: } elsif ($distro =~ /^suse(\d{2,})\.(\d+)$/) {
1.9 raeburn 113: my $version =$1;
1.11 raeburn 114: my $subversion = $2;
115: if (($version > 10) || (($version == 10) && ($subversion > 1))) {
1.9 raeburn 116: $cmd = 'zypper up';
117: &prepare_msg($tmpfile,$cmd);
118: ($send,$addsubj) = &check_with_zypper($tmpfile);
119: } else {
120: $cmd = 'rug up';
121: &prepare_msg($tmpfile,$cmd);
122: ($send,$addsubj) = &check_with_rug($tmpfile);
123: }
124: } elsif ($distro =~ /^sles10$/) {
1.1 raeburn 125: $cmd = 'rug up';
126: &prepare_msg($tmpfile,$cmd);
127: ($send,$addsubj) = &check_with_rug($tmpfile);
1.13 raeburn 128: } elsif ($distro =~ /^sles(\d+)$/) {
129: $cmd = 'zypper up';
130: &prepare_msg($tmpfile,$cmd);
131: ($send,$addsubj) = &check_with_zypper($tmpfile);
1.7 raeburn 132: } elsif ($distro =~ /^rhes(\d+)$/) {
133: my $version = $1;
134: if ($version == 4) {
135: $cmd ='up2date -u --nox';
136: &prepare_msg($tmpfile,$cmd);
137: ($send,$addsubj) = &check_with_up2date($tmpfile);
1.19 raeburn 138: } elsif ($version <= 7) {
1.7 raeburn 139: $cmd = 'yum update';
140: &prepare_msg($tmpfile,$cmd);
1.19 raeburn 141: ($send,$addsubj) = &check_with_yum_or_dnf($tmpfile,'yum');
142: } else {
143: $cmd = 'dnf update';
144: &prepare_msg($tmpfile,$cmd);
145: ($send,$addsubj) = &check_with_yum_or_dnf($tmpfile,'dnf');
146: }
1.20 ! raeburn 147: } elsif ($distro =~ /^(?:centos|scientific|oracle|rocky|alma)(\d+)$/) {
1.19 raeburn 148: my $version = $1;
149: if ($version <= 7) {
150: $cmd = 'yum update';
151: &prepare_msg($tmpfile,$cmd);
152: ($send,$addsubj) = &check_with_yum_or_dnf($tmpfile,'yum');
153: } else {
154: $cmd = 'dnf update';
155: &prepare_msg($tmpfile,$cmd);
156: ($send,$addsubj) = &check_with_yum_or_dnf($tmpfile,'dnf');
1.7 raeburn 157: }
1.11 raeburn 158: } elsif ($distro =~ /^(debian|ubuntu)\d+/) {
159: $cmd = 'apt-get upgrade';
160: &prepare_msg($tmpfile,$cmd);
161: ($send,$addsubj) = &check_with_apt($tmpfile);
1.1 raeburn 162: } else {
163: $cmd = '/usr/local/bin/check-rpms --update';
164: ($send,$addsubj) = &check_with_checkrpms($tmpfile);
165: }
166: if ($send) {
167: $subj .= $addsubj;
1.14 raeburn 168: if ($docroot ne '') {
169: system("cat $tmpfile > $docroot/lon-status/checkrpms.txt");
1.15 raeburn 170: if ($< == 0) {
171: system("chown www:www $docroot/lon-status/checkrpms.txt");
172: }
1.16 raeburn 173: chmod(0600,"$docroot/lon-status/checkrpms.txt");
1.14 raeburn 174: }
1.10 raeburn 175: system(qq{mail -s '$subj' "$emailto" < $tmpfile});
1.1 raeburn 176: }
177:
178: sub prepare_msg {
179: my ($tmpfile,$cmd) = @_;
180: #
181: # Put some nice text in $tmpfile
182: open(TMPFILE,">>$tmpfile");
183: print TMPFILE <<ENDHEADER;
184: Your system needs to be updated. Please execute (as root)
185:
186: $cmd
187:
188: to bring it up to date.
189:
1.5 raeburn 190: This is very important for the security of your server. The packages which need to be updated are listed below.
1.1 raeburn 191:
192: ENDHEADER
193: close(TMPFILE);
194: return;
195: }
196:
197: sub check_with_you {
198: my ($tmpfile) =@_;
199: my $you = '/usr/bin/online_update';
200: my $sendflag = 0;
201: my $append_to_subj;
202:
1.5 raeburn 203: if (open (PIPE, "$you -k -len 2>&1 |")) {
1.1 raeburn 204: my $output=<PIPE>;
205: close(PIPE);
206: chomp $output;
207: unless ($output eq 'No updates available.') {
1.5 raeburn 208: if (open (PIPE, "$you -s -d -len |grep ^INSTALL |")) {
209: my @updates = <PIPE>;
210: close(PIPE);
211: my $allpackages;
212: foreach my $line (@updates) {
213: my $package = substr($line,rindex($line,'/')+1);
214: if ($package ne '') {
215: $allpackages .= $package;
216: }
217: }
218: if ($allpackages ne '') {
219: open(TMPFILE,">>$tmpfile");
220: print TMPFILE $allpackages;
221: close(TMPFILE);
222: $sendflag = 1;
223: $append_to_subj = ' RPMS to upgrade';
224: }
225: } else {
226: $sendflag = 1;
227: $append_to_subj = ' Error running RPM update script';
228: }
1.1 raeburn 229: }
230: } else {
231: $sendflag = 1;
232: $append_to_subj = ' Error running RPM update script';
233: }
234: return ($sendflag,$append_to_subj);
235: }
236:
1.19 raeburn 237: sub check_with_yum_or_dnf {
238: my ($tmpfile,$progname) = @_;
239: my $path_to_exec = '/usr/bin/';
240: if ($progname eq 'dnf') {
241: $path_to_exec .= $progname;
1.1 raeburn 242: } else {
1.19 raeburn 243: $path_to_exec .= 'yum';
1.1 raeburn 244: }
1.17 raeburn 245: my $sendflag = 0;
246: my $append_to_subj;
247:
248: #
1.19 raeburn 249: # Execute command
250: my $command = $path_to_exec.' check-update '.'>>'.$tmpfile;
1.17 raeburn 251: system($command);
252:
253: my $returnvalue = $?>>8;
254:
255: #
1.19 raeburn 256: # Determine status of yum or dnf run
1.17 raeburn 257: if (100 == $returnvalue) {
258: $sendflag = 1;
259: $append_to_subj = ' RPMS to upgrade';
260: } elsif (0 != $returnvalue) {
261: $sendflag = 1;
262: $append_to_subj = ' Error running RPM update script';
263: } else {
1.19 raeburn 264: # yum or dnf returned 0, so everything is up to date.
1.17 raeburn 265: }
266: return ($sendflag,$append_to_subj);
267: }
268:
1.1 raeburn 269: sub check_with_up2date {
270: my ($tmpfile) = @_;
271: my $up2date = '/usr/bin/up2date-nox';
272: my $sendflag = 0;
273: my $append_to_subj;
274: #
275: # Execute online_update command to check for updates
276: my $up2date_error = 1;
277: if (open (PIPE, "$up2date -l 2>&1 |")) {
278: my @result=<PIPE>;
279: close(PIPE);
1.4 raeburn 280: my $output;
281: foreach my $line (@result) {
282: if ($line =~ /^The following Packages were marked to be skipped by your configuration:/) {
283: last;
284: } else {
285: $output .= $line;
286: }
287: }
1.1 raeburn 288: if (@result > 0) {
289: if ($output =~ /Fetching Obsoletes list/) {
290: $up2date_error = 0;
291: if ($output =~ /Name\s+Version\s+Rel\s+[\n\r\f]+\-+[\n\r\f]+(.+)/s) {
292: my $packagelist = $1;
1.4 raeburn 293: if ($packagelist ne '' && $packagelist !~ /^[\s\n\r\f]+$/) {
1.1 raeburn 294: open(TMPFILE,">>$tmpfile");
295: print TMPFILE $packagelist;
296: close(TMPFILE);
297: $append_to_subj = ' RPMS to upgrade';
298: $sendflag = 1;
299: }
300: }
301: }
302: }
303: }
304: if ($up2date_error) {
305: $append_to_subj = ' Error running RPM update script';
306: $sendflag = 1;
307: }
308: return ($sendflag,$append_to_subj);
309: }
310:
311: sub check_with_rug {
312: my ($tmpfile) = @_;
313: my $rug = '/usr/bin/rug';
314: my $sendflag = 0;
315: my $append_to_subj;
316: #
317: # Execute rug command to check for updates
318: if (open (PIPE, "$rug up -N 2>&1 |")) {
319: my @output=<PIPE>;
320: close(PIPE);
321: chomp(@output);
322: my @clean_output;
323: foreach my $line (@output) {
1.3 raeburn 324: if ($line =~ /^Waking\sup\sZMD\.\.\./) {
1.1 raeburn 325: next;
1.2 raeburn 326: } elsif ($line eq 'Done') {
327: next;
328: } elsif ($line eq '') {
329: next;
330: } elsif ($line eq 'The following packages will be installed:') {
331: next;
332: } elsif ($line eq 'Resolving Dependencies...') {
333: next;
334: } elsif ($line eq 'Transaction...') {
335: last;
336: } elsif ($line eq 'No updates are available.') {
1.1 raeburn 337: last;
1.5 raeburn 338: } elsif ($line eq 'Downloading Packages...') {
339: last;
1.1 raeburn 340: } else {
341: push(@clean_output,$line);
342: }
343: }
344: if (@clean_output > 0) {
345: open(TMPFILE,">>$tmpfile");
346: print TMPFILE join("\n",@clean_output);
347: close(TMPFILE);
348: $append_to_subj= ' RPMS to upgrade';
349: $sendflag = 1;
350: }
351: } else {
352: $append_to_subj = ' Error running RPM update check';
353: $sendflag = 1;
354: }
355: return ($sendflag,$append_to_subj);
356: }
357:
1.9 raeburn 358: sub check_with_zypper {
359: my ($tmpfile) = @_;
360: my $zypper = '/usr/bin/zypper';
361: my $sendflag = 0;
362: my $append_to_subj;
363: my $header;
364: #
365: # Execute zypper command to check for updates
366: if (open (PIPE, "$zypper lu 2>&1 |")) {
367: my @output=<PIPE>;
368: close(PIPE);
369: chomp(@output);
370: my @clean_output;
371: foreach my $line (@output) {
372: if ($line eq 'Restoring system sources...') {
373: next;
374: } elsif ($line =~ /^Parsing\smetadata\sfor\s/) {
375: next;
376: } elsif ($line eq 'Parsing RPM database...') {
377: next;
378: } elsif ($line =~ /^Catalog\s+\|\s+Name\s+\|\s+Version\s+\|\s+Category\s+\|\s+Status$/) {
379: $header = $line."\n";
380: next;
381: } elsif ($line =~ /^[-+]+$/) {
382: $header .= $line."\n";
383: next;
384: } elsif ($line eq 'WARNING: These are only the updates affecting the updater itself.') {
385: next;
386: } elsif ($line eq 'There are others available too.') {
387: next;
388: } else {
389: push(@clean_output,$line);
390: }
391: }
392: if (@clean_output > 0) {
393: open(TMPFILE,">>$tmpfile");
394: my $message = join("\n",@clean_output);
395: print TMPFILE $header.$message;
396: close(TMPFILE);
397: $append_to_subj= ' RPMS to upgrade';
398: $sendflag = 1;
399: }
400: } else {
401: $append_to_subj = ' Error running RPM update check';
402: $sendflag = 1;
403: }
404: return ($sendflag,$append_to_subj);
405: }
406:
1.11 raeburn 407: sub check_with_apt {
408: my ($tmpfile) = @_;
409: my $apt = '/usr/bin/apt-get';
410: my $sendflag = 0;
411: my $append_to_subj;
412: my $header;
413: my @chg_package;
414: #
415: # Execute apt-get command to update distributions
416: system ("$apt update > /dev/null");
417: my $returnvalue = $?>>8;
418: if ($returnvalue == 0) {
419: # Execute apt-get commands to check for upgrades
420: if (open (PIPE, "$apt -y --dry-run upgrade 2>&1 |")) {
421: my @output=<PIPE>;
422: close(PIPE);
423: chomp(@output);
424: foreach my $line (@output) {
425: $line =~ s/^\s+//;
426: my @items = split(/\s+/,$line);
427: if ($items[0] eq "Inst") {
428: push(@chg_package,$items[1]);
429: }
430: }
431: if (@chg_package > 0) {
432: $header = 'apt-get upgrade found the following packages need updating:'.
433: "\n\n";
434: open(TMPFILE,">>$tmpfile");
435: my $message = join("\n",@output);
436: print TMPFILE $header.$message;
437: close(TMPFILE);
438: $append_to_subj= ' deb packages to upgrade';
439: $sendflag = 1;
440: }
441: } else {
442: $append_to_subj = ' Error running deb upgrade check';
443: $sendflag = 1;
444: }
445: } else {
446: $append_to_subj = ' Error running deb update check';
447: $sendflag = 1;
448: }
449: return ($sendflag,$append_to_subj);
450: }
451:
1.1 raeburn 452: sub check_with_checkrpms {
453: my ($tmpfile,$perlvar) = @_;
454: my $checkrpms = '/usr/local/bin/check-rpms';
455: my $sendflag = 0;
456: my $append_to_subj;
457:
458: # Run Martin Seigert's checkrpms script. See
459: # See http://www.sfu.ca/acs/security/linux/check-rpms.html
460: # for more information.
461:
462: #
463: # Check that checkrpms is installed and is the proper version...
464: if (! -e $checkrpms) {
465: open(TMPFILE,">>$tmpfile");
466: print TMPFILE <<END;
467:
468: Unable to locate check-rpms on your system. Please go to
469: http://www.sfu.ca/acs/security/linux/check-rpms.html, download and
470: install check-rpms on this system.
471:
472: END
473: $append_to_subj = ' Error running RPM update check';
474: $sendflag = 1;
475: } else {
476: #
477: # Run check-rpms and capture its output
478: if (open (PIPE, "$checkrpms 2>&1 |")) {
479: my $output=<PIPE>;
480: close(PIPE);
481: if ($output ne '') {
482: $output = <<"END";
483:
484: checkrpms checked the status of the packages on your system and
485: produced the following output:
486: -------------------------------------------------------
487: $output
488: -------------------------------------------------------
489: If there are rpms which need to be installed, please log into
490: $perlvar->{'lonHostID'} and run the following command
491:
492: $checkrpms --update
493:
494: If there are kernel packages to be installed, use
495:
496: $checkrpms --update --install-kernel
497:
498: Keeping your system up to date is very important.
499: Ensuring you are using up to date software is a prerequisite for a
500: secure system.
501:
502: END
503: open(TMPFILE,">>$tmpfile");
504: print TMPFILE $output;
505: close(TMPFILE);
506: $append_to_subj = ' RPMS to upgrade';
507: $sendflag = 1;
508: }
509: }
510: }
511: return ($sendflag,$append_to_subj);
512: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>