]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/pakfire/lib/functions.pl
IPFire-Seeder gebaut...
[people/pmueller/ipfire-2.x.git] / src / pakfire / lib / functions.pl
1 #!/usr/bin/perl -w
2
3 require "/opt/pakfire/etc/pakfire.conf";
4 require "/var/ipfire/general-functions.pl";
5
6 use File::Basename;
7 use File::Copy;
8 use LWP::UserAgent;
9 use HTTP::Response;
10 use Net::Ping;
11
12 package Pakfire;
13
14 my %pakfiresettings = ();
15 &General::readhash("${General::swroot}/pakfire/settings", \%pakfiresettings);
16
17 sub message {
18 my $message = shift;
19 print "$message\n";
20 logger("$message");
21 }
22
23 sub logger {
24 my $log = shift;
25 system("logger -t pakfire \"$log\"");
26 }
27
28 sub usage {
29 &Pakfire::message("Usage: pakfire <install|remove> <pak(s)>");
30 &Pakfire::message(" <update> - Contacts the servers for new lists of paks.");
31 &Pakfire::message(" <upgrade> - Installs the latest version of all paks.");
32 &Pakfire::message(" <list> - Outputs a short list with all available paks.");
33 &Pakfire::message("");
34 exit 1;
35 }
36
37 sub pinghost {
38 my $host = shift;
39
40 $p = Net::Ping->new();
41 if ($p->ping($host)) {
42 logger("$host is alive.");
43 return 1;
44 } else {
45 logger("$host is dead.");
46 return 0;
47 }
48 $p->close();
49 }
50
51 sub fetchfile {
52 my $getfile = shift;
53 my $gethost = shift;
54 my (@server, $host, $proto, $file, $allok, $i);
55
56 use File::Basename;
57 $bfile = basename("$getfile");
58
59 $i = 0;
60 while (($allok == 0) && $i < 5) {
61 $i++;
62
63 if ("$gethost" eq "") {
64 @server = selectmirror();
65 $proto = $server[0];
66 $host = $server[1];
67 $file = "$server[2]/$getfile";
68 } else {
69 $host = $gethost;
70 $file = $getfile;
71 }
72
73 $proto = "HTTP" unless $proto;
74
75 logger("Trying to get $file from $host ($proto).");
76
77 my $ua = LWP::UserAgent->new;
78 $ua->agent("Pakfire/$Conf::version");
79 $ua->timeout(5);
80
81 my %proxysettings=();
82 &General::readhash("${General::swroot}/proxy/advanced/settings", \%proxysettings);
83
84 if ($proxysettings{'UPSTREAM_PROXY'}) {
85 logger("Using upstream proxy: \"$proxysettings{'UPSTREAM_PROXY'}\"");
86 if ($proxysettings{'UPSTREAM_USER'}) {
87 $ua->proxy("http","http://$proxysettings{'UPSTREAM_USER'}:$proxysettings{'UPSTREAM_PASSWORD'}@"."$proxysettings{'UPSTREAM_PROXY'}/");
88 logger(" Logging in with: \"$proxysettings{'UPSTREAM_USER'}\" - \"$proxysettings{'UPSTREAM_PASSWORD'}\"");
89 } else {
90 $ua->proxy("http","http://$proxysettings{'UPSTREAM_PROXY'}/");
91 }
92 }
93
94 my $response = $ua->get("http://$host/$file");
95
96 my $code = $response->code();
97 my $log = $response->status_line;
98 logger("HTTP-Status-Code: $code - $log");
99
100 if ( $code eq "500" ) {
101 message("Giving up: There was no chance to get teh file \"$getfile\" from any available server.\nThere was an error on the way. Please fix it.");
102 return 1;
103 }
104
105 if ($response->is_success) {
106 if (open(FILE, ">$Conf::tmpdir/$bfile")) {
107 print FILE $response->content;
108 close(FILE);
109 unless ($bfile =~ /^counter\?.*/) { # Don't check out counterfile cause it's empty
110 logger("File received. Start checking signature...");
111 if (system("gpg --verify \"$Conf::tmpdir/$bfile\" &>/dev/null") eq 0) {
112 logger("Signature of $bfile is fine.");
113 move("$Conf::tmpdir/$bfile","$Conf::cachedir/$bfile");
114 } else {
115 message("The downloaded file ($file) wasn't verified by IPFire.org. Sorry - Exiting...");
116 exit 1;
117 }
118 }
119 logger("Download successfully done from $host (file: $file).");
120 $allok = 1;
121 return 0;
122 } else {
123 logger("Could not open $Conf::cachedir/$bfile for writing.");
124 }
125 } else {
126 logger("Download $file failed from $host ($proto): $log");
127 }
128 }
129 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.");
130 return 1;
131 }
132
133 sub getmirrors {
134 use File::Copy;
135
136 logger("Try to get a mirror list.");
137
138 fetchfile("$Conf::version/lists/server-list.db", "$Conf::mainserver");
139 move("$Conf::cachedir/server-list.db", "$Conf::dbdir/lists/server-list.db");
140 }
141
142 sub selectmirror {
143 ### Check if there is a current server list and read it.
144 # If there is no list try to get one.
145 my $count = 0;
146 while (!(open(FILE, "<$Conf::dbdir/lists/server-list.db")) && ($count lt 5)) {
147 $count++;
148 getmirrors();
149 }
150 if ($count == 5) {
151 message("Could not find or download a server list.");
152 exit 1;
153 }
154 my @lines = <FILE>;
155 close(FILE);
156
157 ### Count the number of the servers in the list
158 my $scount = 0;
159 foreach (@lines) {
160 $scount++;
161 }
162 logger("$scount servers found in list.");
163
164 ### Choose a random server and test if it is online
165 # If the check fails try a new server.
166 # This will never give up.
167 my $found = 0;
168 my $servers = 0;
169 while ($found == 0) {
170 $server = int(rand($scount) + 1);
171 $servers = 0;
172 my ($line, $proto, $path, $host);
173 my @templine;
174 foreach $line (@lines) {
175 $servers++;
176 if ($servers eq $server) {
177 @templine = split(/\;/, $line);
178 $proto = $templine[0];
179 $host = $templine[1];
180 $path = $templine[2];
181 if (pinghost("$host")) {
182 $found = 1;
183 return ($proto, $host, $path);
184 }
185 }
186 }
187 }
188 }
189
190 sub dbgetlist {
191 ### Update the database if the file is older than one day.
192 # If you pass &Pakfire::dbgetlist(force) the list will be downloaded.
193 # Usage is always with an argument.
194 my $force = shift;
195 my $age;
196
197 use File::Copy;
198
199 if ( -e "$Conf::dbdir/lists/packages_list.db" ) {
200 my @stat = stat("$Conf::dbdir/lists/packages_list.db");
201 my $time = time();
202 $age = $time - $stat[9];
203 } else {
204 # Force an update.
205 $age = "86401";
206 }
207
208 if (("$age" gt 86400) || ("$force" eq "force")) {
209 #cleanup();
210 fetchfile("lists/packages_list.db", "");
211 move("$Conf::cachedir/packages_list.db", "$Conf::dbdir/lists/packages_list.db");
212 }
213 }
214
215 sub dblist {
216 ### This subroutine lists the packages.
217 # You may also pass a filter: &Pakfire::dblist(filter)
218 # Usage is always with two arguments.
219 # filter may be: all, notinstalled, installed
220 my $filter = shift;
221 my $forweb = shift;
222 my @meta;
223 my @updatepaks;
224 my $file;
225 my $line;
226 my $prog;
227 my ($name, $version, $release);
228 my @templine;
229
230 ### Make sure that the list is not outdated.
231 dbgetlist("noforce");
232
233 open(FILE, "<$Conf::dbdir/lists/packages_list.db");
234 my @db = <FILE>;
235 close(FILE);
236
237 if ("$filter" eq "upgrade") {
238 opendir(DIR,"$Conf::dbdir/meta");
239 my @files = readdir(DIR);
240 closedir(DIR);
241 foreach $file (@files) {
242 next if ( $file eq "." );
243 next if ( $file eq ".." );
244 open(FILE, "<$Conf::dbdir/meta/$file");
245 @meta = <FILE>;
246 close(FILE);
247 foreach $line (@meta) {
248 @templine = split(/\: /,$line);
249 if ("$templine[0]" eq "Name") {
250 $name = $templine[1];
251 chomp($name);
252 } elsif ("$templine[0]" eq "ProgVersion") {
253 $version = $templine[1];
254 chomp($version);
255 } elsif ("$templine[0]" eq "Release") {
256 $release = $templine[1];
257 chomp($release);
258 }
259 }
260 foreach $prog (@db) {
261 @templine = split(/\;/,$prog);
262 if (("$name" eq "$templine[0]") && ("$release" < "$templine[2]" )) {
263 push(@updatepaks,$name);
264 if ("$forweb" eq "forweb") {
265 print "<option value=\"$name\">Update: $name -- Version: $version -> $templine[1] -- Release: $release -> $templine[2]</option>\n";
266 } else {
267 print "Update: $name\nVersion: $version -> $templine[1]\nRelease: $release -> $templine[2]\n\n";
268 }
269 }
270 }
271 }
272 return @updatepaks;
273 } else {
274 my $line;
275 my @templine;
276 foreach $line (sort @db) {
277 next unless ($line =~ /.*;.*;.*;/ );
278 @templine = split(/\;/,$line);
279 if ("$filter" eq "notinstalled") {
280 next if ( -e "$Conf::dbdir/installed/meta-$templine[0]" );
281 } elsif ("$filter" eq "installed") {
282 next unless ( -e "$Conf::dbdir/installed/meta-$templine[0]" );
283 }
284 if ("$forweb" eq "forweb") {
285 print "<option value=\"$templine[0]\">$templine[0]-$templine[1]-$templine[2]</option>\n";
286 } else {
287 print "Name: $templine[0]\nProgVersion: $templine[1]\nRelease: $templine[2]\n\n";
288 }
289 }
290 }
291 }
292
293 sub resolvedeps {
294 my $pak = shift;
295
296 getmetafile("$pak");
297
298 message("");
299 message("## Resolving dependencies for $pak...");
300 #if (&isinstalled($pak) eq 0) {
301 # my @empty;
302 # return @empty;
303 #}
304
305 open(FILE, "<$Conf::dbdir/meta/meta-$pak");
306 my @file = <FILE>;
307 close(FILE);
308
309 my $line;
310 my (@templine, @deps, @tempdeps, @all);
311 foreach $line (@file) {
312 @templine = split(/\: /,$line);
313 if ("$templine[0]" eq "Dependencies") {
314 @deps = split(/ /, $templine[1]);
315 }
316 }
317 chomp (@deps);
318 foreach (@deps) {
319 if ($_) {
320 my $return = &isinstalled($_);
321 if ($return eq 0) {
322 message("### Dependency is already installed: $_");
323 } else {
324 message("### Need to install dependency: $_");
325 push(@tempdeps,$_);
326 push(@all,$_);
327 }
328 }
329 }
330
331 #my @tempdeps = @deps;
332 foreach (@tempdeps) {
333 if ($_) {
334 my @newdeps = resolvedeps("$_");
335 foreach(@newdeps) {
336 unless (($_ eq " ") || ($_ eq "")) {
337 my $return = &isinstalled($_);
338 if ($return eq 0) {
339 message("### Dependency is already installed: $_");
340 } else {
341 message("### Need to install dependency: $_");
342 push(@all,$_);
343 }
344 }
345 }
346 }
347 }
348 chomp (@all);
349 return @all;
350 }
351
352 sub cleanup {
353 my $dir = shift;
354 my $path;
355
356 if ( "$dir" eq "meta" ) {
357 $path = "$Conf::dbdir/meta";
358 } elsif ( "$dir" eq "tmp" ) {
359 $path = "$Conf::tmpdir";
360 }
361 chdir("$path");
362 opendir(DIR,".");
363 my @files = readdir(DIR);
364 closedir(DIR);
365 foreach (@files) {
366 unless (($_ eq ".") || ($_ eq "..")) {
367 system("rm -rf $_");
368 }
369 }
370 }
371
372 sub getmetafile {
373 my $pak = shift;
374
375 logger("Going to download meta-$pak.");
376
377 unless ( -e "$Conf::dbdir/meta/meta-$pak") {
378 fetchfile("meta/meta-$pak", "");
379 move("$Conf::cachedir/meta-$pak", "$Conf::dbdir/meta/meta-$pak");
380 }
381
382 open(FILE, "<$Conf::dbdir/meta/meta-$pak");
383 my @line = <FILE>;
384 close(FILE);
385
386 open(FILE, ">$Conf::dbdir/meta/meta-$pak");
387 foreach (@line) {
388 my $string = $_;
389 $string =~ s/\r\n/\n/g;
390 print FILE $string;
391 }
392 close(FILE);
393 return 1;
394 }
395
396 sub getsize {
397 my $pak = shift;
398
399 getmetafile("$pak");
400
401 open(FILE, "<$Conf::dbdir/meta/meta-$pak");
402 my @file = <FILE>;
403 close(FILE);
404
405 my $line;
406 my @templine;
407 foreach $line (@file) {
408 @templine = split(/\: /,$line);
409 if ("$templine[0]" eq "Size") {
410 chomp($templine[1]);
411 return $templine[1];
412 }
413 }
414 return 0;
415 }
416
417 sub decryptpak {
418 my $pak = shift;
419
420 cleanup("tmp");
421
422 my $file = getpak("$pak", "noforce");
423
424 my $return = system("cd $Conf::tmpdir/ && gpg -d < $Conf::cachedir/$file | tar x >/dev/null 2>&1");
425 $return %= 255;
426 logger("Decryption process returned the following: $return");
427 if ($return != 0) { exit 1; }
428 }
429
430 sub getpak {
431 my $pak = shift;
432 my $force = shift;
433
434 getmetafile("$pak");
435
436 open(FILE, "<$Conf::dbdir/meta/meta-$pak");
437 my @file = <FILE>;
438 close(FILE);
439
440 my $line;
441 my $file;
442 my @templine;
443 foreach $line (@file) {
444 @templine = split(/\: /,$line);
445 if ("$templine[0]" eq "File") {
446 chomp($templine[1]);
447 $file = $templine[1];
448 }
449 }
450
451 unless ($file) {
452 message("No filename given in meta-file. Please phone the developers.");
453 exit 1;
454 }
455
456 unless ( "$force" eq "force" ) {
457 if ( -e "$Conf::cachedir/$file" ) {
458 return $file;
459 }
460 }
461
462 fetchfile("paks/$file", "");
463 return $file;
464 }
465
466 sub setuppak {
467 my $pak = shift;
468
469 message("################################################################################");
470 message("# --> Installing: $pak");
471 message("################################################################################");
472
473 decryptpak("$pak");
474
475 my $return = system("cd $Conf::tmpdir && NAME=$pak ./install.sh >> $Conf::logdir/install-$pak.log 2>&1");
476 $return %= 255;
477 if ($return == 0) {
478 move("$Conf::tmpdir/ROOTFILES", "$Conf::dbdir/rootfiles/$pak");
479 cleanup("tmp");
480 copy("$Conf::dbdir/meta/meta-$pak","$Conf::dbdir/installed/");
481 message("Setup completed. Congratulations!");
482 message("################################################################################");
483 fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid&ipak=$pak&return=$return", "$Conf::mainserver");
484 } else {
485 message("Setup returned: $return. Sorry. Please search our forum to find a solution for this problem.");
486 exit $return;
487 }
488 return $return;
489 }
490
491 sub isinstalled {
492 my $pak = shift;
493 if ( open(FILE,"<$Conf::dbdir/installed/meta-$pak") ) {
494 close(FILE);
495 return 0;
496 } else {
497 return 1;
498 }
499 }
500
501 sub upgradepak {
502 my $pak = shift;
503
504 message("We are going to upgrade: $pak");
505
506 decryptpak("$pak");
507
508 my $return = system("cd $Conf::tmpdir && NAME=$pak ./update.sh >> $Conf::logdir/update-$pak.log 2>&1");
509 $return %= 255;
510 if ($return == 0) {
511 move("$Conf::tmpdir/ROOTFILES", "$Conf::dbdir/rootfiles/$pak");
512 cleanup("tmp");
513 copy("$Conf::dbdir/meta/meta-$pak","$Conf::dbdir/installed/");
514 fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid&upak=$pak&return=$return", "$Conf::mainserver");
515 message("Upgrade completed. Congratulations!");
516 } else {
517 message("Setup returned: $return. Sorry. Please search our forum to find a solution for this problem.");
518 exit $return;
519 }
520 return $return;
521 }
522
523 sub removepak {
524 my $pak = shift;
525
526 message("We are going to uninstall: $pak");
527
528 decryptpak("$pak");
529
530 my $return = system("cd $Conf::tmpdir && NAME=$pak ./uninstall.sh >> $Conf::logdir/uninstall-$pak.log 2>&1");
531 $return %= 255;
532 if ($return == 0) {
533 open(FILE, "<$Conf::dbdir/rootfiles/$pak");
534 my @file = <FILE>;
535 close(FILE);
536 foreach (@file) {
537 my $line = $_;
538 chomp($line);
539 system("echo \"Removing: $line\" >> $Conf::logdir/uninstall-$pak.log 2>&1");
540 system("cd / && rm -rf $line >> $Conf::logdir/uninstall-$pak.log 2>&1");
541 }
542 unlink("$Conf::dbdir/rootfiles/$pak");
543 cleanup("tmp");
544 fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid&dpak=$pak&return=$return", "$Conf::mainserver");
545 message("Uninstall completed. Congratulations!");
546 } else {
547 message("Setup returned: $return. Sorry. Please search our forum to find a solution for this problem.");
548 exit $return;
549 }
550 return $return;
551 }
552
553 sub beautifysize {
554 my $size = shift;
555 $size = $size / 1024;
556 my $unit;
557
558 if ($size > 1023) {
559 $size = ($size / 1024);
560 $unit = "MB";
561 } else {
562 $unit = "KB";
563 }
564 $size = sprintf("%.2f" , $size);
565 my $string = "$size $unit";
566 return $string;
567 }
568
569 sub makeuuid {
570 unless ( -e "$Conf::dbdir/uuid" ) {
571 open(FILE, "</proc/sys/kernel/random/uuid");
572 my @line = <FILE>;
573 close(FILE);
574
575 open(FILE, ">$Conf::dbdir/uuid");
576 foreach (@line) {
577 print FILE $_;
578 }
579 close(FILE);
580 }
581 }
582
583 sub senduuid {
584 if ($pakfiresettings{'UUID'} ne "off") {
585 unless("$Conf::uuid") {
586 $Conf::uuid = `cat $Conf::dbdir/uuid`;
587 }
588 logger("Sending my uuid: $Conf::uuid");
589 fetchfile("cgi-bin/counter?ver=$Conf::version&uuid=$Conf::uuid", "$Conf::mainserver");
590 system("rm -f $Conf::tmpdir/counter* 2>/dev/null");
591 }
592 }
593
594 sub checkcryptodb {
595 my $myid = "64D96617"; # Our own gpg-key
596 my $trustid = "65D0FD58"; # Id of CaCert
597 my $ret = system("gpg --list-keys | grep -q $myid");
598 unless ( "$ret" eq "0" ) {
599 message("The GnuPG isn't configured corectly. Trying now to fix this.");
600 system("gpg --keyserver wwwkeys.de.pgp.net --always-trust --recv-key $myid");
601 system("gpg --keyserver wwwkeys.de.pgp.net --always-trust --recv-key $trustid");
602 }
603 }
604
605 1;