#!/usr/bin/env ruby ENV['TMPDIR']='/tmp/backup/' require 'optparse' require 'ostruct' require 'fileutils' require 'rdiff_simple' options = OpenStruct.new @verbose = false usage = "Usage: understudy [options] job-name" OptionParser.new do |opts| opts.banner = usage opts.on '-v', '--verbose', 'Output extra information' do |v| @verbose = v end opts.on '-f', '--first-time', 'Force first-time run' do |f| options.first = f end end.parse! def error msg STDERR.puts "ERROR: #{msg}" exit 255 end error usage if ARGV.length != 1 job_name = ARGV.shift config_file = "/etc/understudy/#{job_name}.conf" error "Cannot find '#{config_file}'" unless File.exist? config_file DATA_DIR = "/var/lib/understudy/#{job_name}" FileUtils.mkdir_p DATA_DIR lockfile = File.open( "#{DATA_DIR}/LOCK", File::RDWR|File::CREAT, 0644 ) unless lockfile.flock File::LOCK_EX|File::LOCK_NB error "Job #{job_name} is already running" end lockfile.puts $$ lockfile.flush config = OpenStruct.new # Any options that aren't our options go to rdiff-backup OUR_OPTIONS = %w{source dest command} rdiff_args = [] File.read( config_file ).split( /\n/ ).each do |line| line.sub! /#.*$/, '' line.sub! /^\s+/, '' line.sub! /\s+$/, '' next if line.empty? line =~ /^([-\w]+)(\s+=\s+(.*))?$/ or raise "Strange line in config: #{line}" key = $1 val = $3 if OUR_OPTIONS.member? key config.send "#{key}=".to_sym, val else rdiff_args.push "--#{key}" + ( val ? "=#{val}" : "" ) end end error "Missing 'dest' config option" unless config.dest error "Missing 'source' config option" unless config.source rdiff_data = "#{config.dest}/rdiff-backup-data" exists = File.directory? rdiff_data if exists && options.first error "Cannot force first time, destination '#{config.dest}' already exists" elsif !exists && !options.first error "Destination '#{config.dest}' does not appear to exist, try again with --first-time" end def info message return unless @verbose end def run command friendly = nil if command.is_a? Array friendly = command.map { |i| i =~ /[^-=\/\.\w]/ ? "#{i}" : i }.join ' ' info "Running: #{friendly}" RdiffSimple.execute( friendly ) or error "Could not run #{friendly}" else friendly = command info "Running: #{friendly}" RdiffSimple.execute( friendly ) or error "Could not run #{friendly}" end if $? != 0 error "Could not run #{friendly}" end end ENV['PATH'] += ":/etc/understudy" run config.command if config.command command = [] command << "--terminal-verbosity=5" if @verbose command << "--print-statistics" command += rdiff_args command << config.source command << config.dest run command info "Backup successful" exit 0