6 openlog("distfiles-ff", "pid", "user");
8 $commits_list = "pld-cvs-commit\@lists.pld-linux.org";
10 $spool_dir = "./spool";
11 $copy_dir = "src"; # relative to ftp root
12 $no_url_dir = "./upload";
13 $df_server = "distfiles.pld-linux.org";
14 $df_scp = "plddist\@distfiles.pld-linux.org:ftp";
15 $user_agent = "PLD/distfiles";
25 $req_login = "nobody";
33 syslog("err","FATAL: $msg");
37 # try lookup some file in spool, exit if it cannot be done
38 sub find_file_in_spool()
40 opendir(DIR, $spool_dir) || fatal("can't opendir $spool_dir: $!");
44 -f "$spool_dir/$f" or next;
45 $file = "$spool_dir/$f";
50 exit 0 if ($file eq "");
53 # read file from spool, and try unlink it. if cannot unlink -- exit
54 # sets $requester (email), $problems, @md5 (arrays of md5's)
55 # and @url (map from md5 to urls)
58 syslog("info","reading spool file $file");
59 open(F, "< $file") || exit 0;
62 $requester =~ /^[a-zA-Z_0-9@.-]+$/
63 or fatal("$file: evil requester: $requester");
65 $requester =~ /^([^@]+)\@/ and $req_login = $1;
66 $req_login =~ /^[a-z0-9A-Z_.]+$/ or fatal("$file: evil requester $requester");
72 $force_reply++ if ($flags =~ /force-reply/);
80 if (/^([a-f0-9]{32})\s+((ftp|http|https|no-url|no-url-copy):\/\/([a-z0-9A-Z;:\=\?&\@\+\~\.,\-\/_]|\%[0-9])+(#\/[a-zA-Z0-9\._-]+)?)\s*$/) {
82 $problems .= "$file: cannot fetch dir";
88 $problems .= "FILE: $file: corrupted";
93 unlink($file) || exit 0;
105 my ($md5, $url) = @_;
107 return "/by-md5/$1/$2/$md5/" . basename($url);
110 sub got_on_distfiles($$)
112 my ($md5, $url) = @_;
113 my $p = by_md5($md5, $url);
114 my $l = `lftp -c 'debug 0; open $df_server; quote size $p'`;
115 return $l =~ /^213 /;
120 my ($from, $to) = @_;
121 my $cmd = "scp -pr -B -q $from $df_scp/$to";
122 open(E, "$cmd 2>&1 |") or fatal("$cmd failed");
127 $oops .= "\nThe command has exited with a non-zero status."
129 $problems .= "scp problems: $cmd:\n$oops\n"
131 syslog("err","copy_to_df oops for '$cmd': $oops") if ($oops ne "");
132 return ($oops ne "");
137 my ($md5, $url, $local_copy) = @_;
139 my $bn = basename($url);
141 if ($local_copy ne "$tmp_dir/$md5/$bn") {
142 if (system("mv -f \"$local_copy\" \"$tmp_dir/$md5/$bn\"")) {
143 $problems .= "FATAL: cannot move $local_copy to $tmp_dir\n";
146 $local_copy = "$tmp_dir/$md5/$bn";
148 # no-url local copy may have wrong permissions (it's created by ftp upload)
150 chmod(0644, $local_copy);
152 if (open(D, "> $tmp_dir/$md5/$bn.desc")) {
153 print D "URL: $url\n";
154 print D "Login: $req_login\n";
155 print D "MD5: $md5\n";
156 print D 'Fetched-by: $Id$'."\n";
157 print D "Time: " . time . "\n";
160 $problems .= "ERROR: cannot write $bn.desc\n";
163 my $dir = by_md5($md5, $url);
164 $dir =~ s|/[^/]+/[^/]+$||;
165 if (copy_to_df("$tmp_dir/$md5/", $dir) == 0) {
168 "\t$md5 " . basename($url) . "\n" .
169 "\tSize: " . (-s $local_copy) . " bytes\n";
174 sub make_src_symlink($$)
176 my ($md5, $url) = @_;
178 return unless ($url =~ /^no-url/);
180 my $b = basename($url);
181 if (open(S, "> $tmp_dir/$b.link")) {
182 if ($url =~ /^no-url-copy/) {
183 print S (".." . by_md5($md5, $url));
188 copy_to_df("$tmp_dir/$b.link", "$copy_dir/$b.link");
190 $problems .= "ERROR: cannot write $tmp_dir/$b.link\n";
200 my @cmd = ("md5sum", $file);
202 run \@cmd, \$in, \$md5, \$err;
205 $problems .= "FATAL: " . $err . "\n";
209 $md5 =~ /^([a-f0-9]{32})/ and $md5 = $1;
213 sub handle_no_url($$)
215 my ($md5, $url) = @_;
217 unless ($url =~ m#://([^/]+)#) {
218 $problems .= "$url: corrupted! (no-url)";
222 my $file = "$no_url_dir/$basename";
224 $file = "$no_url_dir/$req_login/$basename" unless (-f $file);
227 my $computed_md5 = md5($file);
228 if ($computed_md5 ne $md5) {
229 $problems .= "FATAL: $basename md5 mismatch, needed $md5, got $computed_md5\n";
231 move_file($md5, $url, $file);
232 make_src_symlink($md5, $url);
235 $problems .= "FATAL: $basename was not uploaded\n";
241 my ($md5, $url) = @_;
244 my $bn = basename($url);
245 my $local = "$tmp_dir/$md5/$bn";
246 my @cmd = ("wget", "-nv", "--no-check-certificate", "--user-agent=$user_agent", "-O", $local, $url);
247 my $cmd_joined = join(' ', @cmd);
248 my @cmd2 = ("wget", "-nv", "--no-check-certificate", "--user-agent=$user_agent", "--passive-ftp", "-O", $local, $url);
249 my $cmd2_joined = join(' ', @cmd2);
251 syslog("info","fetch_file($md5,$url)");
255 if ( $bn =~ m/(%[0-9a-f]{2})/i ) {
256 $problems .= "$bn: refusing to download file with uri escape codes ($1) in the name\n";
257 $bn =~ s/%[0-9a-f]{2}/_/g;
258 $problems .= "HINT: use $url?/$bn as source to rename the file\n\n";
262 if (got_on_distfiles($md5, $url)) {
264 "ALREADY GOT: $url\n" .
265 "\t$md5 " . basename($url) . "\n";
266 make_src_symlink($md5, $url);
270 mkdir("$tmp_dir/$md5");
272 if ($url =~ /^no-url/) {
273 handle_no_url($md5, $url);
277 my $pid = open(W, "-|");
278 fatal("Cannot fork $!") unless defined $pid;
280 open STDERR, ">&", \*STDOUT or fatal("$0: open: $!");
281 exec { $cmd[0] } @cmd or fatal("$0: exec: $!");
285 /URL:.*\s+\-\>\s+.*/ and next;
290 syslog("err","$cmd_joined: $out");
291 $problems .= "$cmd_joined:\n$out\n\n";
294 $problems .= sprintf "%s:\nexited with code %d (0x%02x)\n\n",
299 if (-f $local && -s $local == 0 && $url =~ /^ftp:/) {
301 my $pid = open(W, "-|");
302 fatal("Cannot fork $!") unless defined $pid;
304 open STDERR, ">&", \*STDOUT or fatal("$0: open: $!");
305 exec { $cmd2[0] } @cmd2 or fatal("$0: exec: $!");
308 $all_out .= "\n\t\t$_";
309 /URL:.*\s+\-\>\s+.*/ and next;
314 $problems .= "$cmd2_joined:\n$out\n\n";
317 $problems .= sprintf "%s:\nexited with code %d (0x%02x)\n\n",
323 if (-r $local && -s $local > 0) {
324 my $computed_md5 = md5($local);
325 if ($computed_md5 ne $md5) {
326 $problems .= "FATAL: $url md5 mismatch, needed $md5, got $computed_md5\n";
328 my $testcmd = "file \"$local\" |";
330 if ($url =~ /^(http|https):/ && $local =~ /\.(tar\.(bz2|gz)|tgz|zip|jar|xpi)$/) {
331 open(T, $testcmd) or fatal("$testcmd failed");
335 if ($testres =~ /empty|(ASCII|HTML|SGML).*text/) {
337 $problems .= "FATAL: data returned from $url: $testres";
339 move_file($md5, $url, $local);
342 } elsif (-f $local && -s $local > 0) {
343 $problems .= "FATAL: $url ($md5) was not fetched correctly ($cmd_joined: $all_out): file is not readable\n";
344 } elsif (-f $local && not -s $local) {
345 $problems .= "FATAL: $url ($md5) was not fetched correctly ($cmd_joined: $all_out): file fetched but has 0 length\n";
347 $problems .= "FATAL: $url ($md5) was not fetched correctly ($cmd_joined: $all_out)\n";
355 $problems .= "\n\n" if ($problems ne "");
356 foreach $i (0..$#md5) {
357 fetch_file($md5[$i], $url[$i]);
363 syslog("info","sending email to $requester");
364 open(EMAIL, "| /usr/sbin/sendmail -t");
365 #open(EMAIL, "| cat");
367 if ($problems ne "") {
368 $marker = "ERRORS: ";
371 $requester =~ /^(.*)\@/ and $req_login = $1;
373 splice(@files, 10, @files - 10, "...")
377 "From: $req_login <$requester>
380 Subject: DISTFILES: ${spec}: ${marker}@{files}
381 Message-ID: <$$." . time . "\@distfiles.pld-linux.org>
382 X-distfiles-program: file-fetcher.pl
383 X-distfiles-version: " . '$Id$' . "
386 Files fetched: $fetched_count
391 Virtually Yours: distfiles.
393 close(EMAIL) or fatal("close() failed");
398 my $id = `uuidgen 2>/dev/null`;
400 $id = rand if (!defined $id or $id eq "");
401 $tmp_dir = "./tmp/$id";
402 mkdir($tmp_dir) or fatal("mkdir($tmp_dir) failed");
407 system("rm -rf $tmp_dir")
408 if ($tmp_dir ne "" && -d $tmp_dir);
413 find_file_in_spool();
417 send_email() unless (!$force_reply and $problems eq "" and $fetched_count == 0);
420 # vim: ts=2:sw=2:et:fdm=marker