#!/usr/bin/env tclsh
# snapshot - use rsync to rsync a snapshot of a directory to a remote machine
# via rsync and ssh.
#
# Usage: snapshot directory [interval]
# where interval is: one of hourly, daily, weekly, monthly
#
source ssh.tcl
package require ssh
# account@machine to run the remote
set remote user@machine
# location on remote to store snapshots
set root /var/backup
# schedule of snapshots - how many for each category
array set schedule {
hourly 24
daily 7
weekly 4
monthly 3
}
if {[info exists argv0] && ($argv0 == [info script])} {
if {[llength $argv] < 2} {
puts stderr "Usage: [info script] <interval> <directory>\nwhere interval is: one of hourly, daily, weekly, monthly"
exit 1
}
set interval [lindex $argv 0]
connect $remote
# send remote our globals
remotes [subst {
array set schedule [list [array get schedule]]
set root [file normalize $root]
array get schedule
}]
# rotate according to schedule
remote {
proc rotate {interval} {
global schedule
global root
if {![file exists $root]} {
file mkdir $root
}
set stem [file join $root $interval]
if {![file exists ${stem}.0]} {
# brand new
file mkdir ${stem}.0
return
}
# delete oldest snapshots
if {[file exists $stem.$schedule($interval)]} {
file delete -force $stem.$schedule($interval)
}
# age snapshot names
for {set i $schedule($interval)} {$i > 0} {incr i -1} {
if {[file exists $stem.$i]} {
file rename $stem.$i $stem.[expr {$i + 1}]
}
}
# age/link files from most recent snapshot to .1
exec /bin/cp -al $stem.0/ $stem.1/
}
}
remote "rotate $interval" ;# first rotate this interval's snapshot
remote exit ;# clean up the rotation
set stem [file join $root $interval]
# rsync the local dirs to the appropriate snapshot
foreach dir [lrange $argv 1 end] {
set dir [file normalize $dir]
set dest [file join ${stem}.0 [string map {/ @} $dir]]/
exec sudo /usr/bin/rsync -a -P -S -z --delete --numeric-ids ${dir}/ ${remote}:${dest} >@stdout 2>@stderr
}
}.tclshrc in remote user's home directory.
# This goes into the remote user's home directory. Note the sudo
if {[info exists argv]} {
if {[lindex $argv 0] == "-c"} {
fconfigure stdin -buffering none -encoding binary -translation {binary binary}
fconfigure stdout -buffering none -encoding binary -translation {binary binary}
eval exec sudo [lindex $argv 1] >@stdout <@stdin 2>/tmp/snapshot.err
exit
}
}mzgcoco: My simple backup tool on windows platform Tackup

