#!/usr/bin/perl -s if($help) { print << "EOF"; Usage: $0 [options] Options: -help This message -passive Passive mode. Do not use. -delorphan Remove orphaned files from local -delremoteorphan Remove orphaned files from remote -nosync Report changed files only, don't synchronize -latersync Report changed files only, don't synchronize. Also prints 'upload' commands for use by 'at' -confirmsync Confirm before performing synchronize -forceupload Force all differences to favor the local copy -forcedownload Force all differences to favor the remote copy EOF exit(0); } @exclude = ( ); $| = 1; $SIG{PIPE}=__WARN__; ($hostname = `uname -n`) =~ s|([^\.]*)\..*|$1|; chomp $hostname; if($hostname eq "#####") { $logfile = "/home/cms/synchronize.debug"; $localpath = "/home/cms/###############/site/"; $remotepath = "/www/###############/"; $binpath = "/home/cms/bin"; $sshargs = ""; $sshargs .= " -delorphan" if $delremoteorphan && !$nosync; $sshargs .= " -forcedownload" if $forceupload; $sshargs .= " -forceupload" if $forcedownload; $ssh = "ssh -i /home/cms/.ssh/identity -l ##### ############### '~/bin/synchronize.pl -passive $sshargs'"; $scp = "scp -pqC -i /home/cms/.ssh/identity"; &echo("Updating remote software...\n"); if(system "scp -i /home/cms/.ssh/identity $binpath/synchronize.pl #####\@###############:~/bin") { print "Update failed!\n"; } } elsif($hostname eq "##") { $logfile = "/home/#####/synchronize.debug"; $localpath = "/www/###############/"; $remotepath = "/home/cms/###############/site/"; $binpath = "/home/#####/bin"; if(!$passive) { die "Can not initiate connection from here."; } } else { die "I can only be run from ##### or ##! This appears to be $hostname!"; } #open(D,">$logfile"); chdir ($localpath); @give = (); @take = (); %checked=(); %changed=(); &echo("started\n"); if($passive) { &passive(); } else { &open_remote(); if(&myrecv ne "+Ready\n") { die "Remote not ready."; } else { &echo("Remote ready.\n"); } &do_dir(""); &mysend("DONE\n"); &passive(); &close_remote(); $sep = ", ";$sep="\t"; #&echo("Changed: " . join(", ", (sort keys %changed)) . "\n"); &echo("Files to download: " . join($sep, @take) . "\n"); &echo("Files to upload: " . join($sep, @give) . "\n"); if($latersync) { foreach $file (@give) { print "upload $localpath$file\n"; } } exit(0) if $nosync || $latersync; if((@take || @give) && $confirmsync) { $yesno=""; while($yesno ne "yes" && $yesno ne "no") { print "Do you wish to sync these files [yes/no]? "; $yesno = <>; chomp $yesno; last if($yesno eq "yes"); exit(0) if ($yesno eq "no"); } } chdir ($localpath); if(@take) { $args = join(" ", @take); &echo("ssh -i /home/cms/.ssh/identity -l ##### ############### 'cd $remotepath;tar -cpf - $args'|\n"); open(TARIN, "ssh -i /home/cms/.ssh/identity -l ##### ############### 'cd $remotepath;tar -cpf - $args'|") or die "Can't open SSH tunnel for tar: $!"; open(TAROUT, ">/tmp/syncfiles.tar"); while() { print TAROUT $_; } close TARIN; close TAROUT; &echo("Extracting remote tarball...\n"); system("tar -xpvf /tmp/syncfiles.tar"); &echo("Done\n"); unlink "/tmp/syncfiles.tar"; } if(@give) { $args = join(" ", @give); &echo("Creating local tarball...\n"); system("tar -cpvf /tmp/syncfiles.tar $args"); &echo("Done\n"); &echo("|ssh -i /home/cms/.ssh/identity -l ##### ############### 'cd $remotepath;tar -xpvf -'\n"); open(TAROUT, "|ssh -i /home/cms/.ssh/identity -l ##### ############### 'cd $remotepath;tar -xpvf -'") or die "Can't open SSH tunnel for tar: $!"; open(TARIN, ") { print TAROUT $_; } close TARIN; close TAROUT; unlink "/tmp/syncfiles.tar"; } } &echo("ended\n"); #close D; exit(0); sub mysend { if($passive) { print @_; } else { print TOKID @_; } # print D "$$ SEND: @_"; } sub myrecv { local($r); if($passive) { $r = <>; } else { $r = ; } # print D "$$ RECV: $r"; return $r; } sub echo { if(!$passive) { print @_; } # print D "$$ @_"; } sub open_remote { pipe(FROMKID, TOPARENT); pipe(FROMPARENT, TOKID); $pid = fork; die "Failed to fork: $!" unless defined $pid; if($pid == 0) { close TOKID; close FROMKID; open(STDIN, "<&FROMPARENT"); open(STDOUT, ">&TOPARENT"); exec $ssh or die "Can't exec: $!"; } else { close TOPARENT; close FROMPARENT; select TOKID; $|=1; select FROMKID; $|=1; select STDOUT; } } sub close_remote { &mysend("QUIT\n"); close TOKID; waitpid($pid, 0); } sub do_dir { local($dir) = @_; foreach $exclude (@exclude) { if($dir =~ m|$exclude|) { &echo("Skipping '$dir'\n"); return; } } opendir(D, $dir||"."); &echo(" $dir\n"); local(@fs) = (); while($f = readdir(D)) { next if $f =~ m|^\.+$| ; @fs = (@fs, $f); } closedir(D); @fs = sort @fs; while($f = shift @fs) { if( -d $dir . $f . "/" ) { &do_dir($dir . $f . "/"); } else { &do_file($dir, $f); } } } sub do_file { local($dir, $file) = @_; return if $checked{$dir.$file}; $dirfile = $dir.$file; foreach $exclude (@exclude) { if($dirfile =~ m|$exclude|) { &echo("Skipping '$dirfile'\n"); return; } } $checked{$dir.$file}++; local(@lst) = stat($dir . $file); &mysend("STAT $dir$file\n"); chomp($l = &myrecv); if($l =~ m|^-| ) { if($delorphan) { &echo("unlink $dir$file\n"); unlink $dir.$file; } elsif($passive) { &mysend("TAKE $dir$file\n"); $changed{$dir.$file}++; } else { &echo("-> $dir$file\n"); @give = (@give, $dir.$file); $changed{$dir.$file}++; } } else { $l =~ m|\[ (.*) \]|; local(@rst) = split(" ", $1); if($rst[0] ne $lst[7] || $rst[1] ne $lst[9]) { if($passive) { if(!$forceupload && ($forcedownload || $lst[9] < $rst[9])) { &mysend("GIVE $dir$file\n"); $changed{$dir.$file}++; } else { &mysend("TAKE $dir$file\n"); $changed{$dir.$file}++; } } else { if(!$forceupload && ($forcedownload || $lst[9] < $rst[9])) { &echo("<- $dir$file\n"); @take = (@take, $dir.$file); $changed{$dir.$file}++; } else { &echo("-> $dir$file\n"); @give = (@give, $dir.$file); $changed{$dir.$file}++; } } } } } sub passive { &mysend("+Ready\n"); select D; $|=1;select STDOUT; while($_ = &myrecv) { chomp; m|^([^ ]+) ?(.*)$|; ($command, $args) = ($1, $2); if($command eq "STAT") { $checked{$args}++; if (local(@st) = stat($localpath . $args)) { &mysend("$args [ $st[7] $st[9] ]\n"); } else { &mysend("-Not Found\n"); } } elsif($command eq "GIVE") { if(defined $scp) { &echo("-> $args\n"); @give = (@give, $args); $changed{$args}++; } else { &mysend("-Can not perform SCP from this side.\n") } } elsif($command eq "TAKE") { if(defined $scp) { &echo("<- $args\n"); @take = (@take, $args); $changed{$args}++; } else { &mysend("-Can not perform SCP from this side.\n") } } last if($command eq "QUIT" || $command eq "DONE"); } return unless $passive; if($command eq "DONE") { if(&myrecv ne "+Ready\n") { die "Remote not ready."; } else { &echo("Remote ready.\n"); } &do_dir(""); &mysend("DONE\n"); } else { &mysend("-Bye\n"); } }