123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- #
- # The Qubes OS Project, http://www.qubes-os.org
- #
- # Copyright (C) 2016 Marek Marczykowski-Górecki
- # <marmarek@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 __future__ import print_function
- import getpass
- import locale
- import os
- import sys
- import qubes.backup
- import qubes.tools
- import qubes.utils
- parser = qubes.tools.QubesArgumentParser(want_force_root=True)
- parser.add_argument("--exclude", "-x", action="append",
- dest="exclude_list", default=[],
- help="Exclude the specified VM from the backup (may be "
- "repeated)")
- parser.add_argument("--dest-vm", "-d", action="store",
- dest="appvm", default=None,
- help="Specify the destination VM to which the backup "
- "will be sent (implies -e)")
- parser.add_argument("--encrypt", "-e", action="store_true", dest="encrypted",
- default=False,
- help="Encrypt the backup")
- parser.add_argument("--no-encrypt", action="store_true",
- dest="no_encrypt", default=False,
- help="Skip encryption even if sending the backup to a "
- "VM")
- parser.add_argument("--passphrase-file", "-p", action="store",
- dest="pass_file", default=None,
- help="Read passphrase from a file, or use '-' to read "
- "from stdin")
- parser.add_argument("--enc-algo", "-E", action="store",
- dest="crypto_algorithm", default=None,
- help="Specify a non-default encryption algorithm. For a "
- "list of supported algorithms, execute 'openssl "
- "list-cipher-algorithms' (implies -e)")
- parser.add_argument("--hmac-algo", "-H", action="store",
- dest="hmac_algorithm", default=None,
- help="Specify a non-default HMAC algorithm. For a list "
- "of supported algorithms, execute 'openssl "
- "list-message-digest-algorithms'")
- parser.add_argument("--compress", "-z", action="store_true", dest="compressed",
- default=False,
- help="Compress the backup")
- parser.add_argument("--compress-filter", "-Z", action="store",
- dest="compression_filter", default=False,
- help="Specify a non-default compression filter program "
- "(default: gzip)")
- parser.add_argument("--tmpdir", action="store", dest="tmpdir", default=None,
- help="Specify a temporary directory (if you have at least "
- "1GB free RAM in dom0, use of /tmp is advised) ("
- "default: /var/tmp)")
- parser.add_argument("backup_location", action="store",
- help="Backup location (directory path, or command to pipe backup to)")
- parser.add_argument("vms", nargs="*", action=qubes.tools.VmNameAction,
- help="Backup only those VMs")
- def main(args=None):
- args = parser.parse_args(args)
- appvm = None
- if args.appvm:
- try:
- appvm = args.app.domains[args.appvm]
- except KeyError:
- parser.error('no such domain: {!r}'.format(args.appvm))
- args.app.log.info(("NOTE: VM {} will be excluded because it is "
- "the backup destination.").format(args.appvm))
- if appvm:
- args.exclude_list.append(appvm.name)
- if args.appvm or args.crypto_algorithm:
- args.encrypted = True
- if args.no_encrypt:
- args.encrypted = False
- try:
- backup = qubes.backup.Backup(args.app,
- args.domains if args.domains else None,
- exclude_list=args.exclude_list)
- except qubes.exc.QubesException as e:
- parser.error_runtime(str(e))
- # unreachable - error_runtime will raise SystemExit
- return 1
- backup.target_dir = args.backup_location
- if not appvm:
- if os.path.isdir(args.backup_location):
- stat = os.statvfs(args.backup_location)
- else:
- stat = os.statvfs(os.path.dirname(args.backup_location))
- backup_fs_free_sz = stat.f_bsize * stat.f_bavail
- print()
- if backup.total_backup_bytes > backup_fs_free_sz:
- parser.error_runtime("Not enough space available on the "
- "backup filesystem!")
- args.app.log.info("Available space: {0}".format(
- qubes.utils.size_to_human(backup_fs_free_sz)))
- else:
- stat = os.statvfs('/var/tmp')
- backup_fs_free_sz = stat.f_bsize * stat.f_bavail
- print()
- if backup_fs_free_sz < 1000000000:
- parser.error_runtime("Not enough space available "
- "on the local filesystem (1GB required for temporary files)!")
- if not appvm.is_running():
- appvm.start()
- if not args.encrypted:
- args.app.log.info("WARNING: The backup will NOT be encrypted!")
- if args.pass_file is not None:
- pass_f = open(args.pass_file) if args.pass_file != "-" else sys.stdin
- passphrase = pass_f.readline().rstrip()
- if pass_f is not sys.stdin:
- pass_f.close()
- else:
- if input("Do you want to proceed? [y/N] ").upper() != "Y":
- return 0
- prompt = ("Please enter the passphrase that will be used to {}verify "
- "the backup: ").format('encrypt and ' if args.encrypted else '')
- passphrase = getpass.getpass(prompt)
- if getpass.getpass("Enter again for verification: ") != passphrase:
- parser.error_runtime("Passphrase mismatch!")
- backup.encrypted = args.encrypted
- backup.compressed = args.compressed
- if args.compression_filter:
- backup.compression_filter = args.compression_filter
- encoding = sys.stdin.encoding or locale.getpreferredencoding()
- backup.passphrase = passphrase.decode(encoding)
- if args.hmac_algorithm:
- backup.hmac_algorithm = args.hmac_algorithm
- if args.crypto_algorithm:
- backup.crypto_algorithm = args.crypto_algorithm
- if args.tmpdir:
- backup.tmpdir = args.tmpdir
- if appvm:
- backup.target_vm = appvm
- try:
- backup.backup_do()
- except qubes.exc.QubesException as e:
- parser.error_runtime(str(e))
- print()
- args.app.log.info("Backup completed.")
- return 0
- if __name__ == '__main__':
- main()
|