diff options
Diffstat (limited to 'bin/byteback-restore')
-rwxr-xr-x | bin/byteback-restore | 193 |
1 files changed, 122 insertions, 71 deletions
diff --git a/bin/byteback-restore b/bin/byteback-restore index 7ac47dd..0a068a8 100755 --- a/bin/byteback-restore +++ b/bin/byteback-restore @@ -1,19 +1,19 @@ #!/usr/bin/ruby +# enocoding: UTF-8 # # Restore a file from the most recent backup, from the remote host. # $LOAD_PATH.unshift('/usr/lib/byteback') -$LOAD_PATH.unshift('./lib/') +$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../lib')) # For development require 'trollop' require 'byteback/util' require 'byteback/log' +require 'byteback/restore' include Byteback::Util include Byteback::Log - - # # Run a remote command. # @@ -31,11 +31,16 @@ def ssh(*ssh_args) ] + ssh_args.map { |a| a ? a : '' } + puts args.join(" " ) if @verbose system(*args) end -def list_files(pattern) - ssh('byteback-receive', '--list', pattern) +def list_files(revision, list_all, pattern) + args = ['byteback-receive', '--revision', revision, '--list'] + args << "--list-all" if list_all + args << @verbose if @verbose + args += Byteback::Restore.encode_args(pattern) + ssh(*args) end # @@ -46,77 +51,123 @@ end # do that by setting "rsync-path" to point to a faux script. # # -def restore_file(path, revision) - cmd = %w( rsync ) - cmd += ['--rsh', 'ssh -o BatchMode=yes -x -a -i /etc/byteback/key -l byteback'] - cmd += ['--rsync-path', 'restore --fake-super'] - cmd += ['-aApzrX', '--numeric-ids'] - cmd += ["#{@destination_host}:/#{revision}/#{path}", '.'] - system(*cmd) -end - -# -# Parse our command-line arguments -# -opts = Trollop.options do - banner "byteback-restore: Restore a file\n " - - opt :file, 'The file to restore/list.', - :type => :string +def restore_files(paths, revision) - opt :revision, "The version of the file to restore.", - :type => :string - - opt :destination, 'Backup destination (i.e. user@host:/path).', - :type => :string - - opt :ssh_key, 'SSH key filename', - :type => :string, - :default => '/etc/byteback/key', - :short => 'k' -end - -# -# Setup default destination and key. -# -@destination = File.read('/etc/byteback/destination').chomp if - File.exist?('/etc/byteback/destination') -@ssh_key = '/etc/byteback/key' if File.exist?('/etc/byteback/key') + # + # Basic args + # + args = %w(rsync --archive --acls --numeric-ids --inplace --relative --xattrs --compress --no-implied-dirs) -# -# Allow the command-line to override them. -# -@ssh_key = opts[:ssh_key] unless opts[:ssh_key].nil? -@destination = opts[:destination] unless opts[:destination].nil? + # + # Add on the I/O-timeout + # + args += ['--timeout', @io_timeout.to_s ] unless ( @io_timeout.nil? ) + args += ['--rsh', "ssh -o BatchMode=yes -x -a -i #{@ssh_key} -l #{@destination_user}"] + args << '--verbose' if @verbose + args += ['--rsync-path', "byteback-restore --fake-super --revision #{revision}"] + dst = "#{@destination_user}@#{@destination_host}:" -# -# Check our destination is well-formed -# -if @destination =~ /^(?:(.+)@)?([^@:]+):(.+)?$/ - @destination_user, @destination_host, @destination_path = [Regexp.last_match(1), Regexp.last_match(2), Regexp.last_match(3)] -else - fatal('Destination must be a remote path, e.g. ssh@host.com:/store/backups') -end + paths.each do |path| + path = Byteback::Restore.encode_args(path).first + args << File.join(dst,path) + dst = ":" + end -# -# If the user didn't specify a file then we're not restoring anything, -# and we should abort. -# -if opts[:file].nil? - fatal('You must specify a file to search/restore') + args << "." + puts args.join(" " ) if @verbose + system(*args) end -# -# If the user specified a file, but not a revision, then we list -# the available revisions. -# -if opts[:revision].nil? - list_files(opts[:file]) +## +## Entry-point to our code. +## +if __FILE__ == $PROGRAM_NAME + + ME = File.basename($PROGRAM_NAME) + + # + # Parse our command-line arguments + # + opts = Trollop.options do + banner "#{ME}: Restore a file to this system from a byteback-enabled server\n " + + opt :restore, "Restore the files" + + opt :revision, "The version of the file to restore.", + :type => :string, :default => "*" + + opt :destination, 'Backup destination (i.e. user@host:/path).', + :type => :string + + opt :verbose, 'Show debugging messages' + + opt :io_timeout, 'Number of seconds to allow I/O timeout for', + :type => :integer, + :default => 10800 + + opt :ssh_key, 'SSH key filename', + :type => :string, + :default => '/etc/byteback/key', + :short => 'k' + + opt :list_all, 'List all versrions of each file' + + end + + @verbose = opts[:verbose] ? '--verbose' : nil + @io_timeout = opts[:io_timeout] if opts[:io_timeout] + + # Read the default destination + if File.exist?('/etc/byteback/destination') + @destination = File.read('/etc/byteback/destination').chomp + end + + # Set the default SSH key + if File.exist?('/etc/byteback/key') + @ssh_key = '/etc/byteback/key' + end + + # + # Allow the command-line to override them. + # + @ssh_key = opts[:ssh_key] unless opts[:ssh_key].nil? + @destination = opts[:destination] unless opts[:destination].nil? + + # + # Check our destination + # + fatal('Must suply --destination or put it into /etc/bytebackup/destination') unless @destination + + # + # Check our destination is well-formed + # + if @destination =~ /^(?:(.+)@)?([^@:]+):(.+)?$/ + @destination_user, @destination_host, @destination_path = [Regexp.last_match(1), Regexp.last_match(2), Regexp.last_match(3)] + else + fatal('Destination must be a remote path, e.g. ssh@host.com:/store/backups') + end + + # + # Test that we have an SSH-key which we can read. + # + fatal("Could not read ssh key #{@ssh_key}") unless File.readable?(@ssh_key) + + # + # If the user didn't specify a file then we're not restoring anything, + # and we should abort. + # + if ARGV.empty? + fatal('You must specify a file to search/restore') + end + + if opts[:restore] + # + # Restore a file + # + restore_files(ARGV.collect{|a| File.expand_path(a)}, opts[:revision]) + exit(0) + end + + list_files(opts[:revision], opts[:list_all], ARGV.collect{|a| File.expand_path(a)}) exit(0) end - -# -# Restore a file -# -restore_file(opts[:file], opts[:revision]) -exit(0) |