summaryrefslogtreecommitdiff
path: root/bin/byteback-receive
blob: 8cdb6ee16e95c863eecac66b02d040c8431a6070 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/ruby
# encoding: UTF-8
#
# Program to receive backups and run rsync in receive mode.  Must check that
# user as authorised by SSH is allowed to access particular directory.

$LOAD_PATH << '/usr/lib/byteback'

require 'trollop'
require 'byteback'
require 'byteback/restore'

include Byteback::Log

if ENV['SSH_ORIGINAL_COMMAND']
  ARGV.concat(ENV['SSH_ORIGINAL_COMMAND'].split(' '))
end

byteback_host = ENV['BYTEBACK_HOST']
fatal('BYTEBACK_HOST environment not set') unless byteback_host

byteback_root = ENV['HOME'] + '/' + ENV['BYTEBACK_HOST']
fatal("#{byteback_root} does not exist") unless File.directory?(byteback_root)

#
# Calling byteback-restore really needs rsync to restore the files.
#
if ARGV[0] == 'byteback-restore'
  #
  # Ignore the first arg
  #
  ARGV.shift

  args = ['rsync']
  snapshot = nil
  verbose = false
  all = false

  #
  # Mangle the arguments, and pull out any that are not-rsync compatible.
  #
  while (arg = ARGV.shift)
    case arg
    when '.'
      break
    when /^-([^-]*v[^-]*|-verbose)$/
      verbose = true
      args << arg
    when '--snapshot'
      snapshot = ARGV.shift
    when '--all'
      all = true
    else
      args << arg
    end
  end

  # Always exclude the current directory, because it can change the
  # ownership at the restorers end.
  args << '--exclude=.'

  #
  # Search for certain files
  # DANGER the args might be too long if lots of files are returned.
  #
  paths = Byteback::Restore.decode_args(ARGV)

  restore = Byteback::Restore.new(byteback_root)
  restore.snapshot = snapshot if snapshot
  restore.find(paths, all: all)

  Dir.chdir(byteback_host)

  args << '.'

  restore.results.each do |r|
    args << File.join('.', r.snapshot, r.path)
  end

  if restore.results.empty?
    STDERR.puts '** Sorry.  There were no files matching:'
    STDERR.puts '--> ' + paths.join("\n--> ")
    exit 1
  end

  STDERR.puts 'Restoring:'
  STDERR.puts restore.list
  STDERR.puts(args.join(' ')) if verbose

  exec(*args)

elsif ARGV[0] == 'rsync'
  ARGV[-1] = "#{byteback_root}/current"
  exec(*ARGV)

elsif ARGV[0] == 'byteback-snapshot'
  ARGV.concat(['--root', byteback_root.to_s])
  exec(*ARGV)

elsif ARGV[0] == 'restore'
  puts '** Your byteback package needs to be updated.  Please update and try again.'
  exit(1)

end

opts = Trollop.options do
  opt :ping, 'Check connection parameters and exit'
  opt :complete, 'Mark current backup as complete'
  opt :list, 'Show backed up files matching the given pattern'
  opt :all,  'Show all stored versions of a file'
  opt :snapshot, 'Show backed up files in a certain snapshot.', default: '*'
  opt :verbose, 'Print diagnostics'
end

#
# Make sure we don't get crazy option combinations.
#
n_modes = opts.keys.inject(0) do |s, m|
  [:ping, :complete, :list].include?(m) ? s += 1 : s
end

error('Please only choose one mode') unless n_modes == 1

if opts[:complete]
  system('byteback-snapshot', '--root', byteback_root)

elsif opts[:list]
  args = Byteback::Restore.decode_args(ARGV[1..-1])

  restore = Byteback::Restore.new(byteback_root)
  restore.snapshot = opts[:snapshot]
  restore.find(args, all: opts[:all], verbose: opts[:verbose])

  if restore.results.empty?
    puts '** Sorry.  There were no files matching:'
    puts '--> ' + args.join("\n--> ")
  else
    puts restore.list
  end

  exit(0)

elsif opts[:ping]
  exit 0

else
  STDERR.print "byteback-receive failed\n"
  exit 9

end