]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - src/pakfire/lib/functions.pl
Und wieder den Packfire erweitert. Diesesmal:
[ipfire-2.x.git] / src / pakfire / lib / functions.pl
index 48c34e91050dff03add509166e91129f54d54c19..a07b89ffa78b3f47bbdfbb3ff62d7d40333d5436 100644 (file)
@@ -1,15 +1,26 @@
 #!/usr/bin/perl -w
 
 require "/opt/pakfire/etc/pakfire.conf";
+require "/var/ipfire/general-functions.pl";
 
 use File::Basename;
 use File::Copy;
 use LWP::UserAgent;
 use HTTP::Response;
+use HTTP::Headers;
+use HTTP::Message;
+use HTTP::Request;
 use Net::Ping;
 
 package Pakfire;
 
+my $final_data;
+my $total_size;
+my $bfile;
+
+my %pakfiresettings = ();
+&General::readhash("${General::swroot}/pakfire/settings", \%pakfiresettings);
+
 sub message {
        my $message = shift;
        print "$message\n";
@@ -18,7 +29,16 @@ sub message {
 
 sub logger {
        my $log = shift;
-       system("logger -t pakfire \"$log\"");
+       system("logger -t pakfire \"$log\"") if "$log";
+}
+
+sub usage {
+  &Pakfire::message("Usage: pakfire <install|remove> <pak(s)>");
+  &Pakfire::message("               <update> - Contacts the servers for new lists of paks.");
+  &Pakfire::message("               <upgrade> - Installs the latest version of all paks.");
+  &Pakfire::message("               <list> - Outputs a short list with all available paks.");
+  &Pakfire::message("");
+  exit 1;
 }
 
 sub pinghost {
@@ -26,10 +46,10 @@ sub pinghost {
        
        $p = Net::Ping->new();
   if ($p->ping($host)) {
-       logger("$host is alive.");
+       logger("PING INFO: $host is alive");
        return 1;
   } else {
-               logger("$host is dead.");
+               logger("PING INFO: $host is unreachable");
                return 0;
        }
   $p->close();
@@ -40,6 +60,7 @@ sub fetchfile {
        my $gethost = shift;
        my (@server, $host, $proto, $file, $allok, $i);
        
+       logger("DOWNLOAD STARTED: $getfile") unless ($bfile =~ /^counter\?.*/);
        use File::Basename;
        $bfile = basename("$getfile");
 
@@ -54,57 +75,105 @@ sub fetchfile {
                        $file = "$server[2]/$getfile";
                } else {
                        $host = $gethost;
+                       $file = $getfile;
                }
                
                $proto = "HTTP" unless $proto;
                
-               logger("Trying to get $file from $host ($proto).");
+               unless ($bfile =~ /^counter\?.*/) {
+                       logger("DOWNLOAD INFO: Host: $host ($proto) - File: $file");
+                       #message("DOWNLOAD INFO: Loading $bfile from ($proto) $host...");
+               }
 
                my $ua = LWP::UserAgent->new;
                $ua->agent("Pakfire/$Conf::version");
-               #$ua->timeout(5);
-               #$ua->env_proxy;
-        
-               my $response = $ua->get("http://$host/$file");
+               $ua->timeout(5);
+               
+               my %proxysettings=();
+               &General::readhash("${General::swroot}/proxy/advanced/settings", \%proxysettings);
+
+               if ($proxysettings{'UPSTREAM_PROXY'}) {
+                       logger("DOWNLOAD INFO: Upstream proxy: \"$proxysettings{'UPSTREAM_PROXY'}\"") unless ($bfile =~ /^counter\?.*/); 
+                       if ($proxysettings{'UPSTREAM_USER'}) {
+                               $ua->proxy("http","http://$proxysettings{'UPSTREAM_USER'}:$proxysettings{'UPSTREAM_PASSWORD'}@"."$proxysettings{'UPSTREAM_PROXY'}/");
+                               logger("DOWNLOAD INFO: Logging in with: \"$proxysettings{'UPSTREAM_USER'}\" - \"$proxysettings{'UPSTREAM_PASSWORD'}\"") unless ($bfile =~ /^counter\?.*/);
+                       } else {
+                               $ua->proxy("http","http://$proxysettings{'UPSTREAM_PROXY'}/");
+                       }
+               }
+
+               $final_data = undef;
+               my $url = "http://$host/$file";
+               my $response;
+               
+               unless ($bfile =~ /^counter\?.*/) {
+                       my $result = $ua->head($url);
+                       my $remote_headers = $result->headers;
+                       $total_size = $remote_headers->content_length;
+                       logger("DOWNLOAD INFO: $file has size of $total_size bytes");
+                       
+                       $response = $ua->get($url, ':content_cb' => \&callback );
+                       message("");
+               } else {
+                       $response = $ua->get($url);
+               }
+               
+               my $code = $response->code();
+               my $log = $response->status_line;
+               logger("DOWNLOAD INFO: HTTP-Status-Code: $code - $log");
+               
+               if ( $code eq "500" ) {
+                       message("Giving up: There was no chance to get the file \"$getfile\" from any available server.\nThere was an error on the way. Please fix it.");
+                       return 1;
+               }
                
                if ($response->is_success) {
-                       logger("$host sends file: $file.");
-                       if (open(FILE, ">$Conf::cachedir/$bfile")) {
-                               print FILE $response->content;
+                       if (open(FILE, ">$Conf::tmpdir/$bfile")) {
+                               print FILE $final_data;
                                close(FILE);
+                               unless ($bfile =~ /^counter\?.*/) { # Don't check out counterfile cause it's empty
+                                       logger("DOWNLOAD INFO: File received. Start checking signature...");
+                                       if (system("gpg --verify \"$Conf::tmpdir/$bfile\" &>/dev/null") eq 0) {
+                                               logger("DOWNLOAD INFO: Signature of $bfile is fine.");
+                                               move("$Conf::tmpdir/$bfile","$Conf::cachedir/$bfile");
+                                       } else {
+                                               message("DOWNLOAD ERROR: The downloaded file ($file) wasn't verified by IPFire.org. Sorry - Exiting...");
+                                               exit 1;
+                                       }
+                               }
+                               logger("DOWNLOAD FINISHED: $file") unless ($bfile =~ /^counter\?.*/);
                                $allok = 1;
                                return 0;
                        } else {
-                               logger("Could not open $Conf::cachedir/$bfile for writing.");
+                               logger("DOWNLOAD ERROR: Could not open $Conf::cachedir/$bfile for writing.");
                        }
                }       else {
-                       my $log = $response->status_line;
-                       logger("Download $file failed from $host ($proto): $log");
+                       logger("DOWNLOAD ERROR: $log");
                }
        }
-       message("Giving up: There was no chance to get the file \"$getfile\" from any available server.\nMay be you should run \"pakfire update\" to get some new servers.");
+       message("DOWNLOAD ERROR: There was no chance to get the file \"$getfile\" from any available server.\nMay be you should run \"pakfire update\" to get some new servers.");
        return 1;
 }
 
 sub getmirrors {
        use File::Copy;
 
-       logger("Try to get a mirror list.");
+       logger("MIRROR: Trying to get a mirror list.");
        
-       fetchfile("lists/$Conf::version-server-list", "$Conf::mainserver");
-       move("$Conf::cachedir/$Conf::version-server-list", "$Conf::dbdir/lists/$Conf::version-server-list");
+       fetchfile("$Conf::version/lists/server-list.db", "$Conf::mainserver");
+       move("$Conf::cachedir/server-list.db", "$Conf::dbdir/lists/server-list.db");
 }
 
 sub selectmirror {
        ### Check if there is a current server list and read it.
        #   If there is no list try to get one.
        my $count = 0;
-       while (!(open(FILE, "<$Conf::dbdir/lists/$Conf::version-server-list")) && ($count lt 5)) {
+       while (!(open(FILE, "<$Conf::dbdir/lists/server-list.db")) && ($count lt 5)) {
                $count++;
                getmirrors();
        }
        if ($count == 5) {
-               message("Could not find or download a server list.");
+               message("MIRROR ERROR: Could not find or download a server list");
                exit 1;
        }
        my @lines = <FILE>;
@@ -112,10 +181,14 @@ sub selectmirror {
 
        ### Count the number of the servers in the list
        my $scount = 0;
+       my @newlines;
        foreach (@lines) {
-               $scount++;
+               if ("$_" =~ /.*;.*;.*;/ ) {
+                       push(@newlines,$_);
+                       $scount++;
+               }
        }
-       logger("$scount servers found in list.");
+       logger("MIRROR INFO: $scount servers found in list");
        
        ### Choose a random server and test if it is online
        #   If the check fails try a new server.
@@ -127,7 +200,7 @@ sub selectmirror {
                $servers = 0;
                my ($line, $proto, $path, $host);
                my @templine;
-               foreach $line (@lines) {
+               foreach $line (@newlines) {
                        $servers++;
                        if ($servers eq $server) {
                                @templine = split(/\;/, $line);
@@ -162,7 +235,7 @@ sub dbgetlist {
        }
        
        if (("$age" gt 86400) || ("$force" eq "force")) {
-               cleanup();
+               #cleanup();
                fetchfile("lists/packages_list.db", "");
                move("$Conf::cachedir/packages_list.db", "$Conf::dbdir/lists/packages_list.db");
        }
@@ -175,6 +248,13 @@ sub dblist {
        #   filter may be: all, notinstalled, installed
        my $filter = shift;
        my $forweb = shift;
+       my @meta;
+       my @updatepaks;
+       my $file;
+       my $line;
+       my $prog;
+       my ($name, $version, $release);
+       my @templine;
        
        ### Make sure that the list is not outdated. 
        dbgetlist("noforce");
@@ -182,16 +262,59 @@ sub dblist {
        open(FILE, "<$Conf::dbdir/lists/packages_list.db");
        my @db = <FILE>;
        close(FILE);
-       
-       my $line;
-       my @templine;
-       foreach $line (sort @db) {
-               @templine = split(/\;/,$line);
-               ### filter here...
-               if ("$forweb" eq "forweb") {
-                       print "<option value=\"$templine[0]\">$templine[1]</option>\n";
-               } else {
-                       print "$templine[0] $templine[1]\n";
+
+       if ("$filter" eq "upgrade") {
+               opendir(DIR,"$Conf::dbdir/meta");
+               my @files = readdir(DIR);
+               closedir(DIR);
+               foreach $file (@files) {
+                       next if ( $file eq "." );
+                       next if ( $file eq ".." );
+                       open(FILE, "<$Conf::dbdir/meta/$file");
+                       @meta = <FILE>;
+                       close(FILE);
+                       foreach $line (@meta) {
+                               @templine = split(/\: /,$line);
+                               if ("$templine[0]" eq "Name") {
+                                       $name = $templine[1];
+                                       chomp($name);
+                               } elsif ("$templine[0]" eq "ProgVersion") {
+                                       $version = $templine[1];
+                                       chomp($version);
+                               } elsif ("$templine[0]" eq "Release") {
+                                       $release = $templine[1];
+                                       chomp($release);
+                               }
+                       }
+                       foreach $prog (@db) {
+                               @templine = split(/\;/,$prog);
+                               if (("$name" eq "$templine[0]") && ("$release" < "$templine[2]" )) {
+                                       push(@updatepaks,$name);
+                                       if ("$forweb" eq "forweb") {
+                                               print "<option value=\"$name\">Update: $name -- Version: $version -> $templine[1] -- Release: $release -> $templine[2]</option>\n";
+                                       } else {
+                                               print "Update: $name\nVersion: $version -> $templine[1]\nRelease: $release -> $templine[2]\n\n";
+                                       }
+                               }
+                       }
+               }
+               return @updatepaks;
+       } else {
+               my $line;
+               my @templine;
+               foreach $line (sort @db) {
+                       next unless ($line =~ /.*;.*;.*;/ );
+                       @templine = split(/\;/,$line);
+                       if ("$filter" eq "notinstalled") {
+                               next if ( -e "$Conf::dbdir/installed/meta-$templine[0]" );
+                       } elsif ("$filter" eq "installed") {
+                               next unless ( -e "$Conf::dbdir/installed/meta-$templine[0]" );
+                       }
+                       if ("$forweb" eq "forweb") {
+                               print "<option value=\"$templine[0]\">$templine[0]-$templine[1]-$templine[2]</option>\n";
+                       } else {
+                               print "Name: $templine[0]\nProgVersion: $templine[1]\nRelease: $templine[2]\n\n";
+                       }
                }
        }
 }
@@ -201,14 +324,15 @@ sub resolvedeps {
        
        getmetafile("$pak");
        
-       message("\n## Resolving dependencies for $pak...");
+       message("");
+       message("## Resolving dependencies for $pak...");
        
        open(FILE, "<$Conf::dbdir/meta/meta-$pak");
        my @file = <FILE>;
        close(FILE);
        
        my $line;
-       my (@templine, @deps, @tempdeps);
+       my (@templine, @deps, @tempdeps, @all);
        foreach $line (@file) {
                @templine = split(/\: /,$line);
                if ("$templine[0]" eq "Dependencies") {
@@ -218,25 +342,35 @@ sub resolvedeps {
        chomp (@deps);
        foreach (@deps) {
                if ($_) {
-                 message("### Found dependency: $_");
-                 push(@tempdeps,$_);
+                 my $return = &isinstalled($_);
+                 if ($return eq 0) {
+                       message("### Dependency is already installed: $_");
+                 } else {
+                       message("### Need to install dependency: $_");
+                               push(@tempdeps,$_);
+                               push(@all,$_);
+                       } 
                }
        }
-       
-       #my @tempdeps = @deps;
+
        foreach (@tempdeps) {
                if ($_) {
                        my @newdeps = resolvedeps("$_");
                        foreach(@newdeps) {
                                unless (($_ eq " ") || ($_ eq "")) {
-                                 message("### Found dependency: $_");
-                                       push(@deps,$_);
+                                       my $return = &isinstalled($_);
+                                       if ($return eq 0) {
+                                               message("### Dependency is already installed: $_");
+                                       } else {
+                                               message("### Need to install dependency: $_");
+                                               push(@all,$_);
+                                       }
                                }
                        }
                }
        }
-       chomp (@deps);
-       return @deps;
+       chomp (@all);
+       return @all;
 }
 
 sub cleanup {
@@ -262,8 +396,6 @@ sub cleanup {
 sub getmetafile {
        my $pak = shift;
        
-       logger("Going to download meta-$pak.");
-       
        unless ( -e "$Conf::dbdir/meta/meta-$pak") {
                fetchfile("meta/meta-$pak", "");
                move("$Conf::cachedir/meta-$pak", "$Conf::dbdir/meta/meta-$pak");
@@ -301,18 +433,7 @@ sub getsize {
                        return $templine[1];
                }
        }
-}
-
-sub addsizes { ## Still not working
-       my @paks = shift;
-       
-       my $paksize;
-       my $totalsize = 0;
-       foreach (@paks) {
-               $paksize = getsize("$_");
-               $totalsize = ($totalsize + $paksize) ;
-       }
-       return $totalsize;
+       return 0;
 }
 
 sub decryptpak {
@@ -322,10 +443,11 @@ sub decryptpak {
        
        my $file = getpak("$pak", "noforce");
        
-       my $return = system("gpg -d < $Conf::cachedir/$file | tar xj -C $Conf::tmpdir/");
-       
-       logger("Decryption process returned the following: $return");
-       if ($return == 1) { exit 1; }
+       logger("DECRYPT STARTED: $pak");
+       my $return = system("cd $Conf::tmpdir/ && gpg -d < $Conf::cachedir/$file | tar x &>/dev/null");
+       $return %= 255;
+       logger("DECRYPT FINISHED: $pak - Status: $return");
+       if ($return != 0) { exit 1; }
 }
 
 sub getpak {
@@ -354,8 +476,6 @@ sub getpak {
                exit 1;
        }
        
-       #message("\n## Downloading $file...");
-       
        unless ( "$force" eq "force" ) {
                if ( -e "$Conf::cachedir/$file" ) {
                        return $file;
@@ -369,16 +489,23 @@ sub getpak {
 sub setuppak {
        my $pak = shift;
        
-       message("We are going to install: $pak");
+       message("################################################################################");
+       message("# --> Installing: $pak");
+       message("################################################################################");
        
        decryptpak("$pak");
        
-       my $return = system("cd $Conf::tmpdir && ./install.sh >> $Conf::logdir/install-$pak.log 2>&1");
+       my $return = system("cd $Conf::tmpdir && NAME=$pak ./install.sh >> $Conf::logdir/install-$pak.log 2>&1");
+       $return %= 255;
+       if ($pakfiresettings{'UUID'} ne "off") {
+               fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid&ipak=$pak&return=$return", "$Conf::mainserver");
+       }
        if ($return == 0) {
          move("$Conf::tmpdir/ROOTFILES", "$Conf::dbdir/rootfiles/$pak");
          cleanup("tmp");
          copy("$Conf::dbdir/meta/meta-$pak","$Conf::dbdir/installed/");
                message("Setup completed. Congratulations!");
+               message("################################################################################");
        } else {
                message("Setup returned: $return. Sorry. Please search our forum to find a solution for this problem.");
                exit $return;
@@ -386,18 +513,33 @@ sub setuppak {
        return $return;
 }
 
-sub updatepak {
+sub isinstalled {
+       my $pak = shift;
+       if ( open(FILE,"<$Conf::dbdir/installed/meta-$pak") ) {
+               close(FILE);
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
+sub upgradepak {
        my $pak = shift;
 
-       message("We are going to update: $pak");
+       message("We are going to upgrade: $pak");
 
        decryptpak("$pak");
 
-       my $return = system("cd $Conf::tmpdir && ./update.sh >> $Conf::logdir/update-$pak.log 2>&1");
+       my $return = system("cd $Conf::tmpdir && NAME=$pak ./update.sh >> $Conf::logdir/update-$pak.log 2>&1");
+       $return %= 255;
+       if ($pakfiresettings{'UUID'} ne "off") {
+               fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid&upak=$pak&return=$return", "$Conf::mainserver");
+       }
        if ($return == 0) {
          move("$Conf::tmpdir/ROOTFILES", "$Conf::dbdir/rootfiles/$pak");
          cleanup("tmp");
-               message("Update completed. Congratulations!");
+               copy("$Conf::dbdir/meta/meta-$pak","$Conf::dbdir/installed/");
+               message("Upgrade completed. Congratulations!");
        } else {
                message("Setup returned: $return. Sorry. Please search our forum to find a solution for this problem.");
                exit $return;
@@ -412,11 +554,16 @@ sub removepak {
 
        decryptpak("$pak");
 
-       my $return = system("cd $Conf::tmpdir && ./uninstall.sh >> $Conf::logdir/uninstall-$pak.log 2>&1");
+       my $return = system("cd $Conf::tmpdir && NAME=$pak ./uninstall.sh >> $Conf::logdir/uninstall-$pak.log 2>&1");
+       $return %= 255;
+       if ($pakfiresettings{'UUID'} ne "off") {
+               fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid&dpak=$pak&return=$return", "$Conf::mainserver");
+       }
        if ($return == 0) {
          open(FILE, "<$Conf::dbdir/rootfiles/$pak");
                my @file = <FILE>;
                close(FILE);
+               message("Removing files...");
                foreach (@file) {
                  my $line = $_;
                  chomp($line);
@@ -424,6 +571,8 @@ sub removepak {
                        system("cd / && rm -rf $line >> $Conf::logdir/uninstall-$pak.log 2>&1");
                }
          unlink("$Conf::dbdir/rootfiles/$pak");
+         unlink("$Conf::dbdir/installed/meta-$pak");
+         message("Finished removing files!");
          cleanup("tmp");
                message("Uninstall completed. Congratulations!");
        } else {
@@ -451,7 +600,6 @@ sub beautifysize {
 
 sub makeuuid {
        unless ( -e "$Conf::dbdir/uuid" ) {
-               message("Creating a random key...");
                open(FILE, "</proc/sys/kernel/random/uuid");
                my @line = <FILE>;
                close(FILE);
@@ -465,12 +613,49 @@ sub makeuuid {
 }
 
 sub senduuid {
-       unless("$Conf::uuid") {
-               $Conf::uuid = `cat $Conf::dbdir/uuid`;
+       if ($pakfiresettings{'UUID'} ne "off") {
+               unless("$Conf::uuid") {
+                       $Conf::uuid = `cat $Conf::dbdir/uuid`;
+               }
+               logger("Sending my uuid: $Conf::uuid");
+               fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid", "$Conf::mainserver");
+               system("rm -f $Conf::tmpdir/counter* 2>/dev/null");
+       }
+}
+
+sub checkcryptodb {
+       logger("CRYPTO INFO: Checking GnuPG Database");
+       my $myid = "64D96617"; # Our own gpg-key
+       my $trustid = "65D0FD58"; # Id of CaCert
+       my $ret = system("gpg --list-keys | grep -q $myid");
+       unless ( "$ret" eq "0" ) {
+               message("CRYPTO WARN: The GnuPG isn't configured corectly. Trying now to fix this.");
+               message("CRYPTO WARN: It's normal to see this on first execution.");
+               system("gpg --keyserver wwwkeys.de.pgp.net --always-trust --recv-key $myid &>>$Conf::logdir/gnupg-database.log");
+               system("gpg --keyserver wwwkeys.de.pgp.net --always-trust --recv-key $trustid &>>$Conf::logdir/gnupg-database.log");
+       } else {
+               logger("CRYPTO INFO: Database is okay");
        }
-       logger("Sending my uuid: $Conf::uuid");
-       fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid", "$Conf::mainserver");
-       system("rm -f $Conf::cachedir/counter* 2>/dev/null");
+}
+
+sub callback {
+   my ($data, $response, $protocol) = @_;
+   $final_data .= $data;
+   print progress_bar( length($final_data), $total_size, 25, '=' );
+}
+
+sub progress_bar {
+    my ( $got, $total, $width, $char ) = @_;
+    my $show_bfile;
+    $width ||= 25; $char ||= '=';
+    my $num_width = length $total;
+    my $len_bfile = length $bfile;
+    if ("$len_bfile" >= "12") {
+                       $show_bfile = substr($bfile,0,12)."...";
+               } else {
+                       $show_bfile = $bfile;
+               } 
+    sprintf "$show_bfile [%-${width}s] Got %${num_width}s bytes of %s (%.2f%%)\r", $char x (($width-1)*$got/$total). '>', $got, $total, 100*$got/+$total;
 }
 
 1;