]> git.pld-linux.org Git - projects/distfiles.git/blame - file-fetcher.pl
- +x bits
[projects/distfiles.git] / file-fetcher.pl
CommitLineData
7ebf9245 1#!/usr/bin/perl -w
b396edfa 2# $Id$
7ebf9245 3
56ea0f1e 4use IPC::Run qw(run);
5
7a0595ea 6$commits_list = "pld-cvs-commit\@lists.pld-linux.org";
7ebf9245 7
b5c674c5 8$spool_dir = "./spool";
01806192
MM
9$copy_dir = "src"; # relative to ftp root
10$no_url_dir = "./upload";
11$df_server = "distfiles.pld-linux.org";
51fe5d4e 12$df_scp = "plddist\@ep09.pld-linux.org:ftp";
62f7358e 13$user_agent = "PLD/distfiles";
7ebf9245
MM
14
15@md5 = ();
ccbaa374 16@url = ();
7ebf9245
MM
17$problems = "";
18$normal_out = "";
19$requester = "";
20$file = "";
47f8fda7
MM
21$fetched_count = 0;
22$force_reply = 0;
bca91c1b 23$req_login = "nobody";
cba859d3 24$spec = "";
44cd280f 25@files = ();
7ebf9245
MM
26
27# try lookup some file in spool, exit if it cannot be done
28sub find_file_in_spool()
29{
30 opendir(DIR, $spool_dir) || die "can't opendir $spool_dir: $!";
31 while (1) {
32 my $f = readdir(DIR);
33 defined $f or last;
34 -f "$spool_dir/$f" or next;
35 $file = "$spool_dir/$f";
36 last;
37 }
38 closedir(DIR);
39
40 exit 0 if ($file eq "");
41}
42
43# read file from spool, and try unlink it. if cannot unlink -- exit
576dff03 44# sets $requester (email), $problems, @md5 (arrays of md5's)
ccbaa374 45# and @url (map from md5 to urls)
7ebf9245
MM
46sub read_spool_file()
47{
48 open(F, "< $file") || exit 0;
49 $requester = <F>;
50 chomp $requester;
576dff03 51 $requester =~ /^[a-zA-Z_0-9@.-]+$/
7a1a3819 52 or die "$file: evil requester: $requester";
bca91c1b
MM
53 $req_login = "";
54 $requester =~ /^([^@]+)\@/ and $req_login = $1;
576dff03 55 $req_login =~ /^[a-z0-9A-Z_.]+$/ or die "$file: evil requester $requester";
cba859d3 56 $spec = <F>;
bf2219c8 57 chomp $spec;
cba859d3 58 $spec =~ s/\.spec$//;
bf2219c8 59
47f8fda7
MM
60 my $flags = <F>;
61 $force_reply++ if ($flags =~ /force-reply/);
576dff03 62
7ebf9245
MM
63 while (<F>) {
64 if (/^ERROR/) {
65 s/^ERROR: //;
66 $problems .= $_;
f2a640bf 67 next;
7ebf9245 68 }
8ecb7fad 69 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*$/) {
e4708e3e 70 if (/\/$/) {
7a1a3819 71 $problems .= "$file: cannot fetch dir";
e4708e3e 72 } else {
7a1a3819
ER
73 push @md5, $1;
74 push @url, $2;
e4708e3e 75 }
76 } else {
7a1a3819 77 $problems .= "FILE: $file: corrupted";
e4708e3e 78 }
7ebf9245
MM
79 }
80 close(F);
81
82 unlink($file) || exit 0;
83}
84
44cd280f
MM
85sub basename($)
86{
87 my $f = shift;
88 $f =~ s|.*/||;
89 return $f;
90}
91
01806192 92sub by_md5($$)
7ebf9245
MM
93{
94 my ($md5, $url) = @_;
7ebf9245 95 $md5 =~ /^(.)(.)/;
01806192 96 return "/by-md5/$1/$2/$md5/" . basename($url);
6ce39ee7
MM
97}
98
01806192 99sub got_on_distfiles($$)
6ce39ee7 100{
01806192
MM
101 my ($md5, $url) = @_;
102 my $p = by_md5($md5, $url);
103 my $l = `lftp -c 'debug 0; open $df_server; quote size $p'`;
104 return $l =~ /^213 /;
105}
106
107sub copy_to_df($$)
108{
109 my ($from, $to) = @_;
92eba545 110 my $cmd = "scp -pr -B -q $from $df_scp/$to";
01806192
MM
111 open(E, "$cmd 2>&1 |") or die;
112 my $oops = "";
113 while (<E>) {
114 $oops .= $_;
115 }
219df45c
MM
116 $oops .= "\nThe command has exited with a non-zero status."
117 unless (close (E));
01806192
MM
118 $problems .= "scp problems: $cmd:\n$oops\n"
119 if ($oops ne "");
120 return ($oops ne "");
6ce39ee7
MM
121}
122
b5c674c5 123sub move_file($$$)
6ce39ee7 124{
b5c674c5 125 my ($md5, $url, $local_copy) = @_;
6ce39ee7 126
01806192 127 my $bn = basename($url);
576dff03 128
01806192
MM
129 if ($local_copy ne "$tmp_dir/$md5/$bn") {
130 if (system("mv -f \"$local_copy\" \"$tmp_dir/$md5/$bn\"")) {
131 $problems .= "FATAL: cannot move $local_copy to $tmp_dir\n";
132 return;
133 }
134 $local_copy = "$tmp_dir/$md5/$bn";
135 }
576dff03 136
01806192
MM
137 if (open(D, "> $tmp_dir/$md5/$bn.desc")) {
138 print D "URL: $url\n";
d286a317 139 print D "Login: $req_login\n";
01806192
MM
140 print D "MD5: $md5\n";
141 print D 'Fetched-by: $Id$'."\n";
142 print D "Time: " . time . "\n";
143 close(D);
7ebf9245 144 } else {
01806192
MM
145 $problems .= "ERROR: cannot write $bn.desc\n";
146 }
147
148 my $dir = by_md5($md5, $url);
149 $dir =~ s|/[^/]+/[^/]+$||;
150 if (copy_to_df("$tmp_dir/$md5/", $dir) == 0) {
576dff03 151 $normal_out .=
44cd280f
MM
152 "STORED: $url\n" .
153 "\t$md5 " . basename($url) . "\n" .
01806192 154 "\tSize: " . (-s $local_copy) . " bytes\n";
47f8fda7 155 $fetched_count++;
7ebf9245
MM
156 }
157}
158
b5c674c5
MM
159sub make_src_symlink($$)
160{
161 my ($md5, $url) = @_;
576dff03 162
01806192 163 return unless ($url =~ /^no-url/);
576dff03 164
01806192
MM
165 my $b = basename($url);
166 if (open(S, "> $tmp_dir/$b.link")) {
b5c674c5 167 if ($url =~ /^no-url-copy/) {
01806192 168 print S (".." . by_md5($md5, $url));
b5c674c5 169 } else {
01806192 170 print S "REMOVE";
b5c674c5 171 }
01806192
MM
172 close(S);
173 copy_to_df("$tmp_dir/$b.link", "$copy_dir/$b.link");
b5c674c5 174 } else {
01806192 175 $problems .= "ERROR: cannot write $tmp_dir/$b.link\n";
b5c674c5
MM
176 }
177}
178
179sub md5($)
180{
181 my $file = shift;
56ea0f1e 182 my $in = "";
183 my $md5 = "";
184 my $err = "";
185 my @cmd = ("md5sum", $file);
186
187 run \@cmd, \$in, \$md5, \$err;
188 if ($err ne "") {
189 chomp($err);
a6b09732 190 $problems .= "FATAL: " . $err . "\n";
191 return "error";
56ea0f1e 192 }
193 chomp $md5;
b5c674c5
MM
194 $md5 =~ /^([a-f0-9]{32})/ and $md5 = $1;
195 return $md5;
196}
197
198sub handle_no_url($$)
199{
200 my ($md5, $url) = @_;
576dff03 201
e4708e3e 202 unless ($url =~ m#://([^/]+)#) {
203 $problems .= "$url: corrupted! (no-url)";
204 return;
205 }
b5c674c5 206 my $basename = $1;
bca91c1b 207 my $file = "$no_url_dir/$req_login/$basename";
b5c674c5
MM
208
209 if (-f $file) {
210 my $computed_md5 = md5($file);
211 if ($computed_md5 ne $md5) {
212 $problems .= "FATAL: $file md5 mismatch, needed $md5, got $computed_md5\n";
213 } else {
214 move_file($md5, $url, $file);
215 make_src_symlink($md5, $url);
216 }
217 } else {
bca91c1b 218 $problems .= "FATAL: $file was not uploaded\n";
b5c674c5
MM
219 }
220}
221
7ebf9245
MM
222sub fetch_file($$)
223{
224 my ($md5, $url) = @_;
225 my $out = "";
08ea99b9 226 my $all_out = "";
01806192
MM
227 my $bn = basename($url);
228 my $local = "$tmp_dir/$md5/$bn";
8f58f574
JB
229 my $cmd = "wget -nv --no-check-certificate --user-agent=$user_agent -O $local \"$url\"";
230 my $cmd2 = "wget -nv --no-check-certificate --user-agent=$user_agent --passive-ftp -O $local \"$url\"";
b5c674c5 231
01806192 232 push @files, $bn;
44cd280f 233
b38176ba 234 if ( $bn =~ m/(%[0-9a-f]{2})/i ) {
235 $problems .= "$bn: refusing to download file with uri escape codes ($1) in the name\n";
236 $bn =~ s/%[0-9a-f]{2}/_/g;
237 $problems .= "HINT: use $url#/$bn as source to rename the file\n\n";
238 return;
239 }
240
01806192 241 if (got_on_distfiles($md5, $url)) {
576dff03 242 $normal_out .=
7a1a3819
ER
243 "ALREADY GOT: $url\n" .
244 "\t$md5 " . basename($url) . "\n";
b5c674c5 245 make_src_symlink($md5, $url);
6ce39ee7
MM
246 return;
247 }
01806192 248
2ae8fdec 249 mkdir("$tmp_dir/$md5");
576dff03 250
b5c674c5
MM
251 if ($url =~ /^no-url/) {
252 handle_no_url($md5, $url);
253 return;
254 }
576dff03 255
7ebf9245
MM
256 open(W, "$cmd 2>&1 |");
257 while (<W>) {
08ea99b9 258 $all_out .= $_;
7ebf9245
MM
259 /URL:.*\s+\-\>\s+.*/ and next;
260 $out .= $_;
261 }
262 close(W);
263 if ($out ne "") {
264 $problems .= "$cmd:\n$out\n\n";
265 }
d1c674a4 266 if ( $? ) {
b106d8c1 267 $problems .= sprintf "%s:\nexited with code %d (0x%02x)\n\n",
268 $cmd,
d1c674a4 269 $? >> 8,
270 $? & 0xff;
271 }
e23ae36a 272 if (-f $local && -s $local == 0 && $url =~ /^ftp:/) {
f4f705aa 273 $out = "";
c0467b40 274 open(W, "$cmd2 2>&1 |");
275 while (<W>) {
f4f705aa 276 $all_out .= "\n\t\t$_";
c0467b40 277 /URL:.*\s+\-\>\s+.*/ and next;
278 $out .= $_;
279 }
280 close(W);
281 if ($out ne "") {
d1c674a4 282 $problems .= "$cmd2:\n$out\n\n";
283 }
284 if ( $? ) {
b106d8c1 285 $problems .= sprintf "%s:\nexited with code %d (0x%02x)\n\n",
286 $cmd2,
d1c674a4 287 $? >> 8,
288 $? & 0xff;
c0467b40 289 }
290 }
4db63fc1 291 if (-r $local && -s $local > 0) {
01806192 292 my $computed_md5 = md5($local);
7ebf9245
MM
293 if ($computed_md5 ne $md5) {
294 $problems .= "FATAL: $url md5 mismatch, needed $md5, got $computed_md5\n";
295 } else {
d642cf7e 296 my $testcmd = "file \"$local\" |";
297 my $testres = "";
a14ed9b7 298 if ($url =~ /^(http|https):/ && $local =~ /\.(tar\.(bz2|gz)|tgz|zip|jar|xpi)$/) {
d642cf7e 299 open(T, $testcmd) or die;
300 $testres = <T>;
301 close(T);
302 }
303 if ($testres =~ /empty|(ASCII|HTML|SGML).*text/) {
304 $testres =~ s/.*://;
305 $problems .= "FATAL: data returned from $url: $testres";
306 } else {
307 move_file($md5, $url, $local);
308 }
7ebf9245 309 }
4db63fc1 310 } elsif (-f $local && -s $local > 0) {
9bfc693b 311 $problems .= "FATAL: $url ($md5) was not fetched correctly ($cmd: $all_out): file is not readable\n";
d1c674a4 312 } elsif (-f $local && not -s $local) {
9bfc693b 313 $problems .= "FATAL: $url ($md5) was not fetched correctly ($cmd: $all_out): file fetched but has 0 length\n";
7ebf9245 314 } else {
9bfc693b 315 $problems .= "FATAL: $url ($md5) was not fetched correctly ($cmd: $all_out)\n";
7ebf9245 316 }
01806192
MM
317 # save space
318 unlink($local);
7ebf9245
MM
319}
320
321sub fetch_files()
322{
323 $problems .= "\n\n" if ($problems ne "");
ccbaa374 324 foreach $i (0..$#md5) {
325 fetch_file($md5[$i], $url[$i]);
7ebf9245
MM
326 }
327}
328
329sub send_email()
330{
9a1e36f3
MM
331 open(EMAIL, "| /usr/sbin/sendmail -t");
332 #open(EMAIL, "| cat");
44cd280f 333 my $marker = "";
7ebf9245 334 if ($problems ne "") {
44cd280f 335 $marker = "ERRORS: ";
7ebf9245 336 }
04550b88
MM
337 my $req_login;
338 $requester =~ /^(.*)\@/ and $req_login = $1;
44cd280f
MM
339
340 splice(@files, 10, @files - 10, "...")
341 if (@files > 10);
576dff03
ER
342
343 print EMAIL
04550b88 344"From: $req_login <$requester>
482655f9
MM
345To: $commits_list
346Cc: $requester
8408fdb0 347Subject: DISTFILES: ${spec}: ${marker}@{files}
e157986d
MM
348Message-ID: <$$." . time . "\@distfiles.pld-linux.org>
349X-distfiles-program: file-fetcher.pl
350X-distfiles-version: " . '$Id$' . "
7ebf9245
MM
351
352$problems
47f8fda7
MM
353Files fetched: $fetched_count
354
7ebf9245 355$normal_out
e157986d
MM
356
357--
d8cd573c 358Virtually Yours: distfiles.
7ebf9245
MM
359";
360 close(EMAIL) or die;
361}
362
01806192
MM
363sub make_tmp_dir()
364{
365 my $id = `uuidgen 2>/dev/null`;
366 chomp $id;
367 $id = rand if (!defined $id or $id eq "");
368 $tmp_dir = "./tmp/$id";
369 mkdir($tmp_dir) or die;
370}
371
372sub clean_tmp_dir()
373{
374 system("rm -rf $tmp_dir")
375 if ($tmp_dir ne "" && -d $tmp_dir);
376}
377
2e33bbbc
MM
378umask(002);
379
7ebf9245
MM
380find_file_in_spool();
381read_spool_file();
01806192 382make_tmp_dir();
7ebf9245 383fetch_files();
47f8fda7 384send_email() unless (!$force_reply and $problems eq "" and $fetched_count == 0);
01806192 385clean_tmp_dir();
319fb6c1
ER
386
387# vim: ts=2:sw=2:et:fdm=marker
This page took 0.097747 seconds and 4 git commands to generate.