Script to inform about new updates in OpenSuSE

Some time ago I wrote a script that informs me via e-mail, when zypper finds new updates. Now I'd like to share the script (actually there are two scripts: a main Perl script and a Shell script as wrapper).

An advantage of my script is that it informs you only once, if there are new updates and not every time you start it. It is achieved due to the storing the last result in the file system. The next time you'll get an e-mail is, when the script finds a newer update as found before.



The script works fine for OpenSuSE 11.0 or later. I've tested it neither with other versions of OpenSuSE nor with SLES. It requires zypper and stores the result file under /var/lib. It will not install any packages or patches!

Store the Perl script below as /usr/local/bin/zypper_pchk.pl:

#!/usr/bin/perl -w
#
# Written by Hermann Maurer (c) 2010 
# NO WARRANTY AT ALL!
# You are free to modify the script and to distribute your modifications
#
my %arr_new  = ();
my %arr_old  = ();
my @arr_to_show = ();
my $MYFILE = "/var/lib/zyp_pchk.lst";

my $testflag = 0;
my $param = shift || '';
if ($param eq '--test') { $testflag = 1; }

#This is an example of the output of zypper lu -t package command
#Reading installed packages...
#Patches
#
#Repository           | Name             | Version | Category    | Status
#---------------------+------------------+---------+-------------+-------
#Updates for 11.0     | attr             | 431     | recommended | Needed
#Updates for 11.0     | bind             | 426     | security    | Needed
#Updates for 11.0     | syslog-ng        | 444     | recommended | Needed

my $date = time();
# we try to read the current output
open RT, "/usr/bin/zypper lu -t package|";
while (<RT>) {
    chomp;
    my $str = $_;
    next if m/Reading installed packages/;
    next if m/Reading repository.*cache/;
    next if m/^Patches$/;
    next if m/^$/;

    if (m/^[\-\+]+$/) { push @arr_to_show, $str; next };
    if (m/Repository.*Status$/) { push @arr_to_show, $str; next };
    my ($s, $repo, $name, $version, $status) = split /\|/;
    next if (!defined($name) or !defined($version));
    $name =~ s/^\s+//; $name =~ s/\s+$//;
    $version  =~ s/^\s+//; $version  =~ s/\s+$//;
        push @arr_to_show, $str;
    }
}
close RT;

# we try to read the saved output to compare this with the current one
if (!open RT, "<", "$MYFILE") {
    open RT, ">", "$MYFILE";
    close RT;
    open RT, "<", "$MYFILE";
}
while (<RT>) {
    chomp;
    my $str = $_;
    next if m/Reading installed packages/;
    next if m/Reading repository.*cache/;
    next if m/^Patches$/;
    next if m/^$/;
    next if (m/^[\-\+]+$/);
    next if (m/Repository.*Status$/);
    next if (!defined($name) or !defined($version));
    $name =~ s/^\s+//; $name =~ s/\s+$//;
    $version  =~ s/^\s+//; $version  =~ s/\s+$//;
    if (!exists($arr_old{$name})) { $arr_old{$name} = $version; }
}
close RT;

# we compare the outputs
# only if there is a patch in arr_new, that is not in arr_old, then
# we say, that there is a new update
my $nu_flag = 0;
if (scalar(%arr_new)) {
    foreach $key (keys %arr_new) {
        if (!defined($arr_old{$key})) {
            $nu_flag = 1;
        }
    }
}

# we save the output to the file
if (!$testflag) {
    open RT, ">", "$MYFILE";
    foreach (@arr_to_show) { print RT $_, "\n"; }
    close RT;
    # we print all updates if this is not a test run
    if ($nu_flag) { foreach (@arr_to_show) { print $_, "\n"; } }
}

# if we found new updates
if ($nu_flag) { exit 1; }
else { exit 0; }

The next shell script is to save as /usr/local/bin/zypper_pchk.sh. It is the script, which should be started by cron and executes the Perl script above:

#!/bin/sh
# Written by Hermann Maurer (c) 2010
# NO WARRANTY AT ALL!
# You are free to modify the script and to distribute your modifications

TERM=vt100; export TERM
RECIPIENTS="youremail1@domain.com youremail2@domain.com"
ZYPPER="/usr/bin/zypper"
ZY_REF="${ZYPPER} -q ref"
ZY_PCHK="${ZYPPER} -q pchk"
ZY_LU="`dirname $0`/zypper_pchk.pl"

${ZY_REF} >/dev/null
$ZY_LU --test >/dev/null

if test $? -eq 1; then
    $ZY_LU | mailx -s 'updates available on '`hostname --long`'' ${RECIPIENTS}
fi

Finally you have to create a new cron job to run the zypper patch check periodically. You can create a new crontab file /etc/cron.d/zypper_pchk consisting of two lines below:

# runs OpenSuSE zypper patch check scripts two times daily 
12 6,14 * * *  root /usr/local/bin/zypper_pchk.sh

Finished! After you've created the two scripts, set the execute right for them, created a cron job, you'll be informed about new updates by zypper and this only once each time a new update has been found!

Enjoy it ;-)

1 Kommentare :: Script to inform about new updates in OpenSuSE

  1. You have a redundant 'curly bracket' on line 45. I received this from my Suse box (build 42.2):

    "Unmatched right curly bracket at /usr/local/bin/zypper_pchk.pl line 45, at end o f line"

    Thought you'd like to know.

    A.

Post a Comment