1#!/usr/bin/env perl 2# 3# Copyright (C) 2006 OpenWrt.org 4# 5# This is free software, licensed under the GNU General Public License v2. 6# See /LICENSE for more information. 7# 8 9use strict; 10use warnings; 11use File::Basename; 12use File::Copy; 13 14@ARGV > 2 or die "Syntax: $0 <target dir> <filename> <hash> <url filename> [<mirror> ...]\n"; 15 16my $url_filename; 17my $target = shift @ARGV; 18my $filename = shift @ARGV; 19my $file_hash = shift @ARGV; 20$url_filename = shift @ARGV unless $ARGV[0] =~ /:\/\//; 21my $scriptdir = dirname($0); 22my @mirrors; 23my $ok; 24 25$url_filename or $url_filename = $filename; 26 27sub localmirrors { 28 my @mlist; 29 open LM, "$scriptdir/localmirrors" and do { 30 while (<LM>) { 31 chomp $_; 32 push @mlist, $_ if $_; 33 } 34 close LM; 35 }; 36 open CONFIG, "<".$ENV{'TOPDIR'}."/.config" and do { 37 while (<CONFIG>) { 38 /^CONFIG_LOCALMIRROR="(.+)"/ and do { 39 chomp; 40 my @local_mirrors = split(/;/, $1); 41 push @mlist, @local_mirrors; 42 }; 43 } 44 close CONFIG; 45 }; 46 47 my $mirror = $ENV{'DOWNLOAD_MIRROR'}; 48 $mirror and push @mlist, split(/;/, $mirror); 49 50 return @mlist; 51} 52 53sub which($) { 54 my $prog = shift; 55 my $res = `which $prog`; 56 $res or return undef; 57 $res =~ /^no / and return undef; 58 $res =~ /not found/ and return undef; 59 return $res; 60} 61 62sub hash_cmd() { 63 my $len = length($file_hash); 64 my $cmd; 65 66 $len == 64 and return "openssl dgst -sha256 | sed -e 's,.*= ,,'"; 67 $len == 32 and do { 68 my $cmd = which("md5sum") || which("md5") || die 'no md5 checksum program found, please install md5 or md5sum'; 69 chomp $cmd; 70 return $cmd; 71 }; 72 return undef; 73} 74 75my $hash_cmd = hash_cmd(); 76 77sub download 78{ 79 my $mirror = shift; 80 my $options = $ENV{WGET_OPTIONS} || ""; 81 82 $mirror =~ s!/$!!; 83 84 if ($mirror =~ s!^file://!!) { 85 if (! -d "$mirror") { 86 print STDERR "Wrong local cache directory -$mirror-.\n"; 87 cleanup(); 88 return; 89 } 90 91 if (! -d "$target") { 92 system("mkdir", "-p", "$target/"); 93 } 94 95 if (! open TMPDLS, "find $mirror -follow -name $filename 2>/dev/null |") { 96 print("Failed to search for $filename in $mirror\n"); 97 return; 98 } 99 100 my $link; 101 102 while (defined(my $line = readline TMPDLS)) { 103 chomp ($link = $line); 104 if ($. > 1) { 105 print("$. or more instances of $filename in $mirror found . Only one instance allowed.\n"); 106 return; 107 } 108 } 109 110 close TMPDLS; 111 112 if (! $link) { 113 print("No instances of $filename found in $mirror.\n"); 114 return; 115 } 116 117 print("Copying $filename from $link\n"); 118 copy($link, "$target/$filename.dl"); 119 120 $hash_cmd and do { 121 if (system("cat '$target/$filename.dl' | $hash_cmd > '$target/$filename.hash'")) { 122 print("Failed to generate hash for $filename\n"); 123 return; 124 } 125 }; 126 } else { 127 open WGET, "wget -t5 --timeout=20 --no-check-certificate $options -O- '$mirror/$url_filename' |" or die "Cannot launch wget.\n"; 128 $hash_cmd and do { 129 open MD5SUM, "| $hash_cmd > '$target/$filename.hash'" or die "Cannot launch $hash_cmd.\n"; 130 }; 131 open OUTPUT, "> $target/$filename.dl" or die "Cannot create file $target/$filename.dl: $!\n"; 132 my $buffer; 133 while (read WGET, $buffer, 1048576) { 134 $hash_cmd and print MD5SUM $buffer; 135 print OUTPUT $buffer; 136 } 137 $hash_cmd and close MD5SUM; 138 close WGET; 139 close OUTPUT; 140 141 if ($? >> 8) { 142 print STDERR "Download failed.\n"; 143 cleanup(); 144 return; 145 } 146 } 147 148 $hash_cmd and do { 149 my $sum = `cat "$target/$filename.hash"`; 150 $sum =~ /^(\w+)\s*/ or die "Could not generate file hash\n"; 151 $sum = $1; 152 153 if ($sum ne $file_hash) { 154 print STDERR "MD5 sum of the downloaded file does not match (file: $sum, requested: $file_hash) - deleting download.\n"; 155 cleanup(); 156 return; 157 } 158 }; 159 160 unlink "$target/$filename"; 161 system("mv", "$target/$filename.dl", "$target/$filename"); 162 cleanup(); 163} 164 165sub cleanup 166{ 167 unlink "$target/$filename.dl"; 168 unlink "$target/$filename.hash"; 169} 170 171@mirrors = localmirrors(); 172 173foreach my $mirror (@ARGV) { 174 if ($mirror =~ /^\@SF\/(.+)$/) { 175 # give sourceforge a few more tries, because it redirects to different mirrors 176 for (1 .. 5) { 177 push @mirrors, "http://downloads.sourceforge.net/$1"; 178 } 179 } elsif ($mirror =~ /^\@APACHE\/(.+)$/) { 180 push @mirrors, "http://ftp.tudelft.nl/apache/$1"; 181 push @mirrors, "http://apache.openmirror.de/$1"; 182 push @mirrors, "http://mirrors.ocf.berkeley.edu/apache/$1"; 183 push @mirrors, "http://mirror.cc.columbia.edu/pub/software/apache/$1"; 184 push @mirrors, "http://ftp.jaist.ac.jp/pub/apache/$1"; 185 } elsif ($mirror =~ /^\@GITHUB\/(.+)$/) { 186 # give github a few more tries (different mirrors) 187 for (1 .. 5) { 188 push @mirrors, "https://raw.githubusercontent.com/$1"; 189 } 190 } elsif ($mirror =~ /^\@GNU\/(.+)$/) { 191 push @mirrors, "http://ftpmirror.gnu.org/$1"; 192 push @mirrors, "http://ftp.gnu.org/pub/gnu/$1"; 193 push @mirrors, "ftp://ftp.belnet.be/mirror/ftp.gnu.org/gnu/$1"; 194 push @mirrors, "ftp://ftp.mirror.nl/pub/mirror/gnu/$1"; 195 push @mirrors, "http://mirror.switch.ch/ftp/mirror/gnu/$1"; 196 } elsif ($mirror =~ /^\@SAVANNAH\/(.+)$/) { 197 push @mirrors, "http://download.savannah.gnu.org/releases/$1"; 198 push @mirrors, "http://nongnu.uib.no/$1"; 199 push @mirrors, "http://ftp.igh.cnrs.fr/pub/nongnu/$1"; 200 push @mirrors, "http://download-mirror.savannah.gnu.org/releases/$1"; 201 } elsif ($mirror =~ /^\@KERNEL\/(.+)$/) { 202 my @extra = ( $1 ); 203 if ($filename =~ /linux-\d+\.\d+(?:\.\d+)?-rc/) { 204 push @extra, "$extra[0]/testing"; 205 } elsif ($filename =~ /linux-(\d+\.\d+(?:\.\d+)?)/) { 206 push @extra, "$extra[0]/longterm/v$1"; 207 } 208 foreach my $dir (@extra) { 209 push @mirrors, "https://cdn.kernel.org/pub/$dir"; 210 push @mirrors, "https://www.kernel.org/pub/$dir"; 211 } 212 } elsif ($mirror =~ /^\@GNOME\/(.+)$/) { 213 push @mirrors, "http://ftp.gnome.org/pub/GNOME/sources/$1"; 214 push @mirrors, "http://www.mirrorservice.org/sites/ftp.gnome.org/pub/GNOME/sources/$1"; 215 push @mirrors, "http://fr2.rpmfind.net/linux/gnome.org/sources/$1"; 216 push @mirrors, "http://ftp.acc.umu.se/pub/GNOME/sources/$1"; 217 push @mirrors, "http://ftp.belnet.be/ftp.gnome.org/sources/$1"; 218 push @mirrors, "ftp://ftp.cse.buffalo.edu/pub/Gnome/sources/$1"; 219 push @mirrors, "ftp://ftp.nara.wide.ad.jp/pub/X11/GNOME/sources/$1"; 220 } 221 else { 222 push @mirrors, $mirror; 223 } 224} 225 226#push @mirrors, 'http://mirror1.openwrt.org'; 227push @mirrors, 'http://mirror2.openwrt.org/sources'; 228push @mirrors, 'http://downloads.openwrt.org/sources'; 229 230while (!$ok) { 231 my $mirror = shift @mirrors; 232 $mirror or die "No more mirrors to try - giving up.\n"; 233 234 download($mirror); 235 -f "$target/$filename" and $ok = 1; 236} 237 238$SIG{INT} = \&cleanup; 239 240