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>