10100767da
Even when encrypted backup is selected, file list isn't encrypted. Do not leak VM names in the filenames.
135 lines
4.9 KiB
Python
Executable File
135 lines
4.9 KiB
Python
Executable File
#!/usr/bin/python2
|
|
#
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
#
|
|
# Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
|
#
|
|
# 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] <backup-dir-path> [vmname ...]"
|
|
parser = OptionParser (usage)
|
|
|
|
parser.add_option ("-x", "--exclude", action="append", dest="exclude_list",
|
|
help="Exclude the specified VM from backup (might 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")
|
|
parser.add_option ("-e", "--encrypt", action="store_true", dest="encrypt", default=False,
|
|
help="Encrypts 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:]]
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
try:
|
|
backup_do(base_backup_dir, files_to_backup, passphrase,
|
|
progress_callback=print_progress,
|
|
encrypt=options.encrypt,
|
|
appvm=appvm)
|
|
except QubesException as e:
|
|
print >>sys.stderr, "ERROR: %s" % str(e)
|
|
exit(1)
|
|
|
|
print
|
|
print "-> Backup completed."
|
|
|
|
qvm_collection.unlock_db()
|
|
main()
|