backup_utils.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #!/usr/bin/python2.6
  2. #
  3. # The Qubes OS Project, http://www.qubes-os.org
  4. #
  5. # Copyright (C) 2012 Agnieszka Kostrzewa <agnieszka.kostrzewa@gmail.com>
  6. #
  7. # This program is free software; you can redistribute it and/or
  8. # modify it under the terms of the GNU General Public License
  9. # as published by the Free Software Foundation; either version 2
  10. # of the License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. #
  21. #
  22. import sys
  23. import os
  24. from PyQt4.QtCore import *
  25. from PyQt4.QtGui import *
  26. from pyinotify import WatchManager, Notifier, ThreadedNotifier, EventsCodes, ProcessEvent
  27. import subprocess
  28. import time
  29. from thread_monitor import *
  30. from datetime import datetime
  31. from string import replace
  32. mount_for_backup_path = '/usr/libexec/qubes-manager/mount_for_backup.sh'
  33. def check_if_mounted(dev_path):
  34. mounts_file = open("/proc/mounts")
  35. for m in list(mounts_file):
  36. if m.startswith(dev_path):
  37. return m.split(" ")[1]
  38. return None
  39. def mount_device(dev_path):
  40. try:
  41. mount_dir_name = "backup" + replace(str(datetime.now()),' ', '-').split(".")[0]
  42. pmount_cmd = [mount_for_backup_path, dev_path, mount_dir_name]
  43. res = subprocess.check_call(pmount_cmd)
  44. except Exception as ex:
  45. QMessageBox.warning (None, "Error mounting selected device!", "ERROR: {0}".format(ex))
  46. return None
  47. if res == 0:
  48. dev_mount_path = "/media/"+mount_dir_name
  49. return dev_mount_path
  50. return None
  51. def umount_device(dev_mount_path):
  52. try:
  53. pumount_cmd = ["pumount", dev_mount_path]
  54. res = subprocess.check_call(pumount_cmd)
  55. if res == 0:
  56. dev_mount_path = None
  57. except Exception as ex:
  58. QMessageBox.warning (None, "Could not unmount backup device!", "ERROR: {0}".format(ex))
  59. return dev_mount_path
  60. def fill_devs_list(dialog):
  61. dialog.dev_combobox.clear()
  62. dialog.dev_combobox.addItem("None")
  63. dialog.blk_manager.blk_lock.acquire()
  64. for a in dialog.blk_manager.attached_devs:
  65. if dialog.blk_manager.attached_devs[a]['attached_to']['vm'] == dialog.vm.name :
  66. att = a + " " + unicode(dialog.blk_manager.attached_devs[a]['size']) + " " + dialog.blk_manager.attached_devs[a]['desc']
  67. dialog.dev_combobox.addItem(att, QVariant(a))
  68. for a in dialog.blk_manager.free_devs:
  69. att = a + " " + unicode(dialog.blk_manager.free_devs[a]['size']) + " " + dialog.blk_manager.free_devs[a]['desc']
  70. dialog.dev_combobox.addItem(att, QVariant(a))
  71. dialog.blk_manager.blk_lock.release()
  72. dialog.dev_combobox.setCurrentIndex(0) #current selected is null ""
  73. dialog.prev_dev_idx = 0
  74. dialog.dir_line_edit.clear()
  75. enable_dir_line_edit(dialog, True)
  76. def enable_dir_line_edit(dialog, boolean):
  77. dialog.dir_line_edit.setEnabled(boolean)
  78. dialog.select_path_button.setEnabled(boolean)
  79. def dev_combobox_activated(dialog, idx):
  80. if idx == dialog.prev_dev_idx: #nothing has changed
  81. return
  82. #there was a change
  83. dialog.dir_line_edit.setText("")
  84. dialog.backup_dir = None
  85. if dialog.dev_mount_path != None:
  86. dialog.dev_mount_path = umount_device(dialog.dev_mount_path)
  87. if dialog.dev_mount_path != None:
  88. dialog.dev_combobox.setCurrentIndex(dialog.prev_dev_idx)
  89. return
  90. if dialog.dev_combobox.currentText() != "None": #An existing device chosen
  91. dev_name = str(dialog.dev_combobox.itemData(idx).toString())
  92. dialog.blk_manager.blk_lock.acquire()
  93. if dev_name in dialog.blk_manager.free_devs:
  94. if dev_name.startswith(dialog.vm.name): # originally attached to dom0
  95. dev_path = "/dev/"+dev_name.split(":")[1]
  96. else: # originally attached to another domain, eg. usbvm
  97. #attach it to dom0, then treat it as an attached device
  98. dialog.blk_manager.attach_device(dialog.vm, dev_name)
  99. if dev_name in dialog.blk_manager.attached_devs: #is attached to dom0
  100. assert dialog.blk_manager.attached_devs[dev_name]['attached_to']['vm'] == dialog.vm.name
  101. dev_path = "/dev/" + dialog.blk_manager.attached_devs[dev_name]['attached_to']['frontend']
  102. dialog.blk_manager.blk_lock.release()
  103. #check if device mounted
  104. dialog.dev_mount_path = check_if_mounted(dev_path)
  105. if dialog.dev_mount_path == None:
  106. dialog.dev_mount_path = mount_device(dev_path)
  107. if dialog.dev_mount_path == None:
  108. dialog.dev_combobox.setCurrentIndex(0) #if couldn't mount - set current device to "None"
  109. dialog.prev_dev_idx = 0
  110. return
  111. dialog.prev_dev_idx = idx
  112. dialog.select_dir_page.emit(SIGNAL("completeChanged()"))
  113. def select_path_button_clicked(dialog):
  114. dialog.backup_dir = dialog.dir_line_edit.text()
  115. file_dialog = QFileDialog()
  116. file_dialog.setReadOnly(True)
  117. if dialog.dev_mount_path != None:
  118. new_path = file_dialog.getExistingDirectory(dialog, "Select backup directory.", dialog.dev_mount_path)
  119. else:
  120. new_path = file_dialog.getExistingDirectory(dialog, "Select backup directory.", "~")
  121. if new_path:
  122. dialog.dir_line_edit.setText(new_path)
  123. dialog.backup_dir = new_path
  124. dialog.select_dir_page.emit(SIGNAL("completeChanged()"))
  125. def simulate_long_lasting_proces(period, progress_callback):
  126. for i in range(period):
  127. progress_callback((i*100)/period)
  128. time.sleep(1)
  129. progress_callback(100)
  130. return 0