Catch an error generated while copying iso image to the target.

pull/376/head
shinji-s 6 years ago
parent 674a06b88a
commit c71ed97282

@ -7,32 +7,26 @@
# under the terms of GNU General Public License, v.2 or above
# WARNING : Any boot-able USB made using this module will destroy data stored on USB disk.
import os
import subprocess
import collections
import io
import os
import platform
import signal
import subprocess
import traceback
from PyQt5 import QtWidgets
from .gui.ui_multibootusb import Ui_MainWindow
from .gen import *
from . import iso
from . import config
from . import iso
from . import osdriver
from . import progressbar
if platform.system() == "Windows":
import win32com.client
def dd_linux():
import time
_input = "if=" + config.image_path
in_file_size = float(os.path.getsize(config.image_path))
_output = "of=" + config.usb_disk
os.system("umount " + config.usb_disk + "1")
command = ['dd', _input, _output, "bs=1M", "oflag=sync"]
log("Executing ==> " + " ".join(command))
dd_process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
def dd_iso_image(dd_progress_thread):
pbar = progressbar.ProgressBar(
maxval=100,
widgets=[
@ -43,52 +37,20 @@ def dd_linux():
]
).start()
while dd_process.poll() is None:
time.sleep(0.1) # If this time delay is not given, the Popen does not execute the actual command
dd_process.send_signal(signal.SIGUSR1)
dd_process.stderr.flush()
while True:
time.sleep(0.1)
out_error = dd_process.stderr.readline().decode()
if out_error:
if 'bytes' in out_error:
copied = int(out_error.split(' ', 1)[0])
config.imager_percentage = round((float(copied) / float(in_file_size) * 100))
pbar.update(config.imager_percentage)
break
if dd_process.poll() is not None:
log("\nExecuting ==> sync")
os.sync()
log("ISO has been written to USB disk...")
return
def dd_win():
windd = resource_path(os.path.join("data", "tools", "dd", "dd.exe"))
if os.path.exists(resource_path(os.path.join("data", "tools", "dd", "dd.exe"))):
log("dd exist")
_input = "if=" + config.image_path
in_file_size = float(os.path.getsize(config.image_path) / 1024 / 1024)
_output = "of=\\\.\\" + config.usb_disk
command = [windd, _input, _output, "bs=1M", "--progress"]
log("Executing ==> " + " ".join(command))
dd_process = subprocess.Popen(command, universal_newlines=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
shell=False)
while dd_process.poll() is None:
for line in iter(dd_process.stderr.readline, ''):
line = line.strip()
if 'error' in line.lower() or 'invalid' in line.lower():
log("Error writing to disk...")
break
if line and line[-1] == 'M':
copied = float(line.strip('M').replace(',', ''))
config.imager_percentage = round((copied / float(in_file_size) * 100))
log("ISO has been written to USB disk...")
return
def gui_update(percentage):
config.imager_percentage = percentage
pbar.update(percentage)
try:
error = osdriver.dd_iso_image(config.image_path, config.usb_disk,
gui_update)
if error:
dd_progress_thread.set_error(error)
except:
o = io.StringIO()
traceback.print_exc(None, o)
log(o.getvalue())
dd_progress_thread.set_error(o.getvalue())
class Imager(QtWidgets.QMainWindow, Ui_MainWindow):

