#!/usr/bin/python2 # # The Qubes OS Project, http://www.qubes-os.org # # Copyright (C) 2010 Joanna Rutkowska # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # from qubes.qubes import QubesVmCollection from qubes.qubes import QubesException from qubes.backup import backup_prepare, backup_do from qubes.qubesutils import size_to_human from optparse import OptionParser import os import sys import getpass def print_progress(progress): print >> sys.stderr, "\r-> Backing up files: {0}%...".format (progress), def main(): usage = "usage: %prog [options] [vms-to-be-included ...]" parser = OptionParser (usage) parser.add_option ("-x", "--exclude", action="append", dest="exclude_list", default=[], help="Exclude the specified VM from backup (may be " "repeated)") parser.add_option ("--force-root", action="store_true", dest="force_root", default=False, help="Force to run, even with root privileges") parser.add_option ("-d", "--dest-vm", action="store", dest="appvm", help="The AppVM to send backups to (implies -e)") parser.add_option ("-e", "--encrypt", action="store_true", dest="encrypt", default=False, help="Encrypts the backup") parser.add_option ("-E", "--enc-algo", action="store", dest="crypto_algorithm", default=None, help="Specify non-default encryption algorithm. For " "list of supported algos execute 'openssl " "list-cipher-algorithms' (implies -e)") parser.add_option ("-H", "--hmac-algo", action="store", dest="hmac_algorithm", default=None, help="Specify non-default hmac algorithm. For list of " "supported algos execute 'openssl " "list-message-digest-algorithms'") parser.add_option ("-z", "--compress", action="store_true", dest="compress", default=False, help="Compress the backup") (options, args) = parser.parse_args () if (len (args) < 1): print >> sys.stderr, "You must specify the target backup directory (e.g. /mnt/backup)" print >> sys.stderr, "qvm-backup will create a subdirectory there for each individual backup." exit (0) base_backup_dir = args[0] if os.geteuid() == 0: if not options.force_root: print >> sys.stderr, "*** Running this tool as root is strongly discouraged, this will lead you in permissions problems." print >> sys.stderr, "Retry as unprivileged user." print >> sys.stderr, "... or use --force-root to continue anyway." exit(1) # Only for locking qvm_collection = QubesVmCollection() qvm_collection.lock_db_for_reading() qvm_collection.load() vms = None if (len (args) > 1): vms = [qvm_collection.get_vm_by_name(vmname) for vmname in args[1:]] if options.appvm: print >>sys.stderr, ("WARNING: VM {} excluded because it's used to " "store the backup.").format(options.appvm) options.exclude_list.append(options.appvm) if options.appvm or options.crypto_algorithm: options.encrypt = True files_to_backup = None try: files_to_backup = backup_prepare( vms_list=vms, exclude_list=options.exclude_list, hide_vm_names=options.encrypt) except QubesException as e: print >>sys.stderr, "ERROR: %s" % str(e) exit(1) total_backup_sz = reduce(lambda size, file: size+file["size"], files_to_backup, 0) if not options.appvm: appvm = None stat = os.statvfs(base_backup_dir) backup_fs_free_sz = stat.f_bsize * stat.f_bavail print if (total_backup_sz > backup_fs_free_sz): print >>sys.stderr, "ERROR: Not enough space available on the backup filesystem!" exit(1) print "-> Available space: {0}".format(size_to_human(backup_fs_free_sz)) else: appvm = qvm_collection.get_vm_by_name(options.appvm) if appvm is None: print >>sys.stderr, "ERROR: VM {0} does not exist".format(options.appvm) exit(1) stat = os.statvfs('/var/tmp') backup_fs_free_sz = stat.f_bsize * stat.f_bavail print if (backup_fs_free_sz < 1000000000): print >>sys.stderr, "ERROR: Not enough space available " \ "on the local filesystem (needs 1GB for temporary files)!" exit(1) if not appvm.is_running(): appvm.start(verbose=True) prompt = raw_input ("Do you want to proceed? [y/N] ") if not (prompt == "y" or prompt == "Y"): exit (0) passphrase = getpass.getpass("Please enter the pass phrase that will be used to encrypt/verify the backup: ") passphrase2 = getpass.getpass("Enter again for verification: ") if passphrase != passphrase2: print >>sys.stderr, "ERROR: Password mismatch" exit(1) passphrase = passphrase.decode(sys.stdin.encoding) kwargs = {} if options.hmac_algorithm: kwargs['hmac_algorithm'] = options.hmac_algorithm if options.crypto_algorithm: kwargs['crypto_algorithm'] = options.crypto_algorithm try: backup_do(base_backup_dir, files_to_backup, passphrase, progress_callback=print_progress, encrypted=options.encrypt, compressed=options.compress, appvm=appvm, **kwargs) except QubesException as e: print >>sys.stderr, "ERROR: %s" % str(e) exit(1) print print "-> Backup completed." qvm_collection.unlock_db() main()