paste.org.ru Wed Nov  5 23:24:48 2014 : Anonymous : perl : 19289 wide : parent [ 11 years ]
cookies:
name:

scheme:

custom css:


tools:
custom css sample
paste bash script
more coming soon
or not soon...
last:

- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous
- Anonymous

  1. #!/usr/bin/perl -w
  2. =pod
  3. =head1 NAME
  4. apt-mirror - apt sources mirroring tool
  5. =head1 SYNOPSIS
  6. apt-mirror [configfile]
  7. =head1 DESCRIPTION
  8. A small and efficient tool that lets you mirror a part of or
  9. the whole Debian GNU/Linux distribution or any other apt sources.
  10. Main features:
  11. * It uses a config similar to apts F<sources.list>
  12. * It's fully pool comply
  13. * It supports multithreaded downloading
  14. * It supports multiple architectures at the same time
  15. * It can automatically remove unneeded files
  16. * It works well on overloaded channel to internet
  17. * It never produces an inconsistent mirror including while mirroring
  18. * It works on all POSIX compliant systems with perl and wget
  19. =head1 COMMENTS
  20. apt-mirror uses F</etc/apt/mirror.list> as a configuration file.
  21. By default it is tuned to official Debian or Ubuntu mirrors. Change
  22. it for your needs.
  23. After you setup the configuration file you may run as root:
  24. # su - apt-mirror -c apt-mirror
  25. Or uncomment line in F</etc/cron.d/apt-mirror> to enable daily mirror updates.
  26. =head1 FILES
  27. F</etc/apt/mirror.list>
  28. Main configuration file
  29. F</etc/cron.d/apt-mirror>
  30. Cron configuration template
  31. F</var/spool/apt-mirror/mirror>
  32. Mirror places here
  33. F</var/spool/apt-mirror/skel>
  34. Place for temporarily downloaded indexes
  35. F</var/spool/apt-mirror/var>
  36. Log files placed here. URLs and MD5 summs also here.
  37. =head1 CONFIGURATION EXAMPLES
  38. The mirror.list configuration supports many options, the file is well commented explinging each option.
  39. here are some sample mirror configuration lines showing the various supported ways :
  40. Normal:
  41. deb http://example.com/debian stable main contrib non-free
  42. Arch Specific: ( many other arch's are supported )
  43. deb-powerpc http://example.com/debian stable main contrib non-free
  44. HTTP and FTP Auth or non-standard port:
  45. deb http://user:pass@example.com:8080/debian stable main contrib non-free
  46. Source Mirroring:
  47. deb-src http://example.com/debian stable main contrib non-free
  48. =head1 ORIGINAL AUTHOR
  49. Dmitry N. Hramtsov E<lt>hdn@nsu.ruE<gt>
  50. =head1 MAINTAINERS
  51. Dmitry N. Hramtsov E<lt>hdn@nsu.ruE<gt>
  52. Brandon Holtsclaw E<lt>brandon@imbrandon.comE<gt>
  53. =cut
  54. use strict;
  55. use File::Copy;
  56. use File::Path;
  57. use File::Basename;
  58. my $config_file;
  59. my %config_variables = (
  60. "defaultarch" => `dpkg --print-installation-architecture 2>/dev/null` || 'i386',
  61. "nthreads" => 20,
  62. "base_path" => '/var/spool/apt-mirror',
  63. "mirror_path" => '$base_path/mirror',
  64. "skel_path" => '$base_path/skel',
  65. "var_path" => '$base_path/var',
  66. "cleanscript" => '$var_path/clean.sh',
  67. "_contents" => 1,
  68. "_autoclean" => 0,
  69. "_tilde" => 0,
  70. "limit_rate" => '100m',
  71. "run_postmirror" => 1,
  72. "postmirror_script" => '$var_path/postmirror.sh'
  73. );
  74. my @config_binaries = ();
  75. my @config_sources = ();
  76. my @index_urls;
  77. my @childrens = ();
  78. my %skipclean = ();
  79. my %clean_directory = ();
  80. ######################################################################################
  81. ## Setting up $config_file variable
  82. $config_file = "/etc/apt/mirror.list"; # Default value
  83. if($_ = shift) {
  84. die("apt-mirror: invalid config file specified") unless -f $_;
  85. $config_file = $_;
  86. }
  87. chomp $config_variables{"defaultarch"};
  88. ######################################################################################
  89. ## Common subroutines
  90. sub round_number
  91. {
  92. my $n = shift;
  93. my $minus = $n < 0 ? '-' : '';
  94. $n = abs($n);
  95. $n = int(($n + .05) * 10) / 10;
  96. $n .= '.0' unless $n =~ /\./;
  97. $n .= '0' if substr($n,(length($n) - 1),1) eq '.';
  98. chop $n if $n =~ /\.\d\d0$/;
  99. return "$minus$n";
  100. }
  101. sub format_bytes {
  102. my $bytes = shift;
  103. my $bytes_out = '0';
  104. my $size_name = 'bytes';
  105. my $KiB = 1024;
  106. my $MiB = 1024 * 1024;
  107. my $GiB = 1024 * 1024 * 1024;
  108. if ($bytes >= $KiB) {
  109. $bytes_out = $bytes / $KiB;
  110. $size_name = 'KiB';
  111. if ($bytes >= $MiB) {
  112. $bytes_out = $bytes / $MiB;
  113. $size_name = 'MiB';
  114. if ($bytes >= $GiB) {
  115. $bytes_out = $bytes / $GiB;
  116. $size_name = 'GiB';
  117. }
  118. }
  119. } else {
  120. $bytes_out = $bytes;
  121. $size_name = 'bytes';
  122. }
  123. $bytes_out = round_number($bytes_out);
  124. return "$bytes_out $size_name";
  125. }
  126. sub get_variable {
  127. my $value = $config_variables{shift @_};
  128. my $count = 16;
  129. while($value =~ s/\$(\w+)/$config_variables{$1}/xg) {
  130. die("apt-mirror: too many substitution while evaluating variable") if ($count --) < 0;
  131. }
  132. return $value;
  133. }
  134. sub lock_aptmirror {
  135. system ("touch " . get_variable("var_path") . "/apt-mirror.lock");
  136. }
  137. sub check_lock {
  138. if(-e get_variable("var_path") . "/apt-mirror.lock")
  139. {
  140. die("apt-mirror is already running, exiting");
  141. }
  142. }
  143. sub unlock_aptmirror {
  144. unlink(get_variable("var_path") . "/apt-mirror.lock");
  145. }
  146. sub download_urls {
  147. my $stage = shift;
  148. my @urls;
  149. my $i = 0;
  150. my $pid;
  151. my $nthreads = get_variable("nthreads");
  152. local $| = 1;
  153. @urls = @_;
  154. $nthreads = @urls if @urls < $nthreads;
  155. print "Downloading " . scalar(@urls) . " $stage files using $nthreads threads...\n";
  156. while(scalar @urls) {
  157. my @part = splice(@urls, 0, int(@urls / $nthreads));
  158. open URLS, ">" . get_variable("var_path") . "/$stage-urls.$i" or die("apt-mirror: can't write to intermediate file ($stage-urls.$i)");
  159. foreach (@part) { print URLS "$_\n"; }
  160. close URLS or die("apt-mirror: can't close intermediate file ($stage-urls.$i)");
  161. $pid = fork();
  162. die("apt-mirror: can't do fork in download_urls") if $pid < 0;
  163. if($pid == 0) {
  164. # print " * Running wget $i...\n";
  165. exec 'wget', '--limit-rate='.get_variable("limit_rate"), '-t', '0', '-r', '-N', '-l', 'inf', '-o', get_variable("var_path") . "/$stage-log.$i", '-i', get_variable("var_path") . "/$stage-urls.$i";
  166. # print " * Can't exec $i...\n";
  167. # unlink get_variable("var_path") . "/URLS.$i";
  168. # unlink get_variable("var_path") . "/wget-log.$i";
  169. # exit 1;
  170. }
  171. push @childrens, $pid;
  172. $i++; $nthreads--;
  173. }
  174. print "Begin time: " . localtime() . "\n[" . scalar(@childrens) . "]... ";
  175. while(scalar @childrens) {
  176. my $dead = wait();
  177. @childrens = grep { $_ != $dead } @childrens;
  178. print "[" . scalar(@childrens) . "]... ";
  179. }
  180. print "\nEnd time: " . localtime() . "\n\n";
  181. }
  182. ######################################################################################
  183. ## Create the 3 needed directories if they don't exist yet
  184. my @needed_directories = (get_variable("mirror_path"), get_variable("skel_path"), get_variable("var_path"));
  185. foreach my $needed_directory (@needed_directories) {
  186. unless (-d $needed_directory) {
  187. mkdir($needed_directory) or die("apt-mirror: can't create $needed_directory directory");
  188. }
  189. }
  190. ######################################################################################
  191. ## Parse config
  192. open CONFIG, "<$config_file" or die("apt-mirror: can't open config file ($config_file)");
  193. while(<CONFIG>) {
  194. next if /^\s*#/;
  195. next unless /\S/;
  196. my @config_line = split;
  197. my $config_line = shift @config_line;
  198. if($config_line eq "set") {
  199. $config_variables{$config_line[0]} = $config_line[1];
  200. next;
  201. }
  202. if($config_line eq "deb") {
  203. push @config_binaries, [get_variable("defaultarch"), @config_line];
  204. next;
  205. }
  206. if($config_line =~ /deb-(alpha|amd64|armel|arm|hppa|hurd-i386|i386|ia64|lpia|m68k|mipsel|mips|powerpc|s390|sh|sparc)/) {
  207. push @config_binaries, [$1, @config_line];
  208. next;
  209. }
  210. if($config_line eq "deb-src") {
  211. push @config_sources, [@config_line];
  212. next;
  213. }
  214. if($config_line eq "skip-clean") {
  215. $config_line[0] =~ s[^(\w+)://][];
  216. $config_line[0] =~ s[/$][];
  217. $config_line[0] =~ s[~][%7E]g if get_variable("_tilde");
  218. $skipclean{$config_line[0]} = 1;
  219. next;
  220. }
  221. if($config_line eq "clean") {
  222. $config_line[0] =~ s[^(\w+)://][];
  223. $config_line[0] =~ s[/$][];
  224. $config_line[0] =~ s[~][%7E]g if get_variable("_tilde");
  225. $clean_directory{$config_line[0]} = 1;
  226. next;
  227. }
  228. die("apt-mirror: invalid line in config file ($.: $config_line ...)");
  229. }
  230. close CONFIG;
  231. die("Please explicitly specify 'defaultarch' in mirror.list") unless get_variable("defaultarch");
  232. check_lock();
  233. $SIG{INT} = "unlock_aptmirror";
  234. $SIG{HUP} = "unlock_aptmirror";
  235. $SIG{TERM} = "unlock_aptmirror";
  236. lock_aptmirror();
  237. ######################################################################################
  238. ## Skel download
  239. my %urls_to_download = ();
  240. my ($url, $arch);
  241. sub remove_double_slashes {
  242. local $_ = shift;
  243. while(s[/\./][/]g) {}
  244. while(s[(?<!:)//][/]g) {}
  245. while(s[(?<!:/)/[^/]+/\.\./][/]g) {}
  246. s/~/\%7E/g if get_variable("_tilde");
  247. return $_;
  248. }
  249. sub add_url_to_download {
  250. my $url = remove_double_slashes(shift);
  251. $urls_to_download{$url} = shift;
  252. }
  253. foreach (@config_sources) {
  254. my ($uri, $distribution, @components) = @{$_};
  255. if(@components) {
  256. $url = $uri . "/dists/" . $distribution . "/";
  257. add_url_to_download($url . "Release");
  258. add_url_to_download($url . "Release.gpg");
  259. foreach (@components) {
  260. add_url_to_download($url . $_ . "/source/Release");
  261. add_url_to_download($url . $_ . "/source/Sources.gz");
  262. add_url_to_download($url . $_ . "/source/Sources.bz2");
  263. }
  264. } else {
  265. add_url_to_download($uri . "/$distribution/Sources.gz");
  266. add_url_to_download($uri . "/$distribution/Sources.bz2");
  267. }
  268. }
  269. foreach (@config_binaries) {
  270. my ($arch, $uri, $distribution, @components) = @{$_};
  271. if(@components) {
  272. $url = $uri . "/dists/" . $distribution . "/";
  273. add_url_to_download($url . "Release");
  274. add_url_to_download($url . "Release.gpg");
  275. if (get_variable("_contents")) {
  276. add_url_to_download($url . "Contents-" . $arch . ".gz");
  277. add_url_to_download($url . "Contents-" . $arch . ".bz2");
  278. }
  279. foreach (@components) {
  280. add_url_to_download($url . $_ . "/binary-" . $arch . "/Release");
  281. add_url_to_download($url . $_ . "/binary-" . $arch . "/Packages.gz");
  282. add_url_to_download($url . $_ . "/binary-" . $arch . "/Packages.bz2");
  283. }
  284. } else {
  285. add_url_to_download($uri . "/$distribution/Packages.gz");
  286. add_url_to_download($uri . "/$distribution/Packages.bz2");
  287. }
  288. }
  289. chdir get_variable("skel_path") or die("apt-mirror: can't chdir to skel");
  290. @index_urls = sort keys %urls_to_download;
  291. download_urls("index", @index_urls);
  292. foreach (keys %urls_to_download) {
  293. s[^(\w+)://][];
  294. s[~][%7E]g if get_variable("_tilde");
  295. $skipclean{$_} = 1;
  296. $skipclean{$_} = 1 if s[\.gz$][];
  297. $skipclean{$_} = 1 if s[\.bz2$][];
  298. }
  299. ######################################################################################
  300. ## Main download prepair
  301. %urls_to_download = ();
  302. open FILES_ALL, ">" . get_variable("var_path") . "/ALL" or die("apt-mirror: can't write to intermediate file (ALL)");
  303. open FILES_NEW, ">" . get_variable("var_path") . "/NEW" or die("apt-mirror: can't write to intermediate file (NEW)");
  304. open FILES_MD5, ">" . get_variable("var_path") . "/MD5" or die("apt-mirror: can't write to intermediate file (MD5)");
  305. my %stat_cache = ();
  306. sub _stat {
  307. my ($filename) = shift;
  308. return @{$stat_cache{$filename}} if exists $stat_cache{$filename};
  309. my @res = stat($filename);
  310. $stat_cache{$filename} = \@res;
  311. return @res;
  312. }
  313. sub clear_stat_cache {
  314. %stat_cache = ();
  315. }
  316. sub need_update {
  317. my $filename = shift;
  318. my $size_on_server = shift;
  319. my (undef, undef, undef, undef, undef, undef, undef, $size) = _stat($filename);
  320. return 1 unless($size);
  321. return 0 if $size_on_server == $size;
  322. return 1;
  323. }
  324. sub remove_spaces($) {
  325. my $hashref = shift;
  326. foreach (keys %{$hashref}) {
  327. while(substr($hashref->{$_}, 0, 1) eq ' ') {
  328. substr($hashref->{$_}, 0, 1) = '';
  329. }
  330. }
  331. }
  332. sub sanitise_uri {
  333. my $uri = shift;
  334. $uri =~ s[^(\w+)://][];
  335. $uri =~ s/^([^@]+)?@?// if $uri =~ /@/;
  336. $uri =~ s&:\d+/&/&; # and port information
  337. $uri =~ s/~/\%7E/g if get_variable("_tilde");
  338. return $uri;
  339. }
  340. sub proceed_index_gz {
  341. my $uri = shift;
  342. my $index = shift;
  343. my ($path, $package, $mirror, $files) = '';
  344. $path = sanitise_uri($uri);
  345. local $/ = "\n\n";
  346. $mirror = get_variable("mirror_path") . "/" . $path;
  347. if($index =~ s/\.gz$//) {
  348. system("gunzip < $path/$index.gz > $path/$index");
  349. }
  350. open STREAM, "<$path/$index" or die("apt-mirror: can't open index in proceed_index_gz");
  351. while($package = <STREAM>) {
  352. local $/ = "\n";
  353. chomp $package;
  354. my (undef, %lines) = split(/^([\w\-]+:)/m, $package);
  355. chomp(%lines);
  356. remove_spaces(\%lines);
  357. if(exists $lines{"Filename:"}) { # Packages index
  358. $skipclean{remove_double_slashes($path . "/" . $lines{"Filename:"})} = 1;
  359. print FILES_ALL remove_double_slashes($path . "/" . $lines{"Filename:"}) . "\n";
  360. print FILES_MD5 $lines{"MD5sum:"} . " " . remove_double_slashes($path . "/" . $lines{"Filename:"}) . "\n";
  361. if(need_update($mirror . "/" . $lines{"Filename:"}, $lines{"Size:"})) {
  362. print FILES_NEW remove_double_slashes($uri . "/" . $lines{"Filename:"}) . "\n";
  363. add_url_to_download($uri . "/" . $lines{"Filename:"}, $lines{"Size:"});
  364. }
  365. } else { # Sources index
  366. foreach (split(/\n/, $lines{"Files:"})) {
  367. next if $_ eq '';
  368. my @file = split;
  369. die("apt-mirror: invalid Sources format") if @file != 3;
  370. $skipclean{remove_double_slashes($path . "/" . $lines{"Directory:"} . "/" . $file[2])} = 1;
  371. print FILES_ALL remove_double_slashes($path . "/" . $lines{"Directory:"} . "/" . $file[2]) . "\n";
  372. print FILES_MD5 $file[0] . " " . remove_double_slashes($path . "/" . $lines{"Directory:"} . "/" . $file[2]) . "\n";
  373. if(need_update($mirror . "/" . $lines{"Directory:"} . "/" . $file[2], $file[1])) {
  374. print FILES_NEW remove_double_slashes($uri . "/" . $lines{"Directory:"} . "/" . $file[2]) . "\n";
  375. add_url_to_download($uri . "/" . $lines{"Directory:"} . "/" . $file[2], $file[1]);
  376. }
  377. }
  378. }
  379. }
  380. close STREAM;
  381. }
  382. print "Proceed indexes: [";
  383. foreach (@config_sources) {
  384. my ($uri, $distribution, @components) = @{$_};
  385. print "S";
  386. if(@components) {
  387. my $component;
  388. foreach $component (@components) {
  389. proceed_index_gz($uri, "/dists/$distribution/$component/source/Sources.gz");
  390. }
  391. } else {
  392. proceed_index_gz($uri, "/$distribution/Sources.gz");
  393. }
  394. }
  395. foreach (@config_binaries) {
  396. my ($arch, $uri, $distribution, @components) = @{$_};
  397. print "P";
  398. if(@components) {
  399. my $component;
  400. foreach $component (@components) {
  401. proceed_index_gz($uri, "/dists/$distribution/$component/binary-$arch/Packages.gz");
  402. }
  403. } else {
  404. proceed_index_gz($uri, "/$distribution/Packages.gz");
  405. }
  406. }
  407. clear_stat_cache();
  408. print "]\n\n";
  409. close FILES_ALL;
  410. close FILES_NEW;
  411. close FILES_MD5;
  412. ######################################################################################
  413. ## Main download
  414. chdir get_variable("mirror_path") or die("apt-mirror: can't chdir to mirror");
  415. my $need_bytes = 0;
  416. foreach (values %urls_to_download) {
  417. $need_bytes += $_;
  418. }
  419. my $size_output = format_bytes($need_bytes);
  420. print "$size_output will be downloaded into archive.\n";
  421. download_urls("archive", sort keys %urls_to_download);
  422. ######################################################################################
  423. ## Copy skel to main archive
  424. sub copy_file {
  425. my ($from, $to) = @_;
  426. my $dir = dirname($to);
  427. return unless -f $from;
  428. mkpath($dir) unless -d $dir;
  429. unless(copy($from, $to)) {
  430. warn("apt-mirror: can't copy $from to $to");
  431. return;
  432. }
  433. my ($atime,$mtime) = ( stat($from) ) [8, 9];
  434. utime($atime, $mtime, $to) or die("apt-mirror: can't utime $to");
  435. }
  436. foreach (@index_urls) {
  437. die("apt-mirror: invalid url in index_urls") unless s[^(\w+)://][];
  438. copy_file(get_variable("skel_path") . "/" . sanitise_uri("$_"), get_variable("mirror_path") . "/" . sanitise_uri("$_"));
  439. copy_file(get_variable("skel_path") . "/" . sanitise_uri("$_"), get_variable("mirror_path") . "/" . sanitise_uri("$_")) if(s/\.gz$//);
  440. copy_file(get_variable("skel_path") . "/" . sanitise_uri("$_"), get_variable("mirror_path") . "/" . sanitise_uri("$_")) if(s/\.bz2$//);
  441. }
  442. ######################################################################################
  443. ## Make cleaning script
  444. my (@rm_dirs, @rm_files) = ();
  445. my $unnecessary_bytes = 0;
  446. sub process_symlink {
  447. return 1; # symlinks are always needed
  448. }
  449. sub process_file {
  450. my $file = shift;
  451. $file =~ s[~][%7E]g if get_variable("_tilde");
  452. return 1 if $skipclean{$file};
  453. push @rm_files, sanitise_uri($file);
  454. my (undef, undef, undef, undef, undef, undef, undef, $size, undef, undef, undef, undef, $blocks) = stat($file);
  455. $unnecessary_bytes += $blocks * 512;
  456. return 0;
  457. }
  458. sub process_directory {
  459. my $dir = shift;
  460. my $is_needed = 0;
  461. return 1 if $skipclean{$dir};
  462. opendir(my $dir_h, $dir) or die "apt-mirror: can't opendir $dir: $!";
  463. foreach (grep { !/^\.$/ && !/^\.\.$/ } readdir($dir_h)) {
  464. my $item = $dir . "/". $_;
  465. $is_needed |= process_directory($item) if -d $item && ! -l $item;
  466. $is_needed |= process_file($item) if -f $item;
  467. $is_needed |= process_symlink($item) if -l $item;
  468. }
  469. closedir $dir_h;
  470. push @rm_dirs, $dir unless $is_needed;
  471. return $is_needed;
  472. }
  473. chdir get_variable("mirror_path") or die("apt-mirror: can't chdir to mirror");
  474. foreach (keys %clean_directory) {
  475. process_directory($_) if -d $_ && ! -l $_;
  476. }
  477. open CLEAN, ">" . get_variable("cleanscript") or die("apt-mirror: can't open clean script file");
  478. my ($i, $total) = (0, scalar @rm_files);
  479. if(get_variable("_autoclean")) {
  480. my $size_output = format_bytes($unnecessary_bytes);
  481. print "$size_output in $total files and " . scalar(@rm_dirs) . " directories will be freed...";
  482. chdir get_variable("mirror_path") or die("apt-mirror: can't chdir to mirror");
  483. foreach (@rm_files) { unlink $_; }
  484. foreach (@rm_dirs) { rmdir $_; }
  485. } else {
  486. my $size_output = format_bytes($unnecessary_bytes);
  487. print "$size_output in $total files and " . scalar(@rm_dirs) . " directories can be freed.\n";
  488. print "Run " . get_variable("cleanscript") . " for this purpose.\n\n";
  489. print CLEAN "cd " . get_variable("mirror_path") . " || exit 1\n\n";
  490. print CLEAN "echo 'Removing $total unnecessary files [$unnecessary_bytes bytes]...'\n";
  491. foreach (@rm_files) {
  492. print CLEAN "rm -f '$_'\n";
  493. print CLEAN "echo -n '[" . int(100 * $i/$total) . "\%]'\n" unless $i % 500;
  494. print CLEAN "echo -n .\n" unless $i % 10;
  495. $i ++;
  496. }
  497. print CLEAN "echo 'done.'\n";
  498. print CLEAN "echo\n\n";
  499. $i = 0; $total = scalar @rm_dirs;
  500. print CLEAN "echo 'Removing $total unnecessary directories...'\n";
  501. foreach (@rm_dirs) {
  502. print CLEAN "rmdir '$_'\n";
  503. print CLEAN "echo -n '[" . int(100 * $i/$total) . "\%]'\n" unless $i % 50;
  504. print CLEAN "echo -n .\n";
  505. $i ++;
  506. }
  507. print CLEAN "echo 'done.'\n";
  508. print CLEAN "echo\n";
  509. close CLEAN;
  510. }
  511. if(get_variable("run_postmirror")) {
  512. print "Running the Post Mirror script ...\n";
  513. print "(" . get_variable("postmirror_script") . ")\n\n";
  514. if(-x get_variable("postmirror_script")){
  515. system (get_variable("postmirror_script"));
  516. } else {
  517. system ('/bin/sh ' . get_variable("postmirror_script"));
  518. }
  519. print "\nPost Mirror script has completed. See above output for any possible errors.\n\n";
  520. }
  521. unlock_aptmirror();


viewable in any browser valid css valid html 4.01 powered by lighttpd colored by colorer written in perl hosted by stavcom