@ -31,7 +31,7 @@ from .distro import *
from .qemu import *
from .iso import *
# from .imager import *
from .imager import Imager, dd_linux, dd_win
from .imager import Imager, dd_iso_image
from . import persistence
from . import config
from . import admin
@ -731,8 +731,15 @@ Proceed with installation?'''.lstrip() % \
config.process_exist = None
msgBox = QtWidgets.QMessageBox()
msgBox.setText("Image succesfully written to USB disk.")
msgBox.setInformativeText("Reboot to boot from USB or test it from <b>Boot ISO/USB</b> tab.");
if self.progress_thread_dd.error:
title = "Failed to write the iso image to the USB disk."
msg = self.progress_thread_dd.error
else:
title = "Image succesfully written to USB disk."
msg = "Reboot to boot from USB or test it from " \
"<b>Boot ISO/USB</b> tab."
msgBox.setText(title)
msgBox.setInformativeText(msg);
msgBox.setStandardButtons(QtWidgets.QMessageBox.Ok)
msgBox.setIcon(QtWidgets.QMessageBox.Information)
msgBox.exec_()
@ -960,15 +967,15 @@ class DD_Progress(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
if platform.system() == 'Linux':
self.thread = GenericThread(dd_linux)
elif platform.system() == 'Windows':
self.thread = GenericThread(dd_win)
self.error = None
self.thread = GenericThread(partial(dd_iso_image, self))
def __del__(self):
self.wait()
def set_error(self, error):
self.error = error
def run(self):
self.thread.start()
while self.thread.isRunning():

@ -2,9 +2,12 @@ import logging
import logging.handlers
import os
import platform
import queue
import shutil
import signal
import subprocess
import sys
import time
def log(message, info=True, error=False, debug=False, _print=True):
@ -136,6 +139,30 @@ class Base:
else:
log("%s succeeded." % str(cmd))
def dd_iso_image(self, input_, output, gui_update):
in_file_size = os.path.getsize(input_)
cmd = [self.dd_exe, 'if='+input_, 'of='+output, 'bs=1M']
self.dd_iso_image_add_args(cmd, input_, output)
log('Executing => ' + str(cmd))
kw_args = {
'stdout' : subprocess.PIPE,
'stderr' : subprocess.PIPE,
'shell' : False,
}
self.add_dd_iso_image_popen_args(kw_args)
dd_process = subprocess.Popen(cmd, **kw_args)
errors = queue.Queue()
while dd_process.poll() is None:
self.dd_iso_image_readoutput(dd_process, gui_update, in_file_size,
errors)
if dd_process.returncode == 0:
return None
else:
return ''.join([errors.get() for i in range(errors.qsize())]) or \
"'dd' returned exit-code:%d" % dd_process.returncode
class Windows(Base):
def __init__(self):
@ -144,6 +171,26 @@ class Windows(Base):
def dd_add_args(self, cmd_vec, input, output, bs, count):
pass
def dd_iso_image_add_args(self, cmd_vec, input_, output):
cmd_vec.append('--progress')
def add_dd_iso_image_popen_args(self, dd_iso_image_popen_args):
dd_iso_image_popen_args['universal_newlines'] = True
def dd_iso_image_readoutput(self, dd_process, gui_update, in_file_size,
error_log):
for line in iter(dd_process.stderr.readline, ''):
line = line.strip()
if line and line[-1:] == 'M':
bytes_copied = float(line.rstrip('M').replace(',', '')) \
* 1024 * 1024
gui_update(byets_copied / in_file_size * 100.)
else:
if 16 < error_log.qsize():
error_log.get()
error_log.put(line)
# Now the 'dd' process should have completed or going to soon.
def physical_disk(self, usb_disk):
return r'\\.\physicaldrive%d' % get_physical_disk_number(usb_disk)
@ -158,6 +205,34 @@ class Linux(Base):
def dd_add_args(self, cmd_vec, input, output, bs, count):
cmd_vec.append('conv=notrunc')
def dd_iso_image_add_args(self, cmd_vec, input_, output):
cmd_vec.append('oflag=sync')
def add_dd_iso_image_popen_args(self, dd_iso_image_popen_args):
pass
def dd_iso_image_readoutput(self, dd_process, gui_update, in_file_size,
error_log):
# If this time delay is not given, the Popen does not execute
# the actual command
time.sleep(0.1)
dd_process.send_signal(signal.SIGUSR1)
dd_process.stderr.flush()
while True:
time.sleep(0.1)
out_error = dd_process.stderr.readline().decode()
if out_error:
if 'bytes' in out_error:
bytes_copied = float(out_error.split(' ', 1)[0])
gui_update( bytes_copied / in_file_size * 100. )
break
if 16 < error_log.qsize():
error_log.get()
error_log.put(out_error)
else:
# stderr is closed
break
def physical_disk(self, usb_disk):
return usb_disk.rstrip('0123456789')
@ -177,6 +252,7 @@ for func_name in [
'run_dd',
'physical_disk',
'mbusb_log_file',
'dd_iso_image',
]:
globals()[func_name] = getattr(osdriver, func_name)

Loading…
Cancel
Save