def _decompressIOSSlot(self): """ Slot to decompress an IOS image. """ item = self.uiIOSRoutersTreeWidget.currentItem() if item: key = item.data(0, QtCore.Qt.UserRole) ios_router = self._ios_routers[key] path = ios_router["image"] if not os.path.isfile(path): QtGui.QMessageBox.critical(self, "IOS image", "IOS image file {} is does not exist".format(path)) return if not isIOSCompressed(path): QtGui.QMessageBox.critical(self, "IOS image", "IOS image {} is not compressed".format(os.path.basename(path))) return decompressed_image_path = os.path.splitext(path)[0] + ".image" if os.path.isfile(decompressed_image_path): QtGui.QMessageBox.critical(self, "IOS image", "Decompressed IOS image {} already exist".format(os.path.basename(decompressed_image_path))) return thread = DecompressIOSThread(path, decompressed_image_path) progress_dialog = ProgressDialog(thread, "IOS image", "Decompressing IOS image {}...".format(path), "Cancel", busy=True, parent=self) progress_dialog.show() if progress_dialog.exec_() is not False: ios_router["image"] = decompressed_image_path self._refreshInfo(ios_router) thread.wait()
def _decompressIOSSlot(self): """ Slot to decompress an IOS image. """ item = self.uiIOSRoutersTreeWidget.currentItem() if item: key = item.data(0, QtCore.Qt.UserRole) ios_router = self._ios_routers[key] path = ios_router["path"] if not os.path.isfile(path): QtGui.QMessageBox.critical(self, "IOS image", "IOS image file {} is does not exist".format(path)) return if not isIOSCompressed(path): QtGui.QMessageBox.critical(self, "IOS image", "IOS image {} is not compressed".format(os.path.basename(path))) return decompressed_image_path = os.path.splitext(path)[0] + ".image" if os.path.isfile(decompressed_image_path): QtGui.QMessageBox.critical(self, "IOS image", "Decompressed IOS image {} already exist".format(os.path.basename(decompressed_image_path))) return thread = DecompressIOSThread(path, decompressed_image_path) progress_dialog = ProgressDialog(thread, "IOS image", "Decompressing IOS image {}...".format(path), "Cancel", busy=True, parent=self) progress_dialog.show() if progress_dialog.exec_() is not False: ios_router["path"] = decompressed_image_path ios_router["image"] = os.path.basename(decompressed_image_path) self._refreshInfo(ios_router) thread.wait()
def _uncompressIOSSlot(self): """ Slot to uncompress an IOS image. """ item = self.uiIOSImagesTreeWidget.currentItem() if item: image = item.text(0) server = item.text(2) key = "{server}:{image}".format(server=server, image=image) ios_image = self._ios_images[key] path = ios_image["path"] if not os.path.isfile(path): QtGui.QMessageBox.critical(self, "IOS image", "IOS image file {} is does not exist".format(path)) return if not isIOSCompressed(path): QtGui.QMessageBox.critical(self, "IOS image", "IOS image {} is not compressed".format(os.path.basename(path))) return uncompressed_image_path = os.path.splitext(path)[0] + ".image" if os.path.isfile(uncompressed_image_path): QtGui.QMessageBox.critical(self, "IOS image", "Uncompressed IOS image {} already exist".format(os.path.basename(uncompressed_image_path))) return thread = UncompressIOSThread(path, uncompressed_image_path) progress_dialog = ProgressDialog(thread, "IOS image", "Uncompressing IOS image {}...".format(path), "Cancel", busy=True, parent=self) progress_dialog.show() if progress_dialog.exec_() is not False: self.uiIOSPathLineEdit.setText(uncompressed_image_path) self._iosImageSaveSlot() thread.wait()
def localServerAutoStartIfRequire(self): """ Try to start the embed gns3 server. """ if not self.shouldLocalServerAutoStart(): self._http_client = HTTPClient(self._settings) Controller.instance().setHttpClient(self._http_client) return if self.isLocalServerRunning() and self._server_started_by_me: return True # We check if two gui are not launched at the same time # to avoid killing the server of the other GUI if not LocalConfig.isMainGui(): log.info("Not the main GUI, will not auto start the server") self._http_client = HTTPClient(self._settings) Controller.instance().setHttpClient(self._http_client) return True if self.isLocalServerRunning(): log.debug("A local server already running on this host") # Try to kill the server. The server can be still running after # if the server was started by hand self._killAlreadyRunningServer() if not self.isLocalServerRunning(): if not self.initLocalServer(): QtWidgets.QMessageBox.critical( self.parent(), "Local server", "Could not start the local server process: {}".format( self._settings["path"])) return False if not self.startLocalServer(): QtWidgets.QMessageBox.critical( self.parent(), "Local server", "Could not start the local server process: {}".format( self._settings["path"])) return False if self.parent(): worker = WaitForConnectionWorker(self._settings["host"], self._port) progress_dialog = ProgressDialog( worker, "Local server", "Connecting to server {} on port {}...".format( self._settings["host"], self._port), "Cancel", busy=True, parent=self.parent()) progress_dialog.show() if not progress_dialog.exec_(): return False self._server_started_by_me = True self._http_client = HTTPClient(self._settings) Controller.instance().setHttpClient(self._http_client) return True
def localServerAutoStartIfRequire(self): """ Try to start the embed gns3 server. """ if not self.shouldLocalServerAutoStart(): self._http_client = HTTPClient(self._settings) Controller.instance().setHttpClient(self._http_client) return if self.isLocalServerRunning() and self._server_started_by_me: return True # We check if two gui are not launched at the same time # to avoid killing the server of the other GUI if not LocalConfig.isMainGui(): log.info("Not the main GUI, will not auto start the server") self._http_client = HTTPClient(self._settings) Controller.instance().setHttpClient(self._http_client) return True if self.isLocalServerRunning(): log.info("A local server already running on this host") # Try to kill the server. The server can be still running after # if the server was started by hand self._killAlreadyRunningServer() if not self.isLocalServerRunning(): if not self.initLocalServer(): QtWidgets.QMessageBox.critical(self.parent(), "Local server", "Could not start the local server process: {}".format(self._settings["path"])) return False if not self.startLocalServer(): QtWidgets.QMessageBox.critical(self.parent(), "Local server", "Could not start the local server process: {}".format(self._settings["path"])) return False if self.parent(): worker = WaitForConnectionWorker(self._settings["host"], self._port) progress_dialog = ProgressDialog(worker, "Local server", "Connecting to server {} on port {}...".format(self._settings["host"], self._port), "Cancel", busy=True, parent=self.parent()) progress_dialog.show() if not progress_dialog.exec_(): return False self._server_started_by_me = True self._http_client = HTTPClient(self._settings) Controller.instance().setHttpClient(self._http_client) return True
def _decompressIOSSlot(self): """ Slot to decompress an IOS image. """ item = self.uiIOSRoutersTreeWidget.currentItem() if item: key = item.data(0, QtCore.Qt.UserRole) ios_router = self._ios_routers[key] path = ios_router["image"] if not os.path.isabs(path): path = os.path.join(self.getImageDirectory(), path) if not os.path.isfile(path): QtWidgets.QMessageBox.critical(self, "IOS image", "IOS image file {} does not exist".format(path)) return try: if not isIOSCompressed(path): QtWidgets.QMessageBox.critical(self, "IOS image", "IOS image {} is not compressed".format(os.path.basename(path))) return except OSError as e: # errno 22, invalid argument means the file system where the IOS image is located doesn't support mmap if e.errno == 22: QtWidgets.QMessageBox.critical(self, "IOS image", "IOS image {} cannot be memory mapped, most likely because the file system doesn't support it".format(os.path.basename(path))) else: QtWidgets.QMessageBox.critical(self, "IOS image", "Could not determine if the IOS image is compressed: {}".format(e)) return except ValueError as e: QtWidgets.QMessageBox.critical(self, "IOS image", "Could not determine if the IOS image is compressed: {}".format(e)) return decompressed_image_path = os.path.splitext(path)[0] + ".image" if os.path.isfile(decompressed_image_path): QtWidgets.QMessageBox.critical(self, "IOS image", "Decompressed IOS image {} already exist".format(os.path.basename(decompressed_image_path))) return worker = DecompressIOSWorker(path, decompressed_image_path) progress_dialog = ProgressDialog(worker, "IOS image", "Decompressing IOS image {}...".format(path), "Cancel", busy=True, parent=self) progress_dialog.show() if progress_dialog.exec_() is not False: ios_router["image"] = decompressed_image_path self._refreshInfo(ios_router)
def askCopyUploadImage(self, parent, source_path, server, node_type): """ Ask user for copying the image to the default directory or upload it to remote server. :param parent: Parent window :param path: File path on computer :param server: The server where the images should be located :param node_type: Remote upload endpoint :returns path: Final path """ if (server and server != "local") or Controller.instance().isRemote(): return self._uploadImageToRemoteServer(source_path, server, node_type) else: destination_directory = self.getDirectoryForType(node_type) destination_path = os.path.join(destination_directory, os.path.basename(source_path)) source_filename = os.path.basename(source_path) destination_filename = os.path.basename(destination_path) if os.path.normpath(os.path.dirname(source_path)) != destination_directory: # the image is not in the default images directory if source_filename == destination_filename: # the filename already exists in the default images directory source_image = Image(node_type, source_path, filename=source_filename) destination_image = Image(node_type, destination_path, filename=destination_filename) try: if source_image.md5sum == destination_image.md5sum: # the source and destination images are identical return source_path except OSError as e: QtWidgets.QMessageBox.critical(parent, 'Image', 'Cannot compare image file {} with {}: {}.'.format(source_path, destination_path, str(e))) return source_path # find a new unique path to avoid overwriting existing destination file destination_path = self._getUniqueDestinationPath(source_image, node_type, destination_path) reply = QtWidgets.QMessageBox.question(parent, 'Image', 'Would you like to copy {} to the default images directory'.format(source_filename), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: try: os.makedirs(destination_directory, exist_ok=True) except OSError as e: QtWidgets.QMessageBox.critical(parent, 'Image', 'Could not create destination directory {}: {}'.format(destination_directory, str(e))) return source_path worker = FileCopyWorker(source_path, destination_path) progress_dialog = ProgressDialog(worker, 'Image', 'Copying {}'.format(source_filename), 'Cancel', busy=True, parent=parent) progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtWidgets.QMessageBox.critical(parent, 'Image', '{}'.format(''.join(errors))) return source_path else: source_path = destination_path return source_path
def _decompressIOSSlot(self): """ Slot to decompress an IOS image. """ item = self.uiIOSRoutersTreeWidget.currentItem() if item: key = item.data(0, QtCore.Qt.UserRole) ios_router = self._ios_routers[key] path = ios_router["image"] if not os.path.isfile(path): QtWidgets.QMessageBox.critical(self, "IOS image", "IOS image file {} is does not exist".format(path)) return try: if not isIOSCompressed(path): QtWidgets.QMessageBox.critical(self, "IOS image", "IOS image {} is not compressed".format(os.path.basename(path))) return except OSError as e: # errno 22, invalid argument means the file system where the IOS image is located doesn't support mmap if e.errno == 22: QtWidgets.QMessageBox.critical(self, "IOS image", "IOS image {} cannot be memory mapped, most likely because the file system doesn't support it".format(os.path.basename(path))) else: QtWidgets.QMessageBox.critical(self, "IOS image", "Could not determine if the IOS image is compressed: {}".format(e)) return except ValueError as e: QtWidgets.QMessageBox.critical(self, "IOS image", "Could not determine if the IOS image is compressed: {}".format(e)) return decompressed_image_path = os.path.splitext(path)[0] + ".image" if os.path.isfile(decompressed_image_path): QtWidgets.QMessageBox.critical(self, "IOS image", "Decompressed IOS image {} already exist".format(os.path.basename(decompressed_image_path))) return worker = DecompressIOSWorker(path, decompressed_image_path) progress_dialog = ProgressDialog(worker, "IOS image", "Decompressing IOS image {}...".format(path), "Cancel", busy=True, parent=self) progress_dialog.show() if progress_dialog.exec_() is not False: ios_router["image"] = decompressed_image_path self._refreshInfo(ios_router)
def stopLocalServer(self, wait=False): """ Stops the local server. :param wait: wait for the server to stop """ if self.localServerProcessIsRunning(): self._stopping = True log.info("Stopping local server (PID={})".format(self._local_server_process.pid)) # local server is running, let's stop it if self._http_client: self._http_client.shutdown() if wait: worker = StopLocalServerWorker(self._local_server_process) progress_dialog = ProgressDialog(worker, "Local server", "Waiting for the local server to stop...", None, busy=True, parent=self.parent()) progress_dialog.show() progress_dialog.exec_() if self._local_server_process.returncode is None: self._killLocalServer() self._server_started_by_me = False
def stopLocalServer(self, wait=False): """ Stops the local server. :param wait: wait for the server to stop """ if self.localServerProcessIsRunning(): self._stopping = True log.debug("Stopping local server (PID={})".format( self._local_server_process.pid)) # local server is running, let's stop it if self._http_client: self._http_client.shutdown() if wait: worker = StopLocalServerWorker(self._local_server_process) progress_dialog = ProgressDialog( worker, "Local server", "Waiting for the local server to stop...", None, busy=True, parent=self.parent()) progress_dialog.show() progress_dialog.exec_() if self._local_server_process.returncode is None: self._killLocalServer() self._server_started_by_me = False
def getDiskImage(parent): destination_directory = os.path.join( MainWindow.instance().imagesDirPath(), "QEMU") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter( parent, "Select a QEMU disk image", destination_directory) if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "QEMU disk image", "Cannot read {}".format(path)) return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical( parent, "QEMU disk images directory", "Could not create the QEMU disk images directory {}: {}". format(destination_directory, e)) return if os.path.normpath(os.path.dirname(path)) != destination_directory: # the QEMU disk image is not in the default images directory reply = QtGui.QMessageBox.question( parent, "QEMU disk image", "Would you like to copy {} to the default images directory". format(os.path.basename(path)), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) thread = FileCopyThread(path, destination_path) progress_dialog = ProgressDialog(thread, "QEMU disk image", "Copying {}".format( os.path.basename(path)), "Cancel", busy=True, parent=parent) thread.deleteLater() progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtGui.QMessageBox.critical(parent, "QEMU disk image", "{}".format("".join(errors))) else: path = destination_path return path
def askCopyUploadImage(self, parent, path, server, node_type): """ Ask user for copying the image to the default directory or upload it to remote server. :param parent: Parent window :param path: File path on computer :param server: The server where the images should be located :param node_type: Remote upload endpoint :returns path: Final path """ if (server and server != "local") or Controller.instance().isRemote(): return self._uploadImageToRemoteServer(path, server, node_type) else: destination_directory = self.getDirectoryForType(node_type) if os.path.normpath( os.path.dirname(path)) != destination_directory: # the IOS image is not in the default images directory reply = QtWidgets.QMessageBox.question( parent, 'Image', 'Would you like to copy {} to the default images directory' .format(os.path.basename(path)), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) try: os.makedirs(destination_directory, exist_ok=True) except OSError as e: QtWidgets.QMessageBox.critical( parent, 'Image', 'Could not create destination directory {}: {}'. format(destination_directory, str(e))) return path worker = FileCopyWorker(path, destination_path) progress_dialog = ProgressDialog( worker, 'Image', 'Copying {}'.format(os.path.basename(path)), 'Cancel', busy=True, parent=parent) progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtWidgets.QMessageBox.critical( parent, 'Image', '{}'.format(''.join(errors))) return path else: path = destination_path return path
def askCopyUploadImage(self, parent, path, server, vm_type): """ Ask user for copying the image to the default directory or upload it to remote server. :param parent: Parent window :param path: File path on computer :param server: The server where the images should be located :param vm_type: Remote upload endpoint :returns path: Final path """ if server and not server.isLocal(): return self._uploadImageToRemoteServer(path, server, vm_type) else: destination_directory = self.getDirectoryForType(vm_type) if os.path.normpath(os.path.dirname(path)) != destination_directory: # the IOS image is not in the default images directory reply = QtWidgets.QMessageBox.question(parent, 'Image', 'Would you like to copy {} to the default images directory'.format(os.path.basename(path)), QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) try: os.makedirs(destination_directory, exist_ok=True) except OSError as e: QtWidgets.QMessageBox.critical(parent, 'Image', 'Could not create destination directory {}: {}'.format(destination_directory, str(e))) return path worker = FileCopyWorker(path, destination_path) progress_dialog = ProgressDialog(worker, 'Image', 'Copying {}'.format(os.path.basename(path)), 'Cancel', busy=True, parent=parent) progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtWidgets.QMessageBox.critical(parent, 'Image', '{}'.format(''.join(errors))) return path else: path = destination_path return path
def getDiskImage(parent): destination_directory = os.path.join(MainWindow.instance().imagesDirPath(), "QEMU") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter(parent, "Select a QEMU disk image", destination_directory) if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "QEMU disk image", "Cannot read {}".format(path)) return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical(parent, "QEMU disk images directory", "Could not create the QEMU disk images directory {}: {}".format(destination_directory, e)) return if os.path.normpath(os.path.dirname(path)) != destination_directory: # the QEMU disk image is not in the default images directory reply = QtGui.QMessageBox.question(parent, "QEMU disk image", "Would you like to copy {} to the default images directory".format(os.path.basename(path)), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) worker = FileCopyWorker(path, destination_path) progress_dialog = ProgressDialog(worker, "QEMU disk image", "Copying {}".format(os.path.basename(path)), "Cancel", busy=True, parent=parent) progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtGui.QMessageBox.critical(parent, "QEMU disk image", "{}".format("".join(errors))) else: path = destination_path return path
def sudo(*commands, parent=None, shell=False): """ Run a command as an administrator. """ if parent is None: from ..main_window import MainWindow parent = MainWindow.instance() while True: if sys.platform.startswith("win32"): for command in commands: worker = WaitForRunAsWorker(command) progress_dialog = ProgressDialog(worker, "Run as administrator", "Executing command...", "Cancel", busy=True, parent=parent) progress_dialog.show() if not progress_dialog.exec_(): return False elif sys.platform.startswith("darwin"): cmd = [] for command in commands: command = [shlex.quote(c) for c in command] cmd.append(' '.join(command)) command = [ "osascript", "-e", "do shell script \"{}\" with administrator privileges".format( ' && '.join(cmd)) ] log.info("Execute as admin: {}".format(' '.join(command))) worker = WaitForCommandWorker(command, shell=shell) for line in worker.output().decode("utf-8", errors="ignore").splitlines(): log.info(line) progress_dialog = ProgressDialog(worker, "Run as administrator", "Executing command...", "Cancel", busy=True, parent=parent) progress_dialog.show() if not progress_dialog.exec_(): return False else: command_detail = [] for command in commands: command = [shlex.quote(c) for c in command] command_detail.append(' '.join(command)) password, ok = QtWidgets.QInputDialog.getText( parent, "Run as administrator", "Please enter your password to proceed.\nCommand:\n{}".format( '\n'.join(command_detail)), QtWidgets.QLineEdit.Password, "") if not ok: return False try: # check the password is valid subprocess.check_output(["sudo", "-S", "id"], input=(password + "\n").encode(), timeout=30) except subprocess.CalledProcessError: continue except (OSError, subprocess.SubprocessError) as e: QtWidgets.QMessageBox.critical( parent, "Run as administrator", "Could not execute sudo: {}".format(e)) return False # sudo shouldn't need the password again. for command in commands: waited_command = ["sudo"] waited_command.extend(command) worker = WaitForCommandWorker(waited_command, shell=shell) for line in worker.output().decode( "utf-8", errors="ignore").splitlines(): log.info(line) progress_dialog = ProgressDialog(worker, "Run as administrator", "Executing command...", "Cancel", busy=True, parent=parent) progress_dialog.show() if not progress_dialog.exec_(): return False return True
def getIOSImage(cls, parent, server): """ :param parent: parent widget :param server: The server where the image is located :return: path to the IOS image or None """ if not cls._default_images_dir: cls._default_images_dir = cls.getImageDirectory() path, _ = QtWidgets.QFileDialog.getOpenFileName(parent, "Select an IOS image", cls._default_images_dir, "All files (*.*);;IOS image (*.bin *.image)", "IOS image (*.bin *.image)") if not path: return cls._default_images_dir = os.path.dirname(path) if not os.access(path, os.R_OK): QtWidgets.QMessageBox.critical(parent, "IOS image", "Cannot read {}".format(path)) return if sys.platform.startswith('win'): # Dynamips (Cygwin actually) doesn't like non ascii paths on Windows try: path.encode('ascii') except UnicodeEncodeError: QtWidgets.QMessageBox.warning(parent, "IOS image", "The IOS image filename should contains only ascii (English) characters.") try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtWidgets.QMessageBox.critical(parent, "IOS image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 if elf_header_start != b'\x7fELF\x01\x02\x01': QtWidgets.QMessageBox.critical(parent, "IOS image", "Sorry, this is not a valid IOS image!") return try: os.makedirs(cls.getImageDirectory(), exist_ok=True) except OSError as e: QtWidgets.QMessageBox.critical(parent, "IOS images directory", "Could not create the IOS images directory {}: {}".format(cls.getImageDirectory(), e)) return compressed = False try: compressed = isIOSCompressed(path) except (OSError, ValueError): pass # ignore errors if we cannot find out the IOS image is compressed. if compressed: reply = QtWidgets.QMessageBox.question(parent, "IOS image", "Would you like to decompress this IOS image?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: decompressed_image_path = os.path.join(cls.getImageDirectory(), os.path.basename(os.path.splitext(path)[0] + ".image")) worker = DecompressIOSWorker(path, decompressed_image_path) progress_dialog = ProgressDialog(worker, "IOS image", "Decompressing IOS image {}...".format(os.path.basename(path)), "Cancel", busy=True, parent=parent) progress_dialog.show() if progress_dialog.exec_() is not False: path = decompressed_image_path path = ImageManager.instance().askCopyUploadImage(parent, path, server, "DYNAMIPS") return path
def getIOSImage(parent): """ :param parent: parent widget :return: path to the IOS image or None """ destination_directory = os.path.join(MainWindow.instance().settings()["images_path"], "IOS") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter(parent, "Select an IOS image", destination_directory, "All files (*.*);;IOS image (*.bin *.image)", "IOS image (*.bin *.image)") if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "IOS image", "Cannot read {}".format(path)) return if sys.platform.startswith('win'): # Dynamips (Cygwin acutally) doesn't like non ascii paths on Windows try: path.encode('ascii') except UnicodeEncodeError: QtGui.QMessageBox.warning(parent, "IOS image", "The IOS image filename should contains only ascii (English) characters.") try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtGui.QMessageBox.critical(parent, "IOS image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 if elf_header_start != b'\x7fELF\x01\x02\x01': QtGui.QMessageBox.critical(parent, "IOS image", "Sorry, this is not a valid IOS image!") return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical(parent, "IOS images directory", "Could not create the IOS images directory {}: {}".format(destination_directory, str(e))) return if isIOSCompressed(path): reply = QtGui.QMessageBox.question(parent, "IOS image", "Would you like to uncompress this IOS image?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: uncompressed_image_path = os.path.join(destination_directory, os.path.basename(os.path.splitext(path)[0] + ".image")) thread = UncompressIOSThread(path, uncompressed_image_path) progress_dialog = ProgressDialog(thread, "IOS image", "Uncompressing IOS image {}...".format(os.path.basename(path)), "Cancel", busy=True, parent=parent) progress_dialog.show() if progress_dialog.exec_() is not False: path = uncompressed_image_path thread.wait() if os.path.dirname(path) != destination_directory: # the IOS image is not in the default images directory new_destination_path = os.path.join(destination_directory, os.path.basename(path)) try: # try to create a symbolic link to it symlink_path = new_destination_path os.symlink(path, symlink_path) path = symlink_path except (OSError, NotImplementedError): # if unsuccessful, then copy the IOS image itself try: shutil.copyfile(path, new_destination_path) path = new_destination_path except OSError: pass return path
def _iosImageBrowserSlot(self): """ Slot to open a file browser and select an IOS image. """ destination_directory = os.path.join(self._main_window.settings()["images_path"], "IOS") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter(self, "Select an IOS image", destination_directory, "All files (*.*);;IOS image (*.bin *.image)", "IOS image (*.bin *.image)") if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(self, "IOS image", "Cannot read {}".format(path)) return if sys.platform.startswith('win'): # Dynamips (Cygwin acutally) doesn't like non ascii paths on Windows try: path.encode('ascii') except UnicodeEncodeError: QtGui.QMessageBox.warning(self, "IOS image", "The IOS image filename should contains only ascii (English) characters.") try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtGui.QMessageBox.critical(self, "IOS image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 if elf_header_start != b'\x7fELF\x01\x02\x01': QtGui.QMessageBox.critical(self, "IOS image", "Sorry, this is not a valid IOS image!") return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical(self, "IOS images directory", "Could not create the IOS images directory {}: {}".format(destination_directory, str(e))) return if isIOSCompressed(path): reply = QtGui.QMessageBox.question(self, "IOS image", "Would you like to uncompress this IOS image?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: uncompressed_image_path = os.path.join(destination_directory, os.path.basename(os.path.splitext(path)[0] + ".image")) thread = UncompressIOSThread(path, uncompressed_image_path) progress_dialog = ProgressDialog(thread, "IOS image", "Uncompressing IOS image {}...".format(path), "Cancel", busy=True, parent=self) progress_dialog.show() if progress_dialog.exec_() is not False: path = uncompressed_image_path thread.wait() if os.path.dirname(path) != destination_directory: # the IOS image is not in the default images directory new_destination_path = os.path.join(destination_directory, os.path.basename(path)) try: # try to create a symbolic link to it symlink_path = new_destination_path os.symlink(path, symlink_path) path = symlink_path except (OSError, NotImplementedError): # if unsuccessful, then copy the IOS image itself try: shutil.copyfile(path, new_destination_path) path = new_destination_path except OSError: pass self.uiIOSPathLineEdit.clear() self.uiIOSPathLineEdit.setText(path) # try to guess the platform image = os.path.basename(path) match = re.match("^(c[0-9]+)\\-\w+", image) if not match: QtGui.QMessageBox.warning(self, "IOS image", "Could not detect the platform, make sure this is a valid IOS image!") return detected_platform = match.group(1) detected_chassis = "" # IOS images for the 3600 platform start with the chassis name (c3620 etc.) for platform, chassis in CHASSIS.items(): if detected_platform[1:] in chassis: detected_chassis = detected_platform[1:] detected_platform = platform break if detected_platform not in PLATFORMS_DEFAULT_RAM: QtGui.QMessageBox.warning(self, "IOS image", "This IOS image is for the {} platform/chassis and is not supported by this application!".format(detected_platform)) return index = self.uiPlatformComboBox.findText(detected_platform) if index != -1: self.uiPlatformComboBox.setCurrentIndex(index) index = self.uiChassisComboBox.findText(detected_chassis) if index != -1: self.uiChassisComboBox.setCurrentIndex(index) self.uiRAMSpinBox.setValue(PLATFORMS_DEFAULT_RAM[detected_platform])
def getIOUImage(parent): """ :param parent: parent widget :return: path to the IOU image or None """ destination_directory = os.path.join(MainWindow.instance().imagesDirPath(), "IOU") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter(parent, "Select an IOU image", destination_directory, "All files (*)", "IOU image (*.bin *.image)") if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "IOU image", "Cannot read {}".format(path)) return try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtGui.QMessageBox.critical(parent, "IOU image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, little endian and have an ELF version of 1 # normal IOS image are big endian! if elf_header_start != b'\x7fELF\x01\x01\x01': QtGui.QMessageBox.critical(parent, "IOU image", "Sorry, this is not a valid IOU image!") return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical(parent, "IOU images directory", "Could not create the IOU images directory {}: {}".format(destination_directory, e)) return if os.path.normpath(os.path.dirname(path)) != destination_directory: # the IOU image is not in the default images directory reply = QtGui.QMessageBox.question(parent, "IOU image", "Would you like to copy {} to the default images directory".format(os.path.basename(path)), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) thread = FileCopyThread(path, destination_path) progress_dialog = ProgressDialog(thread, "Project", "Copying {}".format(os.path.basename(path)), "Cancel", busy=True, parent=parent) thread.deleteLater() progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtGui.QMessageBox.critical(parent, "IOS image", "{}".format("".join(errors))) else: path = destination_path mode = os.stat(path).st_mode os.chmod(path, mode | stat.S_IXUSR) if not os.access(path, os.X_OK): QtGui.QMessageBox.warning(parent, "IOU image", "{} is not executable".format(path)) return path
def getIOSImage(parent): """ :param parent: parent widget :return: path to the IOS image or None """ destination_directory = os.path.join(MainWindow.instance().imagesDirPath(), "IOS") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter(parent, "Select an IOS image", destination_directory, "All files (*.*);;IOS image (*.bin *.image)", "IOS image (*.bin *.image)") if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "IOS image", "Cannot read {}".format(path)) return if sys.platform.startswith('win'): # Dynamips (Cygwin acutally) doesn't like non ascii paths on Windows try: path.encode('ascii') except UnicodeEncodeError: QtGui.QMessageBox.warning(parent, "IOS image", "The IOS image filename should contains only ascii (English) characters.") try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtGui.QMessageBox.critical(parent, "IOS image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 if elf_header_start != b'\x7fELF\x01\x02\x01': QtGui.QMessageBox.critical(parent, "IOS image", "Sorry, this is not a valid IOS image!") return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical(parent, "IOS images directory", "Could not create the IOS images directory {}: {}".format(destination_directory, e)) return compressed = False try: compressed = isIOSCompressed(path) except (OSError, ValueError): pass # ignore errors if we cannot find out the IOS image is compressed. if compressed: reply = QtGui.QMessageBox.question(parent, "IOS image", "Would you like to decompress this IOS image?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: decompressed_image_path = os.path.join(destination_directory, os.path.basename(os.path.splitext(path)[0] + ".image")) worker = DecompressIOSWorker(path, decompressed_image_path) progress_dialog = ProgressDialog(worker, "IOS image", "Decompressing IOS image {}...".format(os.path.basename(path)), "Cancel", busy=True, parent=parent) progress_dialog.show() if progress_dialog.exec_() is not False: path = decompressed_image_path if os.path.normpath(os.path.dirname(path)) != destination_directory: # the IOS image is not in the default images directory reply = QtGui.QMessageBox.question(parent, "IOS image", "Would you like to copy {} to the default images directory".format(os.path.basename(path)), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) worker = FileCopyWorker(path, destination_path) progress_dialog = ProgressDialog(worker, "IOS image", "Copying {}".format(os.path.basename(path)), "Cancel", busy=True, parent=parent) progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtGui.QMessageBox.critical(parent, "IOS image", "{}".format("".join(errors))) else: path = destination_path return path
def sudo(*commands, parent=None, shell=False): """ Run a command as an administrator. """ if parent is None: from ..main_window import MainWindow parent = MainWindow.instance() while True: if sys.platform.startswith("win32"): for command in commands: worker = WaitForRunAsWorker(command) progress_dialog = ProgressDialog(worker, "Run as administrator", "Executing command...", "Cancel", busy=True, parent=parent) progress_dialog.show() if not progress_dialog.exec_(): return False elif sys.platform.startswith("darwin"): cmd = [] for command in commands: command = [shlex.quote(c) for c in command] cmd.append(' '.join(command)) command = ["osascript", "-e", "do shell script \"{}\" with administrator privileges".format(' && '.join(cmd))] log.info("Execute as admin: {}".format(' '.join(command))) worker = WaitForCommandWorker(command, shell=shell) for line in worker.output().decode("utf-8", errors="ignore").splitlines(): log.info(line) progress_dialog = ProgressDialog(worker, "Run as administrator", "Executing command...", "Cancel", busy=True, parent=parent) progress_dialog.show() if not progress_dialog.exec_(): return False else: command_detail = [] for command in commands: command = [shlex.quote(c) for c in command] command_detail.append(' '.join(command)) password, ok = QtWidgets.QInputDialog.getText(parent, "Run as administrator", "Please enter your password to proceed.\nCommand:\n{}".format('\n'.join(command_detail)), QtWidgets.QLineEdit.Password, "") if not ok: return False try: # check the password is valid subprocess.check_output(["sudo", "-S", "id"], input=(password + "\n").encode(), timeout=30) except subprocess.CalledProcessError: continue except (OSError, subprocess.SubprocessError) as e: QtWidgets.QMessageBox.critical(parent, "Run as administrator", "Could not execute sudo: {}".format(e)) return False # sudo shouldn't need the password again. for command in commands: waited_command = ["sudo"] waited_command.extend(command) worker = WaitForCommandWorker(waited_command, shell=shell) for line in worker.output().decode("utf-8", errors="ignore").splitlines(): log.info(line) progress_dialog = ProgressDialog(worker, "Run as administrator", "Executing command...", "Cancel", busy=True, parent=parent) progress_dialog.show() if not progress_dialog.exec_(): return False return True
def getIOUImage(parent): """ :param parent: parent widget :return: path to the IOU image or None """ destination_directory = os.path.join( MainWindow.instance().imagesDirPath(), "IOU") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter( parent, "Select an IOU image", destination_directory, "All files (*)", "IOU image (*.bin *.image)") if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "IOU image", "Cannot read {}".format(path)) return try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtGui.QMessageBox.critical( parent, "IOU image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, little endian and have an ELF version of 1 # normal IOS image are big endian! if elf_header_start != b'\x7fELF\x01\x01\x01': QtGui.QMessageBox.critical( parent, "IOU image", "Sorry, this is not a valid IOU image!") return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical( parent, "IOU images directory", "Could not create the IOU images directory {}: {}".format( destination_directory, e)) return if os.path.normpath(os.path.dirname(path)) != destination_directory: # the IOU image is not in the default images directory reply = QtGui.QMessageBox.question( parent, "IOU image", "Would you like to copy {} to the default images directory". format(os.path.basename(path)), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) thread = FileCopyThread(path, destination_path) progress_dialog = ProgressDialog(thread, "Project", "Copying {}".format( os.path.basename(path)), "Cancel", busy=True, parent=parent) thread.deleteLater() progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtGui.QMessageBox.critical(parent, "IOS image", "{}".format("".join(errors))) else: path = destination_path mode = os.stat(path).st_mode os.chmod(path, mode | stat.S_IXUSR) if not os.access(path, os.X_OK): QtGui.QMessageBox.warning(parent, "IOU image", "{} is not executable".format(path)) return path
def getIOSImage(parent): """ :param parent: parent widget :return: path to the IOS image or None """ destination_directory = os.path.join( MainWindow.instance().imagesDirPath(), "IOS") path, _ = QtGui.QFileDialog.getOpenFileNameAndFilter( parent, "Select an IOS image", destination_directory, "All files (*.*);;IOS image (*.bin *.image)", "IOS image (*.bin *.image)") if not path: return if not os.access(path, os.R_OK): QtGui.QMessageBox.critical(parent, "IOS image", "Cannot read {}".format(path)) return if sys.platform.startswith('win'): # Dynamips (Cygwin acutally) doesn't like non ascii paths on Windows try: path.encode('ascii') except UnicodeEncodeError: QtGui.QMessageBox.warning( parent, "IOS image", "The IOS image filename should contains only ascii (English) characters." ) try: with open(path, "rb") as f: # read the first 7 bytes of the file. elf_header_start = f.read(7) except OSError as e: QtGui.QMessageBox.critical( parent, "IOS image", "Cannot read ELF magic number: {}".format(e)) return # file must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1 if elf_header_start != b'\x7fELF\x01\x02\x01': QtGui.QMessageBox.critical( parent, "IOS image", "Sorry, this is not a valid IOS image!") return try: os.makedirs(destination_directory) except FileExistsError: pass except OSError as e: QtGui.QMessageBox.critical( parent, "IOS images directory", "Could not create the IOS images directory {}: {}".format( destination_directory, e)) return if isIOSCompressed(path): reply = QtGui.QMessageBox.question( parent, "IOS image", "Would you like to decompress this IOS image?", QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: decompressed_image_path = os.path.join( destination_directory, os.path.basename(os.path.splitext(path)[0] + ".image")) thread = DecompressIOSThread(path, decompressed_image_path) progress_dialog = ProgressDialog( thread, "IOS image", "Decompressing IOS image {}...".format( os.path.basename(path)), "Cancel", busy=True, parent=parent) progress_dialog.show() if progress_dialog.exec_() is not False: path = decompressed_image_path thread.wait() if os.path.normpath(os.path.dirname(path)) != destination_directory: # the IOS image is not in the default images directory reply = QtGui.QMessageBox.question( parent, "IOS image", "Would you like to copy {} to the default images directory". format(os.path.basename(path)), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: destination_path = os.path.join(destination_directory, os.path.basename(path)) thread = FileCopyThread(path, destination_path) progress_dialog = ProgressDialog(thread, "IOS image", "Copying {}".format( os.path.basename(path)), "Cancel", busy=True, parent=parent) thread.deleteLater() progress_dialog.show() progress_dialog.exec_() errors = progress_dialog.errors() if errors: QtGui.QMessageBox.critical(parent, "IOS image", "{}".format("".join(errors))) else: path = destination_path return path