21d72cdc6c
Prompt for retype the backup password, more thoroughly test if the user entered all required informations, use "dom0" instead of "None" for local backup indication.
203 lines
7.4 KiB
Python
203 lines
7.4 KiB
Python
#!/usr/bin/python2
|
|
#
|
|
# The Qubes OS Project, http://www.qubes-os.org
|
|
#
|
|
# Copyright (C) 2012 Agnieszka Kostrzewa <agnieszka.kostrzewa@gmail.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.
|
|
#
|
|
#
|
|
|
|
import sys
|
|
import os
|
|
from PyQt4.QtCore import *
|
|
from PyQt4.QtGui import *
|
|
|
|
from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
|
|
|
|
import subprocess
|
|
import time
|
|
|
|
from thread_monitor import *
|
|
|
|
from datetime import datetime
|
|
from string import replace
|
|
|
|
mount_for_backup_path = '/usr/libexec/qubes-manager/mount_for_backup.sh'
|
|
|
|
def check_if_mounted(dev_path):
|
|
mounts_file = open("/proc/mounts")
|
|
for m in list(mounts_file):
|
|
if m.startswith(dev_path):
|
|
return m.split(" ")[1]
|
|
return None
|
|
|
|
|
|
def mount_device(dev_path):
|
|
try:
|
|
mount_dir_name = "backup" + replace(str(datetime.now()),' ', '-').split(".")[0]
|
|
pmount_cmd = [mount_for_backup_path, dev_path, mount_dir_name]
|
|
res = subprocess.check_call(pmount_cmd)
|
|
except Exception as ex:
|
|
QMessageBox.warning (None, "Error mounting selected device!", "<b>Could not mount {0}.</b><br><br>ERROR: {1}".format(dev_path, ex))
|
|
return None
|
|
if res == 0:
|
|
dev_mount_path = "/media/"+mount_dir_name
|
|
return dev_mount_path
|
|
return None
|
|
|
|
def umount_device(dev_mount_path):
|
|
while True:
|
|
try:
|
|
pumount_cmd = ["sudo", "pumount", "--luks-force", dev_mount_path]
|
|
res = subprocess.check_call(pumount_cmd)
|
|
if res == 0:
|
|
dev_mount_path = None
|
|
return dev_mount_path
|
|
except Exception as ex:
|
|
title = "Error unmounting backup device!"
|
|
text = "<b>Could not unmount {0}.</b><br>\
|
|
<b>Please retry or unmount it manually using</b><br> pumount {0}.<br><br>\
|
|
ERROR: {1}".format(dev_mount_path, ex)
|
|
button = QMessageBox.warning (None, title, text, QMessageBox.Ok | QMessageBox.Retry, QMessageBox.Retry)
|
|
if button == QMessageBox.Ok:
|
|
return dev_mount_path
|
|
|
|
def fill_appvms_list(dialog):
|
|
dialog.appvm_combobox.clear()
|
|
dialog.appvm_combobox.addItem("dom0")
|
|
|
|
dialog.appvm_combobox.setCurrentIndex(0) #current selected is null ""
|
|
|
|
for vm in dialog.qvm_collection.values():
|
|
if vm.is_appvm() and vm.internal:
|
|
continue
|
|
if vm.is_template() and vm.installed_by_rpm:
|
|
continue
|
|
|
|
if vm.is_running() and vm.qid != 0:
|
|
dialog.appvm_combobox.addItem(vm.name)
|
|
|
|
def fill_devs_list(dialog):
|
|
dialog.dev_combobox.clear()
|
|
dialog.dev_combobox.addItem("None")
|
|
|
|
dialog.blk_manager.blk_lock.acquire()
|
|
for a in dialog.blk_manager.attached_devs:
|
|
if dialog.blk_manager.attached_devs[a]['attached_to']['vm'] == dialog.vm.name :
|
|
att = a + " " + unicode(dialog.blk_manager.attached_devs[a]['size']) + " " + dialog.blk_manager.attached_devs[a]['desc']
|
|
dialog.dev_combobox.addItem(att, QVariant(a))
|
|
for a in dialog.blk_manager.free_devs:
|
|
att = a + " " + unicode(dialog.blk_manager.free_devs[a]['size']) + " " + dialog.blk_manager.free_devs[a]['desc']
|
|
dialog.dev_combobox.addItem(att, QVariant(a))
|
|
dialog.blk_manager.blk_lock.release()
|
|
|
|
dialog.dev_combobox.setCurrentIndex(0) #current selected is null ""
|
|
dialog.prev_dev_idx = 0
|
|
dialog.dir_line_edit.clear()
|
|
enable_dir_line_edit(dialog, True)
|
|
|
|
|
|
def enable_dir_line_edit(dialog, boolean):
|
|
dialog.dir_line_edit.setEnabled(boolean)
|
|
dialog.select_path_button.setEnabled(boolean)
|
|
|
|
|
|
def dev_combobox_activated(dialog, idx):
|
|
if idx == dialog.prev_dev_idx: #nothing has changed
|
|
return
|
|
#there was a change
|
|
|
|
dialog.dir_line_edit.setText("")
|
|
dialog.backup_location = None
|
|
|
|
if dialog.dev_mount_path != None:
|
|
dialog.dev_mount_path = umount_device(dialog.dev_mount_path)
|
|
if dialog.dev_mount_path != None:
|
|
dialog.dev_combobox.setCurrentIndex(dialog.prev_dev_idx)
|
|
return
|
|
|
|
if dialog.dev_combobox.currentText() != "None": #An existing device chosen
|
|
dev_name = str(dialog.dev_combobox.itemData(idx).toString())
|
|
|
|
dialog.blk_manager.blk_lock.acquire()
|
|
if dev_name in dialog.blk_manager.free_devs:
|
|
if dev_name.startswith(dialog.vm.name): # originally attached to dom0
|
|
dev_path = "/dev/"+dev_name.split(":")[1]
|
|
|
|
else: # originally attached to another domain, eg. usbvm
|
|
#attach it to dom0, then treat it as an attached device
|
|
dialog.blk_manager.attach_device(dialog.vm, dev_name)
|
|
dialog.blk_manager.update()
|
|
|
|
if dev_name in dialog.blk_manager.attached_devs: #is attached to dom0
|
|
assert dialog.blk_manager.attached_devs[dev_name]['attached_to']['vm'] == dialog.vm.name
|
|
dev_path = "/dev/" + dialog.blk_manager.attached_devs[dev_name]['attached_to']['frontend']
|
|
dialog.blk_manager.blk_lock.release()
|
|
|
|
#check if device mounted
|
|
dialog.dev_mount_path = check_if_mounted(dev_path)
|
|
if dialog.dev_mount_path == None:
|
|
dialog.dev_mount_path = mount_device(dev_path)
|
|
if dialog.dev_mount_path == None:
|
|
dialog.dev_combobox.setCurrentIndex(0) #if couldn't mount - set current device to "None"
|
|
dialog.prev_dev_idx = 0
|
|
return
|
|
|
|
dialog.prev_dev_idx = idx
|
|
|
|
if dialog.dev_mount_path != None:
|
|
# Initialize path with root of mounted device
|
|
dialog.dir_line_edit.setText(dialog.dev_mount_path)
|
|
dialog.backup_location = dialog.dev_mount_path
|
|
|
|
dialog.select_dir_page.emit(SIGNAL("completeChanged()"))
|
|
|
|
|
|
def select_path_button_clicked(dialog, select_file = False):
|
|
dialog.backup_location = dialog.dir_line_edit.text()
|
|
file_dialog = QFileDialog()
|
|
file_dialog.setReadOnly(True)
|
|
|
|
if select_file:
|
|
file_dialog_function = file_dialog.getOpenFileName
|
|
else:
|
|
file_dialog_function = file_dialog.getExistingDirectory
|
|
|
|
new_appvm = None
|
|
new_path = None
|
|
if dialog.appvm_combobox.currentIndex() != 0: #An existing appvm chosen
|
|
new_appvm = str(dialog.appvm_combobox.currentText())
|
|
elif dialog.dev_mount_path != None:
|
|
new_path = file_dialog_function(dialog, "Select backup location.", dialog.dev_mount_path)
|
|
else:
|
|
new_path = file_dialog_function(dialog, "Select backup location.", "~")
|
|
|
|
if new_path != None:
|
|
dialog.dir_line_edit.setText(new_path)
|
|
dialog.backup_location = new_path
|
|
|
|
if (new_path or new_appvm) and len(dialog.backup_location) > 0:
|
|
dialog.select_dir_page.emit(SIGNAL("completeChanged()"))
|
|
|
|
def simulate_long_lasting_proces(period, progress_callback):
|
|
for i in range(period):
|
|
progress_callback((i*100)/period)
|
|
time.sleep(1)
|
|
|
|
progress_callback(100)
|
|
return 0
|
|
|