#!/bin/sh exec perl -wx -- "$0" "$@" #!perl # vim: filetype=perl : use strict qw($debug); $debug = 0; if (@ARGV and $ARGV[0] eq "-h") { print STDERR "Bedienung:\n", "Wechseln Sie in das gewünschte lokale Verzeichnis: \n", "% cd /mein/daten/verzeichnis\n\n", "Führen Sie aus: sync-ftp RECHNERNAME WURZELVERZEICHNIS_AUF_DEM_SERVER\n", "% sync-ftp www.dr-rohlfs.de /pub\n"; exit; } ## auf default-sprache setzen, de_de gibt anderes datumsformat! $ENV{LANG}= "C"; ################################################################################ # ftp-verbindung aufmachen ################################################################################ use Net::FTP; my $ftp; { ## parameter bestimmen my $REMOTE_HOST = shift; $REMOTE_HOST ||= "dr-rohlfs.de"; my $REMOTE_DIR = shift; ## einloggen auf dem rechner $ftp = Net::FTP->new($REMOTE_HOST) or die "Cannot connect to $REMOTE_HOST: $@"; ## logindaten bestimmen my $USERNAME = ""; my $PASSWD = ""; if (open inF, "<$ENV{HOME}/.netrc") { while () { ($USERNAME, $PASSWD) = (/login\s+(\S+)\spassword\s+(\S+)/i) if /machine\s+$REMOTE_HOST/io; } close inF; ##print "$USERNAME $PASSWD\n"; exit; } else { warn "kein .netrc!\n" } $ftp->login($USERNAME, $PASSWD) or die "Cannot login"; if (defined $REMOTE_DIR) { $ftp->cwd($REMOTE_DIR) or die "cant chdir $REMOTE_DIR" } $ftp->binary or die "no binary mode?"; } ## wurzelverzeichnis fuer unsere operation bestimmenwurzelverzeichnis fuer unsere operation bestimmen my $ftp_rootdir = $ftp->pwd or die "cant pwd"; ################################################################################ # dateiinformationen vom ftp-server und lokal anfordern ################################################################################ #{ local $, = "\n"; print ($ftp->ls("-lR")); } exit; #open lsP, "cat /home/ingo/ls-R|" or die "fehler bei ls: $!"; #my ($f_file) = ls2hash (grep !/\.log$/, ); my ($f_file) = ls2hash (grep !/\.log$/, $ftp->ls("-alLR")); ## list-long ohne log-dateien, -a muss sein, sonst gibt .pl aerger! ## aber mit .pl als zentrale datei! #open lsP, "ls -lRL . .pl|" or die "fehler bei ls: $!"; open lsP, "ls -alRL|" or die "fehler bei ls: $!"; my ($l_file) = ls2hash (grep !/\.log$/, ); close lsP; ################################################################################ # abgleich der listen ################################################################################ for (keys %$l_file) { if (exists $$f_file{$_}) { my @f = @{$$f_file{$_}}; my @l = @{$$l_file{$_}}; ## wenn auf beiden rechnern, nicht entfernt loeschen!! delete $$f_file{$_}; if ($f[2] eq "d" # immer loeschen, wenn ein verzeichnis! or ( $f[0] == $l[0] # dateien loeschen, wenn gleiche groesse and ls2time($f[1]) > ls2time($l[1]) - 3600 )) { delete $$l_file{$_}; } } } ################################################################################ # ausgeben der daten ################################################################################ if ($debug > 1) { print "* l_file:\n"; for (sort keys %$l_file) { print $_, "\t--", $$l_file{$_}[1], "---", $$l_file{$_}[0], "--\n"; } print "* f_file:\n"; for (sort keys %$f_file) { print $_, "\t--", $$f_file{$_}[1], "---", $$f_file{$_}[0], "--\n"; } exit; } ################################################################################ # dateien/verzeichnisse uebertragen ################################################################################ for (sort keys %$l_file) { # sort => dirs kommen zuerst if ($$l_file{$_}[2] eq "d") { print STDERR "mkdir $ftp_rootdir/$_: "; $ftp->mkdir("$ftp_rootdir/$_", 1) or die "FEHLER: ", $ftp->message(); } else { print STDERR "put $_ $ftp_rootdir/$_: "; $ftp->put($_, "$ftp_rootdir/$_") or die "FEHLER: ", $ftp->message(); } print STDERR " ok\n"; } ################################################################################ # dateien/verzeichnisse loeschen ################################################################################ $ftp->quit(), exit unless keys %$f_file; { local $, = "\n"; print "**folgende Dateien loeschen j/n?", reverse sort keys %$f_file, "\n"; exit unless =~ /^[jy]/; } for (reverse sort keys %$f_file) { # reverse => dirs kommen nach den dateien if ($$f_file{$_}[2] eq "d") { print STDERR "rmdir $ftp_rootdir/$_: "; $ftp->rmdir("$ftp_rootdir/$_") or warn "FEHLER: ", $ftp->message(); ## fehlermeldung auch bei erfolg :-( } else { print STDERR "del $ftp_rootdir/$_: "; $ftp->delete("$ftp_rootdir/$_") or die "FEHLER: ", $ftp->message(); } print STDERR " ok\n"; } $ftp->quit; ################################################################################ exit; ################################################################################ ################################################################################ use Time::Local; ################################################################################ # wandelt zeichenkette von ls für die dateizeit in epochensekunden um ################################################################################ sub ls2time { die "ls2time braucht genau ein argument! @_\n" unless 1 == @_; my %mon = ( "Jan" => 0, "Feb" => 1, "Mär" => 2, "Mar" => 2, "Apr" => 3, "Mai" => 4, "May" => 4, "Jun" => 5, "Jul" => 6, "Aug" => 7, "Sep" => 8, "Okt" => 9, "Oct" => 9, "Nov" => 10, "Dez" => 11, "Dec" => 11 ); my @in = split /\s+/, $_[0]; my @t = qw(0 0 0 0 0 0); # monatsnummer bestimmen $t[4] = $mon{$in[0]}; die "monat nicht definiert $_[0]\n" unless defined $t[4]; # tag des monats $t[3] = $in[1]; # die uhrzeit oder das jahr setzten if ($in[2] =~ /:/) { # uhrzeit @t[1..2] = reverse $in[2] =~ /(\d+):(\d+)/; $t[5] = (localtime)[5]; $t[5]-- if timelocal(@t) > time; } else { # jahr $t[5] = $in[2] - 1900; } # rueckgabe als feld oder skalar #if (wantarray) { return @t } else { return timelocal(@t); #} } ################################################################################ ## spaltet die ausgabe von ls in eine datenstruktur ################################################################################ sub ls2hash { my %file; my $dir = ""; if ($debug) { open debugF, ">>/tmp/sync-ftp.debug" or die "/tmp/sync-ftp.debug: $!" } ## alle zeilen einzeln durchgehen while (defined (my $l = shift)) { print debugF "$l\n" if $debug; chomp ($l); $dir = "", next if $l =~ /^\s*$/; next if $l =~ /^(total|insgesamt)\s+\d+\s*$/; # zeile mit "total" loeschen ## verzeichnisnamen extrahieren if ($l =~ /:\s*$/) { ($dir) = $l =~ /^(.*):\s*$/; die "kein verz-name $l" unless defined $dir; $dir .= "/"; next; } my $typ; warn ("keine datei: $l\n"), next unless ($typ) = $l =~ /^([-d])/; ## werte im hash speichern $l = (split /\s+/, $l, 5)[-1]; my $n = (my ($groesse, $datum, $fileN) = $l =~ /^(\d+)\s+(.{12})\s+(.*)/); if (3 != $n) { warn "cannot parse ($n): $l\n"; next; } next if $fileN =~ /^\.*$/; # . und .. schlecht! $fileN = "$dir$fileN"; $fileN =~ s/^\.\///; # normalisieren: ./ am anfang weg #$fileN =~ s/^\///; # normalisieren: / am anfang weg $file{$fileN} = [ $groesse, $datum, $typ ]; } return \%file; }