#!/usr/bin/perl # This script is published under the terms of the GNU General Public License, version 2 or later. # The GNU General Public License can be fetched from http://www.gnu.org/copyleft/gpl.html # # (c) Copyright Daniel Hokka Zakrisson # Derived from updates.cgi which is (c) The SmoothWall Team # $Rev$ use IO::Socket; use Cwd 'abs_path'; my $errormessage; require '/var/smoothwall/header.pl'; require '/var/smoothwall/updatelists.pl'; require '/var/smoothwall/langs/base.pl'; my ($usage, $download_list, $check, $update, $patch_file, @list, $reboot, $lilo_timestamp, @stats, %proxysettings, $ignore_installed); my $debug = 0; sub install_update { my $patch_file = $_[0]; my $md5sum; chomp($md5sum = `/usr/bin/md5sum $patch_file`); my $found = 0; my ($id,$md5,$title,$description,$date,$url); print "MD5: $md5sum\n" if ($debug > 1); foreach (@list) { chomp; ($id,$md5,$title,$description,$date,$url) = split(/\|/,$_); print "Expected MD5: $md5\n" if ($debug > 2); if ($md5sum =~ m/^$md5\s/) { $found = 1; last; } } unless ($found == 1) { $errormessage = $tr{'this is not an authorised update'}; goto ERROR; } unless (chdir("/var/patches/$$")) { $errormessage = "chdir(/var/patches/$$): $!"; goto ERROR; } unless (system("/bin/tar -xzf $patch_file > /dev/null") == 0) { $errormessage = $tr{'this is not a valid archive'}; goto ERROR; } unless (open(INFO, "/var/patches/$$/information")) { $errormessage = $tr{'could not open update information file'}; goto ERROR; } my $info = ; close(INFO); if (!$ignore_installed) { open(INS, "/var/smoothwall/patches/installed") or $errormessage = $tr{'could not open installed updates file'} && goto ERROR; while () { my @temp = split(/\|/, $_); if($info =~ m/^$temp[0]/) { $errormessage = $tr{'this update is already installed'}; goto ERROR; } } close(INS); } unless (system("/usr/local/bin/installpackage $$ > /dev/null") == 0) { $errormessage = $tr{'package failed to install'}; goto ERROR; } chdir("/var/patches"); unless (open(IS, ">>/var/smoothwall/patches/installed")) { $errormessage = $tr{'update installed but'}; goto ERROR; } flock IS, 2; my @time = gmtime(); chomp($info); $time[4] = $time[4] + 1; $time[5] = $time[5] + 1900; $time[3] = "0$time[3]" if ($time[3] < 10); $time[4] = "0$time[4]" if ($time[4] < 10); print IS "$info|$time[5]-$time[4]-$time[3]\n"; close(IS); &log("$tr{'the following update was successfully installedc'} $title"); &updated_lilo(); return 1; } sub check_updates { my (%installed, %available, @fields); unless (open(INSTALLED, "< /var/smoothwall/patches/installed")) { $errormessage = $tr{'could not open installed updates file'}; goto ERROR; } while () { chomp; @fields = split(/\|/, $_); $installed{$fields[0]} = $_; } close(INSTALLED); foreach (@list) { chomp; @fields = split(/\|/, $_); $available{$fields[0]} = $_; } foreach (sort(keys(%installed))) { delete($available{$_}); } return %available; } sub download_update { my $update = $_[0]; my $filename = $_[1]; my $sock; unless ($sock = new IO::Socket::INET (PeerAddr => ($proxysettings{'SERVER'} ? $proxysettings{'SERVER'} : "download.smoothwall.org"), PeerPort => ($proxysettings{'PORT'} ? $proxysettings{'PORT'} : 80), Proto => 'tcp', Timeout => 5)) { $errormessage = $tr{'could not connect to smoothwall org'}; goto ERROR; } unless (open(FILE, "> $filename")) { $errormessage = $tr{'could not open update for writing'}; close($sock); goto ERROR; } print $sock "GET http://download.smoothwall.org/updates/$version/$update HTTP/1.1\r\nHost: download.smoothwall.org\r\nConnection: close\r\n\r\n"; my $response = <$sock>; if ($response !~ /^HTTP\/\d.\d\s+200\s+/) { $errormessage = "Download failed!"; print "Response: $response\n" if ($debug > 2); close($sock); close(FILE); goto ERROR; } while (<$sock>) { last if /^\r?\n$/; } while (<$sock>) { print FILE; } close($sock); close(FILE); } sub updated_lilo() { @stats = stat("/etc/lilo.conf") or die($tr{'could not open file'} . ": /etc/lilo.conf"); if (!$lilo_timestamp) { $lilo_timestamp = $stats[9]; } elsif ($lilo_timestamp != $stats[9]) { $reboot |= 1; } } $usage = "Usage: $ARGV[0] [-r] [-i] {-d|-c|-u|FILE}\n" . "-d Download the updates list\n" . "-c Check for updates and print a list of them (implies -d)\n" . "-r Reboot after installing the update(s) if the kernel was updated\n" . "-u Download all available updates and install them (implies -d)\n" . "-i Don't check to see if this update has already been installed\n" . "FILE Install the update FILE"; foreach my $arg (@ARGV) { if ($arg eq '-d') { $download_list = 2; } elsif ($arg eq '-c') { $check = 1; $download_list = 1; } elsif ($arg eq '-u') { $update = 1; $download_list = 1; } elsif ($arg eq '-r') { $reboot = 2; } elsif ($arg eq '-D') { $debug++; } elsif ($arg eq '-i') { $ignore_installed = 1; } elsif ($arg eq '-V') { print 'swu.pl $Rev$', "\n"; exit(0); } elsif (!$patch_file && $arg ne '-h' && $arg ne '--help') { $patch_file = abs_path($arg); } else { $errormessage = $usage; goto ERROR; } } if ($download_list) { print "Downloading updates list...\n" if ($debug > 0); my $return = &downloadlist(); if ($errormessage) { goto ERROR; } elsif ($return =~ m/^HTTP\/\d+\.\d+ 200/) { unless (open(LIST, ">/var/smoothwall/patches/available")) { $errormessage = $tr{'could not open available updates file'}; goto ERROR; } flock LIST, 2; my @this = split(/----START LIST----\n/,$return); print LIST $this[1]; close(LIST); } } unless(open(LIST, "/var/smoothwall/patches/available")) { $errormessage = $tr{'could not open available updates list'}; goto ERROR; } @list = ; close(LIST); # Get the lilo.conf timestamp to check whether a kernel update was included &updated_lilo(); &readhash("/var/smoothwall/main/proxy", \%proxysettings); if ($download_list == 2) { # Do nothing, all has been done. } elsif ($patch_file) { unless(mkdir("/var/patches/$$", 0700)) { $errormessage = $tr{'could not create directory'}; goto ERROR; } &install_update($patch_file); system("/bin/rm", "-fr", "/var/patches/$$"); system('/usr/local/bin/smoothierebirth') if ($reboot == 3); } elsif ($check) { my (%available, @fields); %available = &check_updates(); if (scalar(keys(%available)) == 0) { print $tr{'all updates installed'} . "\n"; } else { foreach (sort(keys(%available))) { @fields = split(/\|/, $available{$_}); print "$fields[2] ($fields[4]): $fields[5]\n"; } } } elsif ($update) { my (%available, @fields, $filename); %available = &check_updates(); if (scalar(keys(%available)) == 0) { print $tr{'all updates installed'} . "\n"; } else { foreach (sort(keys(%available))) { unless (mkdir("/var/patches/$$", 0700)) { $errormessage = $tr{'could not create directory'}; goto ERROR; } @fields = split(/\|/, $available{$_}); $filename = $fields[2]; $filename =~ s/^(fixes\d+).*$/$1/; $filename = $version . "-" . $filename . ".tar.gz"; print "Fetching $filename\n" if ($debug > 0); &download_update($filename, "/var/patches/$$/patch.tar.gz"); print "Installing $filename\n" if ($debug > 0); &install_update("/var/patches/$$/patch.tar.gz"); system("/bin/rm", "-fr", "/var/patches/$$"); } } system('/usr/local/bin/smoothierebirth') if ($reboot == 3); } else { $errormessage = $usage; goto ERROR; } if ($reboot == 1) { print STDERR "You should reboot your SmoothWall for " . ($update ? "these updates" : "this update") . " to work."; } exit(0); ERROR: print $errormessage . "\n"; system("/bin/rm", "-fr", "/var/patches/$$"); exit(1);