dir syncing script

Kevin Buettner kev@primenet.com
Mon, 25 Sep 2000 10:53:32 -0700


Below is the directory syncing script that I use to keep my sources
synchronized between my local machine and a remote machine.  In order
to use it, you'll need to do at least two things:

 1) Set REMOTE_SRC, LOCAL_SRC, and RSYNC_PATH to values appropriate
    for your situation.

    REMOTE_SRC should be of the form HostName:Path, where ``HostName''
    is the name of the remote machine that you're syncing with and
    ``Path'' is the path (on the remote machine) to the directory
    being sync'd.

    LOCAL_SRC should be a pathname to a directory accessible via your
    local machine.  (Note that Samba or NFS mounts are okay.)

    RSYNC_PATH should be the complete path to the rsync program on the
    remote machine.  (On some of the machines I use, rsync is either
    located in a definitely non-standard place or else is so out of
    date that I've built my own version and installed it in ~/bin.)

 2) Name it something appropriate, make sure it's executable, and
    place it in a directory on your PATH.

    E.g, I have one called sync-sourceware which syncs my checked-out
    gdb sources from sourceware.cygnus.com with these same sources
    on one of the remote machines that I frequently use in Sunnyvale.

    I have other scripts which sync between my laptop and my desktop
    machines at home, etc.  The only difference between these scripts
    is the settings of the three variables mentioned in (1) above.

It uses SSH as a secure transport.  Since (at least) two rsyncs are
done, this would normally require entering your passphrase as many
times as rsync is invoked.  In order to avoid bothering the user to
enter passphrase after passphrase, it attempts to use an existing
ssh-agent.  If none exists, it will create an agent and then invoke
ssh-add which prompts you for your passphrase.  Thus, you'll be
prompted for the passphrase which unlocks your RSA key at most once.

--- sync-sources ---
#!/usr/bin/perl -w

$REMOTE_SRC = "remote.host.com:/path/to/remote/sources";
$LOCAL_SRC = "/path/to/local/sources";
$RSYNC_PATH = "/path/to/remote/rsync";

$ENV{RSYNC_RSH} = 'ssh';

my $nuke_agent = 0;

if (!$ENV{SSH_AGENT_PID}) {
    my $agentdata = `ssh-agent -s`;
    die "Problem starting ssh-agent"	if (!defined($agentdata));
    my ($agent_pid)  = $agentdata =~ /^SSH_AGENT_PID=([^;]*);/m;
    my ($agent_sock) = $agentdata =~ /^SSH_AUTH_SOCK=([^;]*);/m;
    die "Can't fetch ssh agent environment variables"
					unless defined($agent_pid)
					    && defined($agent_sock);

    print "agent_pid=$agent_pid; agent_sock=$agent_sock\n";
    $ENV{SSH_AGENT_PID} = $agent_pid;
    $ENV{SSH_AUTH_SOCK} = $agent_sock;

    system("ssh-add");
    sleep(4);
    $nuke_agent = 1;
}

if (@ARGV) {
    foreach $arg (@ARGV) {
	sync_dir("$REMOTE_SRC/$arg", "$LOCAL_SRC/$arg");
    }
}
else {
    sync_dir($REMOTE_SRC, $LOCAL_SRC);
}
system("ssh-agent -k")			if $nuke_agent;

sub sync_dir {
    my ($remote_src, $local_src) = @_;
    my $remote_dir = $remote_src;
    $remote_dir =~ s#/[^/]*$##;
    my $local_dir = $local_src;
    $local_dir =~ s#/[^/]*$##;
    system("rsync -avuz --exclude '*~' --rsync-path=$RSYNC_PATH $remote_src $local_dir");
    system("rsync -Cavuz --exclude '*~' --rsync-path=$RSYNC_PATH $local_src $remote_dir");
}
--- end sync-sources ---