├── .gitignore ├── .travis.yml ├── .whitesource ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cli └── main.cpp ├── common ├── FileHelpers.cpp └── FileHelpers.h ├── config ├── GlobalConfig.cpp ├── GlobalConfig.h ├── PlatformInfo.cpp ├── PlatformInfo.h ├── QemuList.cpp ├── QemuList.h ├── RecordReplayParams.cpp ├── RecordReplayParams.h ├── VMConfig.cpp └── VMConfig.h ├── device ├── Device.cpp ├── Device.h ├── DeviceBus.cpp ├── DeviceBus.h ├── DeviceFactory.cpp ├── DeviceFactory.h ├── DeviceNetwork.cpp ├── DeviceNetwork.h ├── DeviceStorage.cpp ├── DeviceStorage.h ├── DeviceSystem.cpp ├── DeviceSystem.h ├── DeviceUsb.cpp └── DeviceUsb.h ├── docs ├── Using qemu-gui.md └── imgs │ ├── create_vm.png │ ├── recordreplay.png │ └── vm_settings.png ├── gui ├── AddDeviceForm.cpp ├── AddDeviceForm.h ├── ConnectionSettingsForm.cpp ├── ConnectionSettingsForm.h ├── ConsoleTab.cpp ├── ConsoleTab.h ├── CreateVMForm.cpp ├── CreateVMForm.h ├── DeviceForm.cpp ├── DeviceForm.h ├── QemuGUI.cpp ├── QemuGUI.h ├── QemuGUI.qrc ├── QemuGUICommon.h ├── QemuInstallationsForm.cpp ├── QemuInstallationsForm.h ├── RecordReplayTab.cpp ├── RecordReplayTab.h ├── Resources │ ├── create.png │ ├── create_disable.png │ ├── import.png │ ├── import_disable.png │ ├── pause.png │ ├── pause_disable.png │ ├── play.png │ ├── play_disable.png │ ├── qemu.png │ ├── replay.png │ ├── run_options.png │ ├── run_options_mini.png │ ├── settings.png │ ├── settings_disable.png │ ├── stop.png │ └── stop_disable.png ├── TerminalSettingsForm.cpp ├── TerminalSettingsForm.h ├── TerminalTab.cpp ├── TerminalTab.h ├── VMPropertiesForm.cpp ├── VMPropertiesForm.h ├── VMSettingsForm.cpp ├── VMSettingsForm.h └── main.cpp ├── platform files ├── arm.xml └── i386.xml └── qemu ├── CommandLineParameters.cpp ├── CommandLineParameters.h ├── PlatformInformationReader.cpp ├── PlatformInformationReader.h ├── QMPInteraction.cpp ├── QMPInteraction.h ├── QemuImgLauncher.cpp ├── QemuImgLauncher.h ├── QemuLauncher.cpp ├── QemuLauncher.h ├── QemuRunOptions.cpp ├── QemuRunOptions.h ├── QemuSocket.cpp └── QemuSocket.h /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | moc_*.h 24 | qrc_*.cpp 25 | ui_*.h 26 | Makefile* 27 | *build-* 28 | 29 | # QtCreator 30 | 31 | *.autosave 32 | 33 | # QtCtreator Qml 34 | *.qmlproject.user 35 | *.qmlproject.user.* 36 | 37 | # QtCtreator CMake 38 | CMakeLists.txt.user* 39 | 40 | # VS code 41 | .vscode/* 42 | build/* 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | os: 4 | - linux 5 | 6 | install: 7 | - sudo apt-get update 8 | - sudo apt-get install qt5-default qt5-qmake 9 | - sudo apt-get install cppcheck 10 | 11 | before_script: 12 | - mkdir build 13 | - cd build 14 | - cmake .. 15 | 16 | script: 17 | - make 18 | - cppcheck --version 19 | - cppcheck -f -q --enable=all --std=c++11 --error-exitcode=1 ../gui ../device ../qemu ../cli ../config 20 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "checkRunSettings": { 3 | "vulnerableCheckRunConclusionLevel": "failure" 4 | }, 5 | "issueSettings": { 6 | "minSeverityLevel": "LOW" 7 | } 8 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0) 2 | 3 | project(qemu-gui) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | set(CMAKE_AUTOMOC ON) 7 | set(CMAKE_AUTORCC ON) 8 | set(CMAKE_CXX_STANDARD 11) 9 | 10 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 11 | add_definitions(-DQT_NO_DEBUG_OUTPUT) 12 | endif() 13 | 14 | # Find the QtWidgets library 15 | find_package(Qt5Widgets) 16 | find_package(Qt5Network) 17 | 18 | include_directories(gui device config qemu) 19 | 20 | add_executable(qemu-gui 21 | common/FileHelpers.cpp 22 | 23 | config/GlobalConfig.cpp config/VMConfig.cpp config/PlatformInfo.cpp 24 | config/RecordReplayParams.cpp config/QemuList.cpp 25 | 26 | device/Device.cpp device/DeviceBus.cpp device/DeviceStorage.cpp 27 | device/DeviceFactory.cpp device/DeviceSystem.cpp 28 | device/DeviceUsb.cpp device/DeviceNetwork.cpp 29 | 30 | qemu/QemuRunOptions.cpp qemu/QemuLauncher.cpp qemu/QemuImgLauncher.cpp 31 | qemu/CommandLineParameters.cpp qemu/QMPInteraction.cpp 32 | qemu/PlatformInformationReader.cpp qemu/QemuSocket.cpp 33 | 34 | gui/main.cpp gui/CreateVMForm.cpp gui/QemuGUI.cpp 35 | gui/RecordReplayTab.cpp gui/VMSettingsForm.cpp gui/QemuGUI.qrc 36 | gui/TerminalSettingsForm.cpp 37 | gui/TerminalTab.cpp gui/ConnectionSettingsForm.cpp 38 | gui/ConsoleTab.cpp 39 | gui/VMPropertiesForm.cpp 40 | gui/AddDeviceForm.cpp 41 | gui/DeviceForm.cpp gui/QemuInstallationsForm.cpp 42 | ) 43 | 44 | target_link_libraries(qemu-gui Qt5::Widgets Qt5::Network) 45 | target_compile_definitions(qemu-gui PUBLIC GUI) 46 | 47 | 48 | add_executable(qemu-cli cli/main.cpp 49 | common/FileHelpers.cpp 50 | 51 | config/GlobalConfig.cpp config/VMConfig.cpp config/QemuList.cpp 52 | config/PlatformInfo.cpp config/RecordReplayParams.cpp 53 | 54 | device/Device.cpp device/DeviceBus.cpp device/DeviceStorage.cpp device/DeviceSystem.cpp 55 | device/DeviceUsb.cpp device/DeviceNetwork.cpp device/DeviceFactory.cpp 56 | 57 | qemu/PlatformInformationReader.cpp qemu/QemuRunOptions.cpp qemu/QemuLauncher.cpp 58 | qemu/QemuImgLauncher.cpp qemu/CommandLineParameters.cpp 59 | qemu/QMPInteraction.cpp qemu/QemuSocket.cpp 60 | ) 61 | target_link_libraries(qemu-cli Qt5::Core Qt5::Gui Qt5::Network) 62 | 63 | 64 | 65 | install(TARGETS qemu-gui 66 | RUNTIME DESTINATION bin) 67 | install(TARGETS qemu-cli 68 | RUNTIME DESTINATION bin) 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qemu-gui — GUI for running and recording QEMU virtual machines 2 | 3 | Building and running the project: 4 | ```shell 5 | git clone https://github.com/ispras/qemu-gui 6 | mkdir qemu-gui-build 7 | cd qemu-gui-build 8 | cmake ../qemu-gui 9 | make 10 | ./qemu-gui 11 | ``` 12 | 13 | See more details in [User guide](docs/Using%20qemu-gui.md) 14 | -------------------------------------------------------------------------------- /cli/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "GlobalConfig.h" 3 | #include "CommandLineParameters.h" 4 | #include "QemuList.h" 5 | #include "qemu/QemuRunOptions.h" 6 | #include "qemu/QemuLauncher.h" 7 | 8 | QTextStream out(stdout); 9 | 10 | void usage() 11 | { 12 | out << "qemu-cli usage:\n" 13 | "qemulist - output configured QEMU installations\n" 14 | "qemuadd - add new QEMU installation\n" 15 | "qemudel - remove QEMU installation\n" 16 | "vmlist - output configured VMs\n" 17 | "vm cmdline [(record | replay) []]" 18 | " - output command line for running specified VM\n" 19 | "vm executions - list the recorded executions\n" 20 | "vm replay - replay the specified execution\n"; 21 | } 22 | 23 | int vmlist() 24 | { 25 | foreach(VMConfig *vm, GlobalConfig::get_exist_vm()) 26 | { 27 | out << "===============================\n"; 28 | out << vm->get_vm_info(); 29 | } 30 | return 0; 31 | } 32 | 33 | int qemulist() 34 | { 35 | QemuList::Items q = QemuList::getAllQemuInstallations(); 36 | foreach(QString name, q.keys()) 37 | { 38 | out << name << " : " << q.value(name) << "\n"; 39 | } 40 | return 0; 41 | } 42 | 43 | int qemuadd(const char *name, const char *path) 44 | { 45 | if (QemuList::getQemuDir(name) != "") 46 | { 47 | out << "Insallation " << name << " already exists\n"; 48 | return 1; 49 | } 50 | 51 | QemuList::addQemuInstallation(name, path); 52 | } 53 | 54 | int qemudel(const char *name) 55 | { 56 | QemuList::delQemuInstallation(name); 57 | } 58 | 59 | int vmcmdline(VMConfig *vm, LaunchMode mode, const char *execution) 60 | { 61 | CommandLineParameters params(mode); 62 | params.setOverlayEnabled(false); 63 | QString res = vm->getCommandLine(params); 64 | if (execution && mode == LaunchMode::REPLAY) 65 | { 66 | RecordReplayParams rr = vm->getRRParams(execution); 67 | res += rr.getCommandLine(mode); 68 | res = QemuList::getQemuExecutablePath(rr.getQemu(), vm->getPlatform()) + " " + res; 69 | } 70 | out << res << "\n"; 71 | return 0; 72 | } 73 | 74 | int replaylist(VMConfig *vm) 75 | { 76 | QStringList rr = vm->getReplayList(); 77 | out << "Recorded executions for " << vm->get_name() << " VM:\n"; 78 | foreach(QString s, rr) 79 | { 80 | out << "\t" << s << "\n"; 81 | } 82 | return 0; 83 | } 84 | 85 | int replay(VMConfig *vm, const char *rr) 86 | { 87 | RecordReplayParams params = vm->getRRParams(rr); 88 | QemuRunOptions opt; 89 | 90 | QemuLauncher launcher(params.getQemu(), vm, opt, LaunchMode::REPLAY, params); 91 | launcher.start_qemu(); 92 | 93 | return 0; 94 | } 95 | 96 | int main(int argc, char *argv[]) 97 | { 98 | if (argc < 2) 99 | { 100 | usage(); 101 | return 0; 102 | } 103 | 104 | if (!strcmp(argv[1], "vmlist")) 105 | { 106 | return vmlist(); 107 | } 108 | else if (!strcmp(argv[1], "qemulist")) 109 | { 110 | return qemulist(); 111 | } 112 | else if (!strcmp(argv[1], "qemuadd")) 113 | { 114 | if (argc < 4) 115 | { 116 | usage(); 117 | return 1; 118 | } 119 | return qemuadd(argv[2], argv[3]); 120 | } 121 | else if (!strcmp(argv[1], "qemudel")) 122 | { 123 | if (argc < 3) 124 | { 125 | usage(); 126 | return 1; 127 | } 128 | return qemudel(argv[2]); 129 | } 130 | else if (!strcmp(argv[1], "vm")) 131 | { 132 | if (argc < 4) 133 | { 134 | usage(); 135 | return 1; 136 | } 137 | 138 | VMConfig *vm = GlobalConfig::get_vm_by_name(argv[2]); 139 | if (!vm) 140 | { 141 | out << "VM " << argv[2] << " does not exist\n"; 142 | return 1; 143 | } 144 | 145 | if (!strcmp(argv[3], "cmdline")) 146 | { 147 | LaunchMode mode = LaunchMode::NORMAL; 148 | char **arg = argv + 4; 149 | const char *exec = nullptr; 150 | while (*arg) 151 | { 152 | if (!strcmp(*arg, "record")) 153 | { 154 | mode = LaunchMode::RECORD; 155 | } 156 | else if (!strcmp(*arg, "replay")) 157 | { 158 | mode = LaunchMode::REPLAY; 159 | } 160 | else if (!exec && mode == LaunchMode::REPLAY) 161 | { 162 | exec = *arg; 163 | } 164 | else 165 | { 166 | usage(); 167 | return 1; 168 | } 169 | ++arg; 170 | } 171 | return vmcmdline(vm, mode, exec); 172 | } 173 | else if (!strcmp(argv[3], "executions")) 174 | { 175 | return replaylist(vm); 176 | } 177 | else if (!strcmp(argv[3], "replay")) 178 | { 179 | if (argc < 5) 180 | { 181 | usage(); 182 | return 1; 183 | } 184 | return replay(vm, argv[4]); 185 | } 186 | } 187 | 188 | usage(); 189 | 190 | return 0; 191 | } -------------------------------------------------------------------------------- /common/FileHelpers.cpp: -------------------------------------------------------------------------------- 1 | #include "FileHelpers.h" 2 | 3 | namespace FileHelpers { 4 | 5 | static void deleteDirectoryRec(const QDir &dir) 6 | { 7 | int res = 0; 8 | QStringList dirs = dir.entryList(QDir::Dirs | QDir::AllDirs | QDir::NoDotAndDotDot); 9 | QStringList files = dir.entryList(QDir::Files); 10 | 11 | foreach(const QString f_name, files) 12 | { 13 | QString del_file = dir.absolutePath() + "/" + f_name; 14 | if (!QFile::remove(del_file)) 15 | qDebug() << "File" << del_file << "was not deleted!"; 16 | } 17 | 18 | foreach(QString d_name, dirs) 19 | { 20 | deleteDirectoryRec(QDir(dir.absolutePath() + "/" + d_name)); 21 | } 22 | 23 | QDir().rmdir(dir.absolutePath()); 24 | } 25 | 26 | void deleteDirectory(const QString &path) 27 | { 28 | QDir dir(path); 29 | if (dir.exists()) 30 | { 31 | deleteDirectoryRec(dir); 32 | } 33 | } 34 | 35 | void createDirectory(const QString &path) 36 | { 37 | QDir dir(path); 38 | if (!dir.exists()) 39 | { 40 | dir.mkpath(path); 41 | } 42 | } 43 | 44 | }; 45 | -------------------------------------------------------------------------------- /common/FileHelpers.h: -------------------------------------------------------------------------------- 1 | #ifndef FILEHELPERS_H 2 | #define FILEHELPERS_H 3 | 4 | #include 5 | 6 | namespace FileHelpers 7 | { 8 | void deleteDirectory(const QString &path); 9 | void createDirectory(const QString &path); 10 | }; 11 | 12 | #endif // FILEHELPERS_H 13 | -------------------------------------------------------------------------------- /config/GlobalConfig.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "GlobalConfig.h" 3 | #include "QemuList.h" 4 | 5 | const QString xml_vm_directory = "VMDirectory"; 6 | const QString xml_vm_directory_item = "Dir"; 7 | const QString xml_terminal_settings = "TerminalSettings"; 8 | const QString xml_terminal_backgroud = "BackgroundColor"; 9 | const QString xml_terminal_text_color = "TextColor"; 10 | const QString xml_terminal_font_family = "FontFamily"; 11 | const QString xml_terminal_font_size = "FontSize"; 12 | const QString xml_qmp_port = "QMPPort"; 13 | const QString xml_monitor_port = "MonitorPort"; 14 | const QString xml_qemu_installation = "QemuInstallation"; 15 | 16 | // default values 17 | const QString qmp_port_default = "2323"; 18 | const QString monitor_port_default = "2424"; 19 | const QString bckgrnd_color_default = "#000000"; 20 | const QString text_color_default = "#00ff00"; 21 | const QString font_family_default = "Courier New"; 22 | const QString font_size_default = "12"; 23 | 24 | 25 | GlobalConfig::GlobalConfig() 26 | { 27 | port_qmp = qmp_port_default; 28 | port_monitor = monitor_port_default; 29 | terminal_parameters_background = bckgrnd_color_default; 30 | terminal_parameters_text_color = text_color_default; 31 | terminal_parameters_font_family = font_family_default; 32 | terminal_parameters_font_size = font_size_default; 33 | 34 | QDir home_dir(get_home_dir()); 35 | if (!home_dir.exists()) 36 | { 37 | home_dir.mkdir(get_home_dir()); 38 | } 39 | vm_config_file = new QFile(get_home_dir() + "/VMconfig.conf"); 40 | if (!vm_config_file->exists()) 41 | { 42 | vm_config_file->open(QIODevice::Append); 43 | vm_config_file->close(); 44 | } 45 | else 46 | { 47 | if (vm_config_file->open(QIODevice::ReadOnly)) 48 | { 49 | QXmlStreamReader xmlReader(vm_config_file); 50 | 51 | xmlReader.readNext(); 52 | 53 | while (!xmlReader.atEnd()) 54 | { 55 | if (xmlReader.isStartElement()) 56 | { 57 | if (xmlReader.name() == xml_vm_directory) 58 | { 59 | xmlReader.readNextStartElement(); 60 | while (xmlReader.name() == xml_vm_directory_item) 61 | { 62 | QString path = xmlReader.readElementText(); 63 | VMConfig *vm = new VMConfig(path); 64 | virtual_machines.append(vm); 65 | xmlReader.readNextStartElement(); 66 | } 67 | } 68 | if (xmlReader.name() == xml_terminal_settings) 69 | { 70 | xmlReader.readNextStartElement(); 71 | if (xmlReader.name() == xml_terminal_backgroud) 72 | { 73 | terminal_parameters_background = xmlReader.readElementText(); 74 | xmlReader.readNextStartElement(); 75 | } 76 | if (xmlReader.name() == xml_terminal_text_color) 77 | { 78 | terminal_parameters_text_color = xmlReader.readElementText(); 79 | xmlReader.readNextStartElement(); 80 | } 81 | if (xmlReader.name() == xml_terminal_font_family) 82 | { 83 | terminal_parameters_font_family = xmlReader.readElementText(); 84 | xmlReader.readNextStartElement(); 85 | } 86 | if (xmlReader.name() == xml_terminal_font_size) 87 | { 88 | terminal_parameters_font_size = xmlReader.readElementText(); 89 | xmlReader.readNextStartElement(); 90 | } 91 | } 92 | if (xmlReader.name() == xml_qemu_installation) 93 | { 94 | current_qemu = xmlReader.readElementText(); 95 | } 96 | if (xmlReader.name() == xml_qmp_port) 97 | { 98 | port_qmp = xmlReader.readElementText(); 99 | } 100 | if (xmlReader.name() == xml_monitor_port) 101 | { 102 | port_monitor = xmlReader.readElementText(); 103 | } 104 | } 105 | xmlReader.readNext(); 106 | } 107 | vm_config_file->close(); 108 | } 109 | } 110 | } 111 | 112 | GlobalConfig &GlobalConfig::instance() 113 | { 114 | static GlobalConfig inst; 115 | return inst; 116 | } 117 | 118 | QString GlobalConfig::get_home_dir() 119 | { 120 | return QDir::homePath() + "/QemuGUI_VirtualMachines"; 121 | } 122 | 123 | QList GlobalConfig::get_exist_vm() 124 | { 125 | return instance().virtual_machines; 126 | } 127 | 128 | void GlobalConfig::set_current_qemu(const QString & qemu) 129 | { 130 | instance().current_qemu = qemu; 131 | instance().save_config_file(); 132 | } 133 | 134 | QString GlobalConfig::get_current_qemu() 135 | { 136 | return instance().current_qemu; 137 | } 138 | 139 | QString GlobalConfig::get_current_qemu_dir() 140 | { 141 | return QemuList::getQemuDir(get_current_qemu()); 142 | } 143 | 144 | void GlobalConfig::set_terminal_parameters(QColor background, QColor text_color, const QString & font_family, int font_size) 145 | { 146 | instance().terminal_parameters_background = background.name(); 147 | instance().terminal_parameters_text_color = text_color.name(); 148 | instance().terminal_parameters_font_family = font_family; 149 | instance().terminal_parameters_font_size = QString::number(font_size); 150 | instance().save_config_file(); 151 | } 152 | 153 | QColor GlobalConfig::get_terminal_backgroud() 154 | { 155 | return QColor(instance().terminal_parameters_background); 156 | } 157 | 158 | QColor GlobalConfig::get_terminal_text_color() 159 | { 160 | return QColor(instance().terminal_parameters_text_color); 161 | } 162 | 163 | QString GlobalConfig::get_terminal_font_family() 164 | { 165 | return instance().terminal_parameters_font_family; 166 | } 167 | 168 | int GlobalConfig::get_terminal_font_size() 169 | { 170 | return instance().terminal_parameters_font_size.toInt(); 171 | } 172 | 173 | QString GlobalConfig::get_port_qmp() 174 | { 175 | return instance().port_qmp; 176 | } 177 | 178 | QString GlobalConfig::get_port_monitor() 179 | { 180 | return instance().port_monitor; 181 | } 182 | 183 | void GlobalConfig::set_port_qmp(const QString &port) 184 | { 185 | instance().port_qmp = port; 186 | instance().save_config_file(); 187 | } 188 | 189 | void GlobalConfig::set_port_monitor(const QString &port) 190 | { 191 | instance().port_monitor = port; 192 | instance().save_config_file(); 193 | } 194 | 195 | VMConfig * GlobalConfig::get_vm_by_name(const QString &name) 196 | { 197 | foreach(VMConfig *vm, instance().virtual_machines) 198 | { 199 | if (vm->get_name() == name) 200 | return vm; 201 | } 202 | return nullptr; 203 | } 204 | 205 | bool GlobalConfig::save_config_file() 206 | { 207 | if (vm_config_file->open(QIODevice::WriteOnly)) 208 | { 209 | QXmlStreamWriter xmlWriter(vm_config_file); 210 | 211 | xmlWriter.setAutoFormatting(true); 212 | xmlWriter.writeStartDocument(); 213 | xmlWriter.writeStartElement("CommonParameters"); 214 | 215 | xmlWriter.writeStartElement(xml_vm_directory); 216 | foreach(VMConfig *vm, virtual_machines) 217 | { 218 | xmlWriter.writeStartElement(xml_vm_directory_item); 219 | xmlWriter.writeCharacters(vm->get_dir_path()); 220 | xmlWriter.writeEndElement(); 221 | } 222 | xmlWriter.writeEndElement(); 223 | 224 | xmlWriter.writeStartElement(xml_terminal_settings); 225 | { 226 | xmlWriter.writeStartElement(xml_terminal_backgroud); 227 | xmlWriter.writeCharacters(terminal_parameters_background); 228 | xmlWriter.writeEndElement(); 229 | 230 | xmlWriter.writeStartElement(xml_terminal_text_color); 231 | xmlWriter.writeCharacters(terminal_parameters_text_color); 232 | xmlWriter.writeEndElement(); 233 | 234 | xmlWriter.writeStartElement(xml_terminal_font_family); 235 | xmlWriter.writeCharacters(terminal_parameters_font_family); 236 | xmlWriter.writeEndElement(); 237 | 238 | xmlWriter.writeStartElement(xml_terminal_font_size); 239 | xmlWriter.writeCharacters(terminal_parameters_font_size); 240 | xmlWriter.writeEndElement(); 241 | } 242 | xmlWriter.writeEndElement(); 243 | 244 | xmlWriter.writeStartElement(xml_qemu_installation); 245 | xmlWriter.writeCharacters(current_qemu); 246 | xmlWriter.writeEndElement(); 247 | 248 | xmlWriter.writeStartElement(xml_qmp_port); 249 | xmlWriter.writeCharacters(port_qmp); 250 | xmlWriter.writeEndElement(); 251 | 252 | xmlWriter.writeStartElement(xml_monitor_port); 253 | xmlWriter.writeCharacters(port_monitor); 254 | xmlWriter.writeEndElement(); 255 | 256 | xmlWriter.writeEndElement(); 257 | xmlWriter.writeEndDocument(); 258 | vm_config_file->close(); 259 | return true; 260 | } 261 | return false; 262 | } 263 | 264 | bool GlobalConfig::add_exist_vm(const QString &path) 265 | { 266 | VMConfig *vm = new VMConfig(path); 267 | 268 | if (vm->get_name().isEmpty() || vm->get_dir_path().isEmpty()) 269 | { 270 | delete vm; 271 | return false; 272 | } 273 | 274 | foreach(VMConfig *vm_exist, instance().virtual_machines) 275 | { 276 | if (vm_exist->get_name() == vm->get_name() || vm_exist->get_dir_path() == vm->get_dir_path()) 277 | { 278 | delete vm; 279 | return false; 280 | } 281 | } 282 | instance().virtual_machines.append(vm); 283 | instance().save_config_file(); 284 | 285 | return true; 286 | } 287 | 288 | void GlobalConfig::delete_exclude_vm(const QString &del_vm_name, bool delete_vm) 289 | { 290 | foreach(VMConfig *vm, instance().virtual_machines) 291 | { 292 | if (vm->get_name() == del_vm_name) 293 | { 294 | if (delete_vm) 295 | vm->remove_directory_vm(); 296 | instance().virtual_machines.removeOne(vm); 297 | delete vm; 298 | break; 299 | } 300 | } 301 | instance().save_config_file(); 302 | } 303 | 304 | void GlobalConfig::vm_is_created(VMConfig *vm_config) 305 | { 306 | if (vm_config->save_vm_config(vm_config->get_dir_path())) 307 | { 308 | instance().virtual_machines.append(vm_config); 309 | 310 | instance().save_config_file(); 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /config/GlobalConfig.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALCONFIG_H 2 | #define GLOBALCONFIG_H 3 | 4 | #include 5 | 6 | #include "VMConfig.h" 7 | 8 | class GlobalConfig 9 | { 10 | GlobalConfig(); 11 | GlobalConfig(const GlobalConfig &) = delete; 12 | GlobalConfig &operator=(const GlobalConfig &) = delete; 13 | 14 | static GlobalConfig &instance(); 15 | 16 | public: 17 | static QString get_home_dir(); 18 | static QList get_exist_vm(); 19 | static VMConfig *get_vm_by_name(const QString &name); 20 | 21 | static bool add_exist_vm(const QString &path); 22 | static void delete_exclude_vm(const QString &del_vm_name, bool delete_vm); 23 | static void exclude_vm(const QString &del_vm_name); 24 | static void set_current_qemu(const QString &qemu); 25 | static QString get_current_qemu(); 26 | static QString get_current_qemu_dir(); 27 | 28 | static void set_terminal_parameters(QColor background, QColor text_color, const QString &font_family, int font_size); 29 | static QColor get_terminal_backgroud(); 30 | static QColor get_terminal_text_color(); 31 | static QString get_terminal_font_family(); 32 | static int get_terminal_font_size(); 33 | 34 | static QString get_port_qmp(); 35 | static QString get_port_monitor(); 36 | static void set_port_qmp(const QString &port); 37 | static void set_port_monitor(const QString &port); 38 | 39 | static void vm_is_created(VMConfig *vm_config); 40 | 41 | private: 42 | QList virtual_machines; 43 | QString terminal_parameters_background; 44 | QString terminal_parameters_text_color; 45 | QString terminal_parameters_font_family; 46 | QString terminal_parameters_font_size; 47 | QFile *vm_config_file; 48 | QString current_qemu; 49 | QString port_qmp; 50 | QString port_monitor; 51 | 52 | private: 53 | bool save_config_file(); 54 | }; 55 | 56 | #endif // GLOBALCONFIG_H 57 | -------------------------------------------------------------------------------- /config/PlatformInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "PlatformInfo.h" 2 | 3 | 4 | PlatformInfo::PlatformInfo(const QString &path) 5 | : path(path) 6 | { 7 | QFile file(path + ".xml"); 8 | if (file.open(QIODevice::ReadOnly)) 9 | { 10 | QXmlStreamReader xmlReader(&file); 11 | xmlReader.readNextStartElement(); 12 | 13 | while (xmlReader.readNextStartElement()) 14 | { 15 | if (xmlReader.name() == "Machine") 16 | { 17 | machines.append(xmlReader.readElementText()); 18 | } 19 | else if (xmlReader.name() == "Cpu") 20 | { 21 | cpus.append(xmlReader.readElementText()); 22 | } 23 | else if (xmlReader.name() == "Netdev") 24 | { 25 | netdev.append(xmlReader.readElementText()); 26 | } 27 | } 28 | } 29 | } 30 | 31 | void PlatformInfo::addMachine(const QString &s, bool isDefault) 32 | { 33 | if (isDefault) 34 | { 35 | machines.push_front(s); 36 | } 37 | else 38 | { 39 | machines.append(s); 40 | } 41 | } 42 | 43 | void PlatformInfo::addCpu(const QString &s) 44 | { 45 | cpus.append(s); 46 | } 47 | 48 | void PlatformInfo::addNetdev(const QString &s) 49 | { 50 | netdev.append(s); 51 | } 52 | 53 | void PlatformInfo::saveXml() const 54 | { 55 | QFile file(path + ".xml"); 56 | if (file.open(QIODevice::WriteOnly)) 57 | { 58 | QXmlStreamWriter xmlWriter(&file); 59 | xmlWriter.setAutoFormatting(true); 60 | xmlWriter.writeStartDocument(); 61 | xmlWriter.writeStartElement("Platform"); 62 | 63 | foreach(QString name, machines) 64 | { 65 | xmlWriter.writeStartElement("Machine"); 66 | xmlWriter.writeCharacters(name); 67 | xmlWriter.writeEndElement(); 68 | } 69 | 70 | xmlWriter.writeStartElement("Cpu"); 71 | xmlWriter.writeCharacters("default"); 72 | xmlWriter.writeEndElement(); 73 | 74 | foreach(QString name, cpus) 75 | { 76 | xmlWriter.writeStartElement("Cpu"); 77 | xmlWriter.writeCharacters(name); 78 | xmlWriter.writeEndElement(); 79 | } 80 | 81 | foreach(QString name, netdev) 82 | { 83 | xmlWriter.writeStartElement("Netdev"); 84 | xmlWriter.writeCharacters(name); 85 | xmlWriter.writeEndElement(); 86 | } 87 | 88 | xmlWriter.writeEndElement(); 89 | xmlWriter.writeEndDocument(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /config/PlatformInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORMINFORMATION_H 2 | #define PLATFORMINFORMATION_H 3 | 4 | #include 5 | 6 | class PlatformInfo 7 | { 8 | public: 9 | explicit PlatformInfo(const QString &path); 10 | 11 | const QStringList &getMachines() const { return machines; } 12 | const QStringList &getCpus() const { return cpus; } 13 | const QStringList &getNetdev() const { return netdev; } 14 | 15 | void addMachine(const QString &s, bool isDefault = false); 16 | void addCpu(const QString &s); 17 | void addNetdev(const QString &s); 18 | 19 | void saveXml() const; 20 | 21 | private: 22 | QString path; 23 | QStringList machines; 24 | QStringList cpus; 25 | QStringList netdev; 26 | }; 27 | 28 | 29 | #endif // PLATFORMINFORMATION_H 30 | 31 | -------------------------------------------------------------------------------- /config/QemuList.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuList.h" 2 | #include "GlobalConfig.h" 3 | #include "common/FileHelpers.h" 4 | #include "PlatformInformationReader.h" 5 | 6 | const QString configName = "Qemu.conf"; 7 | const QString platformPrefix = "/platforms/qemu_"; 8 | const QString xml_qemu_intallation = "QEMUInstallation"; 9 | const QString xml_qemu_installation_name = "Name"; 10 | const QString xml_qemu_installation_path = "Path"; 11 | 12 | QemuList::QemuList() 13 | { 14 | loadConfig(); 15 | } 16 | 17 | QemuList &QemuList::instance() 18 | { 19 | static QemuList inst; 20 | return inst; 21 | } 22 | 23 | QString QemuList::getQemuProfilePath(const QString &name) 24 | { 25 | return GlobalConfig::get_home_dir() + platformPrefix + name; 26 | } 27 | 28 | void QemuList::addQemuInstallation(const QString &name, const QString &path) 29 | { 30 | /* Add QEMU to the list to allow other classes request it's path */ 31 | instance().qemuList.insert(name, path); 32 | new PlatformInformationReader(name); 33 | 34 | instance().saveConfig(); 35 | } 36 | 37 | void QemuList::delQemuInstallation(const QString &name) 38 | { 39 | instance().qemuList.remove(name); 40 | instance().saveConfig(); 41 | FileHelpers::deleteDirectory(GlobalConfig::get_home_dir() + platformPrefix + name); 42 | } 43 | 44 | QString QemuList::getQemuDir(const QString &name) 45 | { 46 | return instance().qemuList.value(name); 47 | } 48 | 49 | QString QemuList::getQemuExecutablePath(const QString &qemu, const QString &platform) 50 | { 51 | return getQemuDir(qemu) 52 | #ifdef Q_OS_WIN 53 | + "/" + "qemu-system-" + platform + "w.exe"; 54 | #else 55 | + "/" + "qemu-system-" + platform; 56 | #endif 57 | } 58 | 59 | const QemuList::Items &QemuList::getAllQemuInstallations() 60 | { 61 | return instance().qemuList; 62 | } 63 | 64 | void QemuList::loadConfig() 65 | { 66 | QFile file(GlobalConfig::get_home_dir() + "/" + configName); 67 | if (file.open(QIODevice::ReadOnly)) 68 | { 69 | QXmlStreamReader xmlReader(&file); 70 | xmlReader.readNextStartElement(); 71 | 72 | while (!xmlReader.atEnd()) 73 | { 74 | if (xmlReader.name() == xml_qemu_intallation) 75 | { 76 | xmlReader.readNextStartElement(); 77 | QString name, path; 78 | if (xmlReader.name() == xml_qemu_installation_name) 79 | { 80 | name = xmlReader.readElementText(); 81 | xmlReader.readNextStartElement(); 82 | } 83 | if (xmlReader.name() == xml_qemu_installation_path) 84 | { 85 | path = xmlReader.readElementText(); 86 | xmlReader.readNextStartElement(); 87 | } 88 | if (!name.isEmpty() && !path.isEmpty()) 89 | { 90 | qemuList.insert(name, path); 91 | } 92 | } 93 | xmlReader.readNext(); 94 | } 95 | } 96 | } 97 | 98 | void QemuList::saveConfig() 99 | { 100 | QFile file(GlobalConfig::get_home_dir() + "/" + configName); 101 | if (file.open(QIODevice::WriteOnly)) 102 | { 103 | QXmlStreamWriter xmlWriter(&file); 104 | xmlWriter.setAutoFormatting(true); 105 | xmlWriter.writeStartDocument(); 106 | xmlWriter.writeStartElement("QemuList"); 107 | 108 | for (auto it = qemuList.begin() ; it != qemuList.end() ; ++it) 109 | { 110 | xmlWriter.writeStartElement(xml_qemu_intallation); 111 | xmlWriter.writeStartElement(xml_qemu_installation_name); 112 | xmlWriter.writeCharacters(it.key()); 113 | xmlWriter.writeEndElement(); 114 | xmlWriter.writeStartElement(xml_qemu_installation_path); 115 | xmlWriter.writeCharacters(it.value()); 116 | xmlWriter.writeEndElement(); 117 | xmlWriter.writeEndElement(); 118 | } 119 | xmlWriter.writeEndElement(); 120 | xmlWriter.writeEndDocument(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /config/QemuList.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMULIST_H 2 | #define QEMULIST_H 3 | 4 | #include 5 | 6 | class QemuList 7 | { 8 | private: 9 | QemuList(); 10 | QemuList(const QemuList &) = delete; 11 | QemuList &operator=(const QemuList &) = delete; 12 | static QemuList &instance(); 13 | 14 | public: 15 | typedef QMap Items; 16 | 17 | static void addQemuInstallation(const QString &name, const QString &path); 18 | static void delQemuInstallation(const QString &name); 19 | static QString getQemuDir(const QString &name); 20 | static QString getQemuExecutablePath(const QString &qemu, const QString &platform); 21 | static QString getQemuProfilePath(const QString &name); 22 | static const Items &getAllQemuInstallations(); 23 | 24 | private: 25 | void loadConfig(); 26 | void saveConfig(); 27 | 28 | private: 29 | Items qemuList; 30 | }; 31 | 32 | #endif // QEMULIST_H 33 | -------------------------------------------------------------------------------- /config/RecordReplayParams.cpp: -------------------------------------------------------------------------------- 1 | #include "RecordReplayParams.h" 2 | #include "GlobalConfig.h" 3 | #include "PlatformInformationReader.h" 4 | 5 | static const QString constXmlName = "replay.xml"; 6 | static const QString dummyName = "dummy.qcow2"; 7 | static const QString xml_qemu = "Qemu"; 8 | static const QString xml_icount = "icount"; 9 | static const QString xml_overlay = "IsOverlay"; 10 | static const QString xml_start = "replay"; 11 | 12 | RecordReplayParams::RecordReplayParams() 13 | : icount(5), snapshotPeriod(0), initialSnapshot("init") 14 | { 15 | } 16 | 17 | void RecordReplayParams::createXml() const 18 | { 19 | QFile file(currentDir + "/" + constXmlName); 20 | if (file.open(QIODevice::WriteOnly)) 21 | { 22 | QXmlStreamWriter xmlWriter(&file); 23 | xmlWriter.setAutoFormatting(true); 24 | xmlWriter.writeStartDocument(); 25 | xmlWriter.writeStartElement(xml_start); 26 | 27 | xmlWriter.writeStartElement(xml_qemu); 28 | xmlWriter.writeCharacters(qemu); 29 | xmlWriter.writeEndElement(); 30 | 31 | xmlWriter.writeStartElement(xml_icount); 32 | xmlWriter.writeCharacters(QString::number(icount)); 33 | xmlWriter.writeEndElement(); 34 | 35 | xmlWriter.writeStartElement(xml_overlay); 36 | xmlWriter.writeCharacters(overlay ? "true" : ""); 37 | xmlWriter.writeEndElement(); 38 | 39 | xmlWriter.writeEndElement(); 40 | xmlWriter.writeEndDocument(); 41 | } 42 | } 43 | 44 | void RecordReplayParams::readXml() 45 | { 46 | QFile file(currentDir + "/" + constXmlName); 47 | if (file.open(QIODevice::ReadOnly)) 48 | { 49 | QXmlStreamReader xmlReader(&file); 50 | xmlReader.readNextStartElement(); 51 | Q_ASSERT(xmlReader.name() == xml_start); 52 | 53 | while (xmlReader.readNextStartElement()) 54 | { 55 | if (xmlReader.name() == xml_qemu) 56 | { 57 | qemu = xmlReader.readElementText(); 58 | } 59 | else if (xmlReader.name() == xml_icount) 60 | { 61 | icount = xmlReader.readElementText().toInt(); 62 | } 63 | else if (xmlReader.name() == xml_overlay) 64 | { 65 | overlay = !xmlReader.readElementText().isEmpty(); 66 | } 67 | } 68 | } 69 | } 70 | 71 | QString RecordReplayParams::getCommandLine(LaunchMode mode) const 72 | { 73 | QString initSnapshotCmd = overlay ? ",rrsnapshot=" + initialSnapshot : ""; 74 | QString rr = mode == LaunchMode::RECORD ? "record" : "replay"; 75 | QString res = "-icount shift=" + QString::number(icount) 76 | + ",rr=" + rr + ",rrfile=" + 77 | "\"" + currentDir + "/replay.bin\"" + initSnapshotCmd; 78 | if (snapshotPeriod) 79 | { 80 | res += ",rrperiod=" + QString::number(snapshotPeriod); 81 | } 82 | if (mode != LaunchMode::NORMAL) 83 | { 84 | res += " -drive file=" + currentDir 85 | + "/" + dummyName + ",if=none"; 86 | } 87 | return res; 88 | } 89 | 90 | QString RecordReplayParams::getDummyImage() const 91 | { 92 | return currentDir + "/" + dummyName; 93 | } 94 | -------------------------------------------------------------------------------- /config/RecordReplayParams.h: -------------------------------------------------------------------------------- 1 | #ifndef RECORDREPLAYPARAMS_H 2 | #define RECORDREPLAYPARAMS_H 3 | 4 | #include 5 | #include "CommandLineParameters.h" 6 | 7 | class RecordReplayParams 8 | { 9 | public: 10 | RecordReplayParams(); 11 | 12 | void createXml() const; 13 | void readXml(); 14 | 15 | QString getCommandLine(LaunchMode mode) const; 16 | QString getDummyImage() const; 17 | 18 | const QString &getCurrentDir() const { return currentDir; } 19 | void setCurrentDir(const QString &dir) { currentDir = dir; } 20 | const QString &getQemu() const { return qemu; } 21 | void setQemu(const QString &value) { qemu = value; } 22 | bool isOverlayEnabled() const { return overlay; } 23 | void setOverlayEnabled(bool value) { overlay = value; } 24 | int getIcount() const { return icount; } 25 | void setIcount(int value) { icount = value; } 26 | int getSnapshotPeriod() const { return snapshotPeriod; } 27 | void setSnapshotPeriod(int value) { snapshotPeriod = value; } 28 | const QString &getInitialSnapshot() const { return initialSnapshot; } 29 | void setInitialSnapshot(const QString &value) { initialSnapshot = value; } 30 | 31 | private: 32 | QString currentDir; 33 | QString qemu; 34 | bool overlay; 35 | int icount; 36 | int snapshotPeriod; 37 | QString initialSnapshot; 38 | }; 39 | 40 | #endif // RECORDREPLAYPARAMS_H 41 | -------------------------------------------------------------------------------- /config/VMConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "VMConfig.h" 2 | #include "DeviceStorage.h" 3 | #include "DeviceSystem.h" 4 | #include "DeviceUsb.h" 5 | #include "common/FileHelpers.h" 6 | 7 | const QString const_xml_name = "vm.xml"; 8 | const QString xml_parameters = "VMParameters"; 9 | const QString xml_field_name = "Name"; 10 | const QString xml_field_dir = "Directory_path"; 11 | const QString xml_field_img = "Image_path"; 12 | const QString xml_platform = "Platform"; 13 | const QString xml_cmdLine = "AdditionCommandLine"; 14 | const QString xml_kernel = "Kernel"; 15 | const QString xml_initrd = "InitialRamDisk"; 16 | 17 | 18 | VMConfig::VMConfig(const QString &path_vm) 19 | : system("System") 20 | { 21 | list_of_vm_file = NULL; 22 | system.setRemovable(false); 23 | path = path_vm; 24 | QString xml_name; 25 | if (path_vm.section('/', -1) != const_xml_name) 26 | { 27 | dir_path = path; 28 | path = path + "/" + const_xml_name; 29 | } 30 | else 31 | { 32 | dir_path = path; 33 | dir_path.chop(const_xml_name.size()); 34 | } 35 | 36 | readVMConfig(); 37 | } 38 | 39 | VMConfig::~VMConfig() 40 | { 41 | 42 | } 43 | 44 | void VMConfig::createVMFolder(const QString &path) const 45 | { 46 | QDir vm_dir(path); 47 | if (!vm_dir.exists()) 48 | { 49 | QDir().mkdir(path); 50 | } 51 | } 52 | 53 | void VMConfig::readVMConfig() 54 | { 55 | QFile file(path); 56 | if (file.open(QIODevice::ReadOnly)) 57 | { 58 | QXmlStreamReader xmlReader(&file); 59 | 60 | xmlReader.readNextStartElement(); 61 | Q_ASSERT(xmlReader.name() == xml_parameters); 62 | 63 | while (xmlReader.readNextStartElement()) 64 | { 65 | if (xmlReader.name() == xml_field_name) 66 | { 67 | name_vm = xmlReader.readElementText(); 68 | } 69 | else if (xmlReader.name() == xml_platform) 70 | { 71 | platform = xmlReader.readElementText(); 72 | } 73 | else if (xmlReader.name() == xml_cmdLine) 74 | { 75 | addCmdLine = xmlReader.readElementText(); 76 | } 77 | else if (xmlReader.name() == xml_kernel) 78 | { 79 | kernel = xmlReader.readElementText(); 80 | } 81 | else if (xmlReader.name() == xml_initrd) 82 | { 83 | initrd = xmlReader.readElementText(); 84 | } 85 | else /* Device */ 86 | { 87 | system.read(xmlReader); 88 | } 89 | } 90 | } 91 | else 92 | { 93 | /* Default config */ 94 | } 95 | } 96 | 97 | bool VMConfig::save_vm_config(const QString &path) const 98 | { 99 | createVMFolder(path); 100 | 101 | QString xml_name; 102 | xml_name = path + "/" + const_xml_name; 103 | 104 | QFile file(xml_name); 105 | if (file.open(QIODevice::WriteOnly)) 106 | { 107 | QXmlStreamWriter xmlWriter(&file); 108 | 109 | xmlWriter.setAutoFormatting(true); 110 | xmlWriter.writeStartDocument(); 111 | xmlWriter.writeStartElement(xml_parameters); 112 | 113 | xmlWriter.writeStartElement(xml_field_name); 114 | xmlWriter.writeCharacters(name_vm); 115 | xmlWriter.writeEndElement(); 116 | 117 | xmlWriter.writeStartElement(xml_platform); 118 | xmlWriter.writeCharacters(platform); 119 | xmlWriter.writeEndElement(); 120 | 121 | xmlWriter.writeStartElement(xml_cmdLine); 122 | xmlWriter.writeCharacters(addCmdLine); 123 | xmlWriter.writeEndElement(); 124 | 125 | xmlWriter.writeStartElement(xml_kernel); 126 | xmlWriter.writeCharacters(kernel); 127 | xmlWriter.writeEndElement(); 128 | 129 | xmlWriter.writeStartElement(xml_initrd); 130 | xmlWriter.writeCharacters(initrd); 131 | xmlWriter.writeEndElement(); 132 | 133 | system.save(xmlWriter); 134 | 135 | xmlWriter.writeEndElement(); 136 | xmlWriter.writeEndDocument(); 137 | file.close(); 138 | return true; 139 | } 140 | return false; 141 | } 142 | 143 | void VMConfig::save_vm_config() const 144 | { 145 | save_vm_config(dir_path); 146 | } 147 | 148 | void VMConfig::set_name(const QString &name_vm_) 149 | { 150 | name_vm = name_vm_; 151 | } 152 | 153 | void VMConfig::setCmdLine(const QString &cmdLine) 154 | { 155 | addCmdLine = cmdLine; 156 | } 157 | 158 | void VMConfig::addDefaultBus(const QString &image) 159 | { 160 | Device *pci = new DevicePciController(&system); 161 | pci->setRemovable(false); 162 | Device *ide = new DeviceIdeController(pci); 163 | ide->setRemovable(false); 164 | if (!image.isEmpty()) 165 | { 166 | new DeviceIdeHd(image, ide->getDevices().at(0)); 167 | } 168 | } 169 | 170 | void VMConfig::addDeviceMemory(const QString &size) 171 | { 172 | (new DeviceMemory(size, &system))->setRemovable(false); 173 | } 174 | 175 | void VMConfig::addDeviceMachine(const QString &name) 176 | { 177 | (new DeviceMachine(name, &system))->setRemovable(false); 178 | } 179 | 180 | void VMConfig::addDeviceCpu(const QString &name) 181 | { 182 | (new DeviceCpu(name, &system))->setRemovable(false); 183 | } 184 | 185 | void VMConfig::setKernel(const QString &name) 186 | { 187 | kernel = name; 188 | } 189 | 190 | void VMConfig::setInitrd(const QString &name) 191 | { 192 | initrd = name; 193 | } 194 | 195 | void VMConfig::addUsbDevice() 196 | { 197 | qDebug() << "---usb" << (new DeviceUsb(&system))->getDeviceTypeName(); 198 | //save_vm_config(); 199 | } 200 | 201 | QString VMConfig::get_vm_info() 202 | { 203 | QString info = "Name: " + name_vm + "\n" + "Directory: " + dir_path + "\n" + 204 | "Platform: " + platform + "\n"; 205 | QString kernelInfo = (!kernel.isEmpty()) ? "Kernel: " + kernel + "\n" : ""; 206 | QString initrdInfo = (!initrd.isEmpty()) ? "Initial ram disk: " + initrd + "\n" : ""; 207 | info += (kernelInfo + initrdInfo); 208 | info += system.getCommonDeviceInfo(); 209 | return info; 210 | } 211 | 212 | void VMConfig::setPlatform(const QString &platformVM) 213 | { 214 | platform = platformVM; 215 | } 216 | 217 | QString VMConfig::getPlatform() 218 | { 219 | return platform; 220 | } 221 | 222 | QString VMConfig::getMachine() 223 | { 224 | foreach(Device *dev, system.getDevices()) 225 | { 226 | if (dev->getDeviceTypeName() == "DeviceMachine") 227 | { 228 | DeviceMachine *machine = dynamic_cast(dev); 229 | return machine->getName(); 230 | } 231 | } 232 | return ""; 233 | } 234 | 235 | QString VMConfig::get_name() 236 | { 237 | return name_vm; 238 | } 239 | 240 | QString VMConfig::getKernel() 241 | { 242 | return kernel; 243 | } 244 | 245 | QString VMConfig::getInitrd() 246 | { 247 | return initrd; 248 | } 249 | 250 | QString VMConfig::getCmdLine() 251 | { 252 | return addCmdLine; 253 | } 254 | 255 | QString VMConfig::get_dir_path() 256 | { 257 | return dir_path; 258 | } 259 | 260 | QString VMConfig::getCommandLine(CommandLineParameters &cmdParams) 261 | { 262 | return QString(" -net none") 263 | + (kernel.isEmpty() ? "" : " -kernel " + kernel) 264 | + (initrd.isEmpty() ? "" : " -initrd " + initrd) 265 | + system.getCommandLine(cmdParams) + " " + addCmdLine; 266 | } 267 | 268 | QString VMConfig::getPathRRDir() 269 | { 270 | return get_dir_path() + "/RecordReplay"; 271 | } 272 | 273 | RecordReplayParams VMConfig::getRRParams(const QString &exec) 274 | { 275 | RecordReplayParams params; 276 | params.setCurrentDir(getPathRRDir() + "/" + exec); 277 | params.readXml(); 278 | return params; 279 | } 280 | 281 | void VMConfig::remove_directory_vm() 282 | { 283 | FileHelpers::deleteDirectory(dir_path); 284 | } 285 | 286 | QStringList VMConfig::getReplayList() 287 | { 288 | QDir rrDir(getPathRRDir()); 289 | QStringList dirs = rrDir.entryList(QDir::Dirs | QDir::AllDirs | QDir::Filter::NoDotAndDotDot); 290 | return dirs; 291 | } 292 | -------------------------------------------------------------------------------- /config/VMConfig.h: -------------------------------------------------------------------------------- 1 | #ifndef VMCONFIG_H 2 | #define VMCONFIG_H 3 | 4 | #include 5 | 6 | #include "Device.h" 7 | #include "config/RecordReplayParams.h" 8 | 9 | class CommandLineParameters; 10 | 11 | class VMConfig 12 | { 13 | public: 14 | VMConfig(const QString &path); 15 | ~VMConfig(); 16 | 17 | public: 18 | void readVMConfig(); 19 | bool save_vm_config(const QString &path) const; 20 | void save_vm_config() const; 21 | void createVMFolder(const QString &path) const; 22 | void set_name(const QString &name_vm_); 23 | void setCmdLine(const QString &cmdLine); 24 | void addDefaultBus(const QString &image); 25 | void addDeviceMemory(const QString &size); 26 | void addDeviceMachine(const QString &name); 27 | void addDeviceCpu(const QString &name); 28 | void setKernel(const QString &name); 29 | void setInitrd(const QString &name); 30 | void addUsbDevice(); 31 | QString get_vm_info(); 32 | 33 | void setPlatform(const QString &platformVM); 34 | QString getPlatform(); 35 | QString getMachine(); 36 | 37 | QString get_name(); 38 | QString getKernel(); 39 | QString getInitrd(); 40 | QString getCmdLine(); 41 | QString get_dir_path(); 42 | QString getCommandLine(CommandLineParameters &cmdParams); 43 | Device *getSystemDevice() { return &system; } 44 | QString getPathRRDir(); 45 | RecordReplayParams getRRParams(const QString &exec); 46 | QStringList getReplayList(); 47 | 48 | void remove_directory_vm(); 49 | 50 | private: 51 | QFile *list_of_vm_file; 52 | 53 | QString path; 54 | QString name_vm; 55 | QString kernel; 56 | QString initrd; 57 | QString dir_path; 58 | QString platform; 59 | QString addCmdLine; 60 | Device system; 61 | }; 62 | 63 | #endif //VMCONFIG_H 64 | 65 | -------------------------------------------------------------------------------- /device/Device.cpp: -------------------------------------------------------------------------------- 1 | #include "Device.h" 2 | #include "DeviceFactory.h" 3 | 4 | /* 5 | 6 | Device properties: 7 | - parent bus type 8 | - child buses 9 | - type of children 10 | - number of children 11 | */ 12 | 13 | static const char xml_name[] = "Name"; 14 | static const char xml_removable[] = "removable"; 15 | static const char xml_cmdLine[] = "CmdLineOption"; 16 | 17 | Device::Device() 18 | { 19 | init(); 20 | } 21 | 22 | Device::Device(const QString &n, Device *parent) 23 | : QObject(NULL), name(n), additionalCmdOption("") 24 | { 25 | init(); 26 | if (parent) 27 | parent->addDevice(this); 28 | } 29 | 30 | void Device::init() 31 | { 32 | static int lastId = 0; 33 | 34 | id = "device-" + QString::number(lastId++); 35 | isCanRemove = true; 36 | } 37 | 38 | void Device::addDevice(Device *dev) 39 | { 40 | devices.append(dev); 41 | dev->setParent(this); 42 | } 43 | 44 | void Device::removeDevice(Device *dev) 45 | { 46 | devices.removeOne(dev); 47 | } 48 | 49 | QString Device::getDescription() const 50 | { 51 | return name; 52 | } 53 | 54 | QString Device::getCommonDeviceInfo() 55 | { 56 | QString res = getDeviceInfo(); 57 | foreach(Device *dev, devices) 58 | { 59 | res += dev->getCommonDeviceInfo(); 60 | } 61 | return res; 62 | } 63 | 64 | void Device::save(QXmlStreamWriter &xml) const 65 | { 66 | xml.writeStartElement(getDeviceTypeName()); 67 | 68 | xml.writeStartElement(xml_name); 69 | if (isCanRemove) 70 | { 71 | xml.writeAttribute(xml_removable, "true"); 72 | } 73 | xml.writeCharacters(name); 74 | xml.writeEndElement(); 75 | 76 | if (isCanRemove) 77 | { 78 | xml.writeStartElement(xml_cmdLine); 79 | xml.writeCharacters(getAddtionalCommandLineOption()); 80 | xml.writeEndElement(); 81 | } 82 | 83 | saveParameters(xml); 84 | 85 | foreach(Device *dev, devices) 86 | dev->save(xml); 87 | 88 | xml.writeEndElement(); 89 | } 90 | 91 | void Device::read(QXmlStreamReader &xml) 92 | { 93 | Q_ASSERT(xml.isStartElement() && xml.name() == getDeviceTypeName()); 94 | 95 | xml.readNextStartElement(); 96 | Q_ASSERT(xml.name() == xml_name); 97 | if (xml.attributes().empty()) 98 | isCanRemove = false; 99 | name = xml.readElementText(); 100 | 101 | if (isCanRemove) 102 | { 103 | xml.readNextStartElement(); 104 | Q_ASSERT(xml.name() == xml_cmdLine); 105 | setAdditionalCommandLineOption(xml.readElementText()); 106 | } 107 | 108 | readParameters(xml); 109 | 110 | // default children 111 | foreach(Device *dev, devices) 112 | { 113 | xml.readNextStartElement(); 114 | dev->read(xml); 115 | } 116 | 117 | while (xml.readNextStartElement()) 118 | { 119 | Device *dev = DeviceFactory::createDevice(QString().append(xml.name())); 120 | addDevice(dev); 121 | dev->read(xml); 122 | } 123 | } 124 | 125 | QString Device::getCommandLine(CommandLineParameters &cmdParams) 126 | { 127 | QString addCmdOpt = additionalCmdOption.isEmpty() ? "" : "," + additionalCmdOption; 128 | QString res = getCommandLineOption(cmdParams) + addCmdOpt; 129 | foreach(Device *dev, devices) 130 | res += dev->getCommandLine(cmdParams); 131 | return res; 132 | } 133 | -------------------------------------------------------------------------------- /device/Device.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_H 2 | #define DEVICE_H 3 | 4 | #include 5 | #ifdef GUI 6 | #include 7 | #endif 8 | 9 | class Device; 10 | class CommandLineParameters; 11 | 12 | enum class BusType 13 | { 14 | None, 15 | System, 16 | IDE, 17 | PCI, 18 | SCSI, 19 | }; 20 | 21 | typedef QList Devices; 22 | 23 | class Device : public QObject 24 | { 25 | Q_OBJECT 26 | public: 27 | Device(); 28 | Device(const QString &n, Device *parent = 0); 29 | 30 | void addDevice(Device *dev); 31 | void removeDevice(Device *dev); 32 | const Devices &getDevices() const { return devices; } 33 | QString getDescription() const; 34 | QString getCommandLine(CommandLineParameters &cmdParams); 35 | void setAdditionalCommandLineOption(const QString &cmd) { additionalCmdOption = cmd; } 36 | QString getAddtionalCommandLineOption() const { return additionalCmdOption; } 37 | QString getCommonDeviceInfo(); 38 | 39 | void save(QXmlStreamWriter &xml) const; 40 | void read(QXmlStreamReader &xml); 41 | 42 | virtual QString getDeviceTypeName() const { return "Device"; } 43 | #ifdef GUI 44 | virtual QWidget *getEditorForm() { return NULL; } 45 | #endif 46 | virtual bool isDeviceValid() { return true; } 47 | virtual bool isRemovable() { return isCanRemove; } 48 | void setRemovable(bool isRemove) { isCanRemove = isRemove; } 49 | virtual bool isDeviceInvisible() { return false; } 50 | 51 | virtual BusType providesBus() const { return BusType::None; } 52 | virtual BusType needsBus() const { return BusType::None; } 53 | 54 | virtual int getMaxCountDevices() const { return std::numeric_limits::max(); } 55 | 56 | const QString &getId() const { return id; } 57 | void setPathToConfig(const QString &path) { pathToConfig = path; } 58 | QString getPathToConfig() const { return pathToConfig; } 59 | 60 | protected: 61 | void setId(const QString &s) { id = s; } 62 | 63 | virtual void saveParameters(QXmlStreamWriter &xml) const {}; 64 | virtual void readParameters(QXmlStreamReader &xml) {}; 65 | 66 | /** 67 | *getCommandLineOption* 68 | function returns command line for each device in which it is implemented. 69 | order of options sequence is important. for example, if you make command 70 | line for storage device, option '-device' must be in the end of string, 71 | because we have opportunity to add additional options in the right. 72 | **/ 73 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams) { return ""; } 74 | virtual QString getDeviceInfo() { return ""; } 75 | 76 | private: 77 | void init(); 78 | 79 | private: 80 | QString name; 81 | QString additionalCmdOption; 82 | // Device id for the command line. 83 | // Does not need to be saved in the config file. 84 | QString id; 85 | bool isCanRemove; 86 | Devices devices; 87 | QString pathToConfig; 88 | }; 89 | 90 | #endif // DEVICE_H 91 | -------------------------------------------------------------------------------- /device/DeviceBus.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceBus.h" 2 | #include "DeviceStorage.h" 3 | 4 | DeviceBus::DeviceBus(const QString &n, Device *parent) 5 | : Device(n, parent) 6 | { 7 | 8 | } 9 | 10 | const char DeviceBusIde::typeName[] = "DeviceBusIde"; 11 | 12 | DeviceBusIde::DeviceBusIde(int n, DeviceIdeController *parent) 13 | : DeviceBus(QString("ide.%1").arg(n), parent), num(n) 14 | { 15 | 16 | } 17 | 18 | 19 | //const char DeviceBusPci::typeName[] = "DeviceBusPci"; 20 | 21 | //DeviceBusPci::DeviceBusPci(int n, DevicePciController *parent) 22 | // : DeviceBus(QString("pci.%1").arg(num), parent), num(n) 23 | //{ 24 | // 25 | //} 26 | -------------------------------------------------------------------------------- /device/DeviceBus.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICEBUS_H 2 | #define DEVICEBUS_H 3 | 4 | #include "Device.h" 5 | 6 | class DeviceStorageController; 7 | class DeviceIdeController; 8 | class DevicePciController; 9 | 10 | class DeviceBus : public Device 11 | { 12 | public: 13 | DeviceBus(const QString &n, Device *parent); 14 | 15 | virtual QString getDeviceTypeName() const = 0; 16 | virtual int getMaxCountDevices() const { return 1; } 17 | }; 18 | 19 | class DeviceBusIde : public DeviceBus 20 | { 21 | public: 22 | static const char typeName[]; 23 | 24 | DeviceBusIde(int n, DeviceIdeController *parent); 25 | 26 | virtual QString getDeviceTypeName() const { return typeName; } 27 | 28 | virtual BusType providesBus() const { return BusType::IDE; } 29 | 30 | int getNumber() const { return num; } 31 | private: 32 | int num; 33 | }; 34 | 35 | 36 | //class DeviceBusPci : public DeviceBus 37 | //{ 38 | //public: 39 | // static const char typeName[]; 40 | // 41 | // DeviceBusPci(int n, DevicePciController *parent); 42 | // 43 | // virtual QString getDeviceTypeName() const { return typeName; } 44 | // 45 | // virtual BusType providesBus() const { return BusType::PCI; } 46 | // 47 | // int getNumber() const { return num; } 48 | //private: 49 | // int num; 50 | //}; 51 | 52 | #endif // DEVICEBUS_H 53 | -------------------------------------------------------------------------------- /device/DeviceFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceFactory.h" 2 | #include "DeviceStorage.h" 3 | #include "DeviceSystem.h" 4 | #include "DeviceUsb.h" 5 | 6 | namespace DeviceFactory 7 | { 8 | 9 | Device *createDevice(const QString &name) 10 | { 11 | auto create = Internal::getDeviceRegistry().value(name); 12 | if (create) 13 | return create(); 14 | 15 | return new Device(); 16 | } 17 | 18 | 19 | Devices getDevicesForBus(BusType t) 20 | { 21 | Devices res; 22 | Internal::DeviceRegistry ® = Internal::getDeviceRegistry(); 23 | foreach(auto create, reg) 24 | { 25 | Device *d = create(); 26 | if (d->needsBus() == t) 27 | { 28 | res.append(d); 29 | } 30 | else 31 | { 32 | delete d; 33 | } 34 | } 35 | return res; 36 | } 37 | 38 | 39 | QWidget *getDeviceEditorForm() 40 | { 41 | return NULL; 42 | } 43 | 44 | 45 | namespace Internal 46 | { 47 | 48 | DeviceRegistry &getDeviceRegistry() 49 | { 50 | static DeviceRegistry reg; 51 | return reg; 52 | } 53 | 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /device/DeviceFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICEFACTORY_H 2 | #define DEVICEFACTORY_H 3 | 4 | #include 5 | #include "Device.h" 6 | 7 | namespace DeviceFactory 8 | { 9 | Device *createDevice(const QString &name); 10 | Devices getDevicesForBus(BusType t); 11 | 12 | namespace Internal 13 | { 14 | typedef Device * (*CreateDeviceFunc)(); 15 | typedef QMap DeviceRegistry; 16 | DeviceRegistry &getDeviceRegistry(); 17 | 18 | template 19 | Device *createDevice() 20 | { 21 | return new T; 22 | } 23 | 24 | template 25 | class RegistryEntry 26 | { 27 | public: 28 | RegistryEntry(const QString &name) 29 | { 30 | getDeviceRegistry().insert(name, createDevice); 31 | } 32 | }; 33 | } 34 | } 35 | 36 | #define REGISTER_DEVICE(TYPE) \ 37 | namespace DeviceFactory \ 38 | { \ 39 | namespace Internal \ 40 | { \ 41 | static RegistryEntry reg_##TYPE(TYPE::typeName); \ 42 | } \ 43 | } 44 | 45 | #endif // DEVICEFACTORY_H 46 | -------------------------------------------------------------------------------- /device/DeviceNetwork.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceNetwork.h" 2 | #include "DeviceFactory.h" 3 | #ifdef GUI 4 | #include "DeviceForm.h" 5 | #endif 6 | #include "CommandLineParameters.h" 7 | #include "PlatformInfo.h" 8 | 9 | 10 | const char DeviceNetworkController::typeName[] = "DeviceNetworkController"; 11 | const char DeviceNetworkController::deviceName[] = "Network adapter"; 12 | 13 | static const char xml_controller[] = "Controller"; 14 | static const char xml_netdev[] = "NetworkDevice"; 15 | static const char xml_tapIfName[] = "TapIfName"; 16 | 17 | static const char noNetdev[] = "unplugged"; 18 | REGISTER_DEVICE(DeviceNetworkController) 19 | 20 | 21 | DeviceNetworkController::DeviceNetworkController() 22 | : Device(deviceName, NULL) 23 | { 24 | initDefault(); 25 | } 26 | 27 | DeviceNetworkController::DeviceNetworkController(const QString &n, Device *parent) 28 | : Device(deviceName, parent) 29 | { 30 | initDefault(); 31 | } 32 | 33 | void DeviceNetworkController::initDefault() 34 | { 35 | controller = ""; 36 | netdev = getNetdevBackend().first(); 37 | } 38 | 39 | #ifdef GUI 40 | QWidget *DeviceNetworkController::getEditorForm() 41 | { 42 | return new DeviceNetworkForm(this); 43 | } 44 | #endif 45 | 46 | const QStringList DeviceNetworkController::getControllers() const 47 | { 48 | PlatformInfo pi(getPathToConfig()); 49 | return pi.getNetdev(); 50 | } 51 | 52 | const QStringList &DeviceNetworkController::getNetdevBackend() const 53 | { 54 | static QStringList netdev = { "user", "tap", noNetdev }; 55 | return netdev; 56 | } 57 | 58 | QString DeviceNetworkController::getCommandLineOption(CommandLineParameters &cmdParams) 59 | { 60 | if (netdev.compare(noNetdev) != 0) 61 | { 62 | QString netdevCmd = " -netdev " + netdev + ",id=" + getId(); 63 | QString devCmd = " -device " + controller + ",netdev=" + getId(); 64 | QString tapCmd = netdevCmd + ",ifname=" + tapIfName + 65 | ",script=no,downscript=no" + devCmd; 66 | QString netAllCmd = netdevCmd + devCmd; 67 | QString rrCmd = ""; 68 | if (cmdParams.getLaunchMode() != LaunchMode::NORMAL) 69 | { 70 | rrCmd = " -object filter-replay,id=replay,netdev=" + getId(); 71 | } 72 | if (netdev.compare("tap") != 0) 73 | { 74 | return netAllCmd + rrCmd; 75 | } 76 | else 77 | { 78 | return tapCmd + rrCmd; 79 | } 80 | } 81 | else 82 | { 83 | return " -device " + controller; 84 | } 85 | } 86 | 87 | void DeviceNetworkController::saveParameters(QXmlStreamWriter &xml) const 88 | { 89 | xml.writeStartElement(xml_controller); 90 | xml.writeCharacters(controller); 91 | xml.writeEndElement(); 92 | 93 | xml.writeStartElement(xml_netdev); 94 | xml.writeCharacters(netdev); 95 | xml.writeEndElement(); 96 | 97 | xml.writeStartElement(xml_tapIfName); 98 | xml.writeCharacters(tapIfName); 99 | xml.writeEndElement(); 100 | } 101 | 102 | void DeviceNetworkController::readParameters(QXmlStreamReader &xml) 103 | { 104 | xml.readNextStartElement(); 105 | Q_ASSERT(xml.name() == xml_controller); 106 | controller = xml.readElementText(); 107 | 108 | xml.readNextStartElement(); 109 | Q_ASSERT(xml.name() == xml_netdev); 110 | netdev = xml.readElementText(); 111 | 112 | xml.readNextStartElement(); 113 | Q_ASSERT(xml.name() == xml_tapIfName); 114 | tapIfName = xml.readElementText(); 115 | } 116 | 117 | QString DeviceNetworkController::getDeviceInfo() 118 | { 119 | return "Network:\n\tController: " + controller + "\n" 120 | + "\tBackend type: " + netdev + "\n"; 121 | } 122 | 123 | 124 | -------------------------------------------------------------------------------- /device/DeviceNetwork.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICENETWORK_H 2 | #define DEVICENETWORK_H 3 | 4 | #include "Device.h" 5 | 6 | 7 | class DeviceNetworkController : public Device 8 | { 9 | public: 10 | static const char typeName[]; 11 | 12 | DeviceNetworkController(); 13 | DeviceNetworkController(const QString &n, Device *parent); 14 | ~DeviceNetworkController() {} 15 | 16 | virtual QString getDeviceTypeName() const { return typeName; } 17 | virtual BusType needsBus() const { return BusType::PCI; } 18 | #ifdef GUI 19 | virtual QWidget *getEditorForm(); 20 | #endif 21 | 22 | const QStringList getControllers() const; 23 | const QStringList &getNetdevBackend() const; 24 | void setController(const QString &name) { controller = name; } 25 | void setNetdev(const QString &name) { netdev = name; } 26 | void setTapIfName(const QString &name) { tapIfName = name; } 27 | QString getCurrentController() const { return controller; } 28 | QString getCurrentNetdev() const { return netdev; } 29 | QString getCurrentTabIfName() const { return tapIfName; } 30 | 31 | protected: 32 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 33 | virtual void saveParameters(QXmlStreamWriter &xml) const; 34 | virtual void readParameters(QXmlStreamReader &xml); 35 | virtual QString getDeviceInfo(); 36 | 37 | private: 38 | void initDefault(); 39 | static const char deviceName[]; 40 | QString controller; 41 | QString netdev; 42 | QString tapIfName; 43 | 44 | }; 45 | 46 | 47 | #endif // DEVICENETWORK_H 48 | 49 | 50 | -------------------------------------------------------------------------------- /device/DeviceStorage.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceStorage.h" 2 | #include "DeviceBus.h" 3 | #include "DeviceFactory.h" 4 | #include "CommandLineParameters.h" 5 | #ifdef GUI 6 | #include "DeviceForm.h" 7 | #endif 8 | 9 | DeviceStorageController::DeviceStorageController(const QString &n, Device *parent) 10 | : Device(n, parent) 11 | { 12 | 13 | } 14 | 15 | const char DeviceIdeController::typeName[] = "DeviceIdeController"; 16 | const char DeviceIdeController::deviceName[] = "IDE"; 17 | static const char xml_removable[] = "Removable"; 18 | REGISTER_DEVICE(DeviceIdeController) 19 | 20 | DeviceIdeController::DeviceIdeController() 21 | : DeviceStorageController(deviceName, NULL) 22 | { 23 | initDefault(); 24 | } 25 | 26 | DeviceIdeController::DeviceIdeController(Device *parent) 27 | : DeviceStorageController(deviceName, parent) 28 | { 29 | initDefault(); 30 | } 31 | 32 | QString DeviceIdeController::getDeviceInfo() 33 | { 34 | return "IDE devices: \n"; 35 | } 36 | 37 | void DeviceIdeController::initDefault() 38 | { 39 | (new DeviceBusIde(0, this))->setRemovable(false); 40 | (new DeviceBusIde(1, this))->setRemovable(false); 41 | // TODO: allow non-default ide controllers 42 | setId("ide"); 43 | } 44 | 45 | 46 | const char DevicePciController::typeName[] = "DevicePciController"; 47 | REGISTER_DEVICE(DevicePciController) 48 | 49 | DevicePciController::DevicePciController(Device *parent) 50 | : DeviceStorageController("PCI", parent) 51 | { 52 | initDefault(); 53 | } 54 | 55 | void DevicePciController::initDefault() 56 | { 57 | setId("pci"); 58 | } 59 | 60 | 61 | const char DeviceScsiController::typeName[] = "DeviceScsiController"; 62 | const char DeviceScsiController::deviceName[] = "SCSI"; 63 | 64 | static const char xml_controller[] = "Controller"; 65 | REGISTER_DEVICE(DeviceScsiController) 66 | 67 | DeviceScsiController::DeviceScsiController() 68 | : DeviceStorageController(deviceName, NULL) 69 | { 70 | initDefault(); 71 | } 72 | 73 | DeviceScsiController::DeviceScsiController(Device *parent) 74 | : DeviceStorageController(deviceName, parent) 75 | { 76 | initDefault(); 77 | } 78 | 79 | #ifdef GUI 80 | QWidget *DeviceScsiController::getEditorForm() 81 | { 82 | return new DeviceScsiControllerForm(this); 83 | } 84 | #endif 85 | 86 | const QStringList &DeviceScsiController::getControllers() const 87 | { 88 | static QStringList controllers = {"mptsas1068", "lsi53c810", "lsi53c895a", 89 | "megasas", "megasas-gen2", "am53c974", "dc390"}; 90 | return controllers; 91 | } 92 | 93 | void DeviceScsiController::initDefault() 94 | { 95 | setId("scsi"); 96 | controller = getControllers().first(); 97 | } 98 | 99 | QString DeviceScsiController::getCommandLineOption(CommandLineParameters &cmdParams) 100 | { 101 | return " -device " + controller + ",id=" + getId(); 102 | } 103 | 104 | void DeviceScsiController::saveParameters(QXmlStreamWriter &xml) const 105 | { 106 | xml.writeStartElement(xml_controller); 107 | xml.writeCharacters(controller); 108 | xml.writeEndElement(); 109 | } 110 | 111 | void DeviceScsiController::readParameters(QXmlStreamReader &xml) 112 | { 113 | xml.readNextStartElement(); 114 | Q_ASSERT(xml.name() == xml_controller); 115 | controller = xml.readElementText(); 116 | } 117 | 118 | QString DeviceScsiController::getDeviceInfo() 119 | { 120 | return "SCSI controller: " + controller + "\n"; 121 | } 122 | 123 | 124 | static const char xml_image[] = "Image"; 125 | static const char xml_cmdLine[] = "CmdLineOption"; 126 | 127 | DeviceStorage::DeviceStorage(const QString &n, Device *parent) 128 | : Device(n, parent) 129 | { 130 | } 131 | 132 | void DeviceStorage::saveParameters(QXmlStreamWriter &xml) const 133 | { 134 | xml.writeStartElement(xml_image); 135 | xml.writeCharacters(getImage()); 136 | xml.writeEndElement(); 137 | } 138 | 139 | void DeviceStorage::readParameters(QXmlStreamReader &xml) 140 | { 141 | xml.readNextStartElement(); 142 | Q_ASSERT(xml.name() == xml_image); 143 | setImage(xml.readElementText()); 144 | } 145 | 146 | #ifdef GUI 147 | QWidget *DeviceStorage::getEditorForm() 148 | { 149 | return new DeviceStorageForm(this); 150 | } 151 | #endif 152 | 153 | /****************************************************************************** 154 | * IDE HDD * 155 | ******************************************************************************/ 156 | 157 | const char DeviceIdeHd::typeName[] = "DeviceIdeHd"; 158 | const char DeviceIdeHd::deviceName[] = "IDE-HD"; 159 | REGISTER_DEVICE(DeviceIdeHd) 160 | 161 | DeviceIdeHd::DeviceIdeHd() 162 | : DeviceStorage(deviceName, NULL) 163 | { 164 | } 165 | 166 | DeviceIdeHd::DeviceIdeHd(const QString &img, Device *parent) 167 | : DeviceStorage(deviceName, parent) 168 | { 169 | setImage(img); 170 | } 171 | 172 | QString DeviceIdeHd::getCommandLineOption(CommandLineParameters &cmdParams) 173 | { 174 | DeviceBusIde *bus = dynamic_cast(parent()); 175 | Q_ASSERT(bus); 176 | DeviceIdeController *ide = dynamic_cast(bus->parent()); 177 | Q_ASSERT(ide); 178 | 179 | if (cmdParams.getLaunchMode() == LaunchMode::NORMAL) 180 | { 181 | QString cmdFile = " -drive file=\"" + getImage() + "\"" + ",if=none,id=" 182 | + getId() + "-file"; 183 | return cmdFile + " -device ide-hd" 184 | +",bus=" + ide->getId() + "." + QString::number(bus->getNumber()) 185 | + ",drive=" + getId() + "-file" 186 | + ",id=" + getId(); 187 | } 188 | else 189 | { 190 | QString overlay = cmdParams.getOverlayForImage(getImage()); 191 | QString cmdFile = " -drive file=\"" + overlay + "\"" + ",if=none,id=" 192 | + getId() + "-file"; 193 | QString overlayEnabled = cmdParams.isOverlayEnabled() ? "" : ",snapshot=on"; 194 | 195 | return cmdFile + overlayEnabled + " -drive driver=blkreplay,if=none,image=" 196 | + getId() + "-file,id=" + getId() 197 | + "-driver -device ide-hd,drive=" + getId() + "-driver" 198 | +",bus=" + ide->getId() + "." + QString::number(bus->getNumber()) 199 | + ",id=" + getId(); 200 | } 201 | } 202 | 203 | bool DeviceIdeHd::isDeviceValid() 204 | { 205 | return !getImage().isEmpty(); 206 | } 207 | 208 | QString DeviceIdeHd::getDeviceInfo() 209 | { 210 | DeviceBusIde *bus = dynamic_cast(parent()); 211 | Q_ASSERT(bus); 212 | return "\tHard Disk:\n\t\tImage: " + getImage() + "\n" 213 | + "\t\tBus: " + "ide." + QString::number(bus->getNumber()) + "\n"; 214 | } 215 | 216 | 217 | /****************************************************************************** 218 | * CDROM * 219 | ******************************************************************************/ 220 | 221 | const char DeviceIdeCdrom::typeName[] = "DeviceIdeCdrom"; 222 | const char DeviceIdeCdrom::deviceName[] = "IDE-CDROM"; 223 | REGISTER_DEVICE(DeviceIdeCdrom) 224 | 225 | DeviceIdeCdrom::DeviceIdeCdrom() 226 | : DeviceStorage(deviceName, NULL) 227 | { 228 | } 229 | 230 | DeviceIdeCdrom::DeviceIdeCdrom(const QString &img, Device *parent) 231 | : DeviceStorage(deviceName, parent) 232 | { 233 | setImage(img); 234 | } 235 | 236 | QString DeviceIdeCdrom::getCommandLineOption(CommandLineParameters &cmdParams) 237 | { 238 | DeviceBusIde *bus = dynamic_cast(parent()); 239 | Q_ASSERT(bus); 240 | DeviceIdeController *ide = dynamic_cast(bus->parent()); 241 | Q_ASSERT(ide); 242 | 243 | if (cmdParams.getLaunchMode() == LaunchMode::NORMAL) 244 | { 245 | QString cmdFile = " -drive file=\"" + getImage() + "\"" + ",if=none,id=" 246 | + getId() + "-file"; 247 | return cmdFile + " -device ide-cd" 248 | + ",bus=" + ide->getId() + "." + QString::number(bus->getNumber()) 249 | + ",drive=" + getId() + "-file" 250 | + ",id=" + getId(); 251 | } 252 | else 253 | { 254 | QString overlay = cmdParams.getOverlayForImage(getImage()); 255 | QString cmdFile = " -drive file=\"" + overlay + "\"" + ",if=none,id=" 256 | + getId() + "-file"; 257 | 258 | return cmdFile + " -drive driver=blkreplay,if=none,image=" 259 | + getId() + "-file,id=" + getId() 260 | + "-driver -device ide-cd,drive=" + getId() + "-driver" 261 | + ",bus=" + ide->getId() + "." + QString::number(bus->getNumber()) 262 | + ",id=" + getId(); 263 | } 264 | } 265 | 266 | bool DeviceIdeCdrom::isDeviceValid() 267 | { 268 | return !getImage().isEmpty(); 269 | } 270 | 271 | QString DeviceIdeCdrom::getDeviceInfo() 272 | { 273 | DeviceBusIde *bus = dynamic_cast(parent()); 274 | Q_ASSERT(bus); 275 | return "\tCD-ROM:\n\t\tImage: " + getImage() + "\n" 276 | + "\t\tBus: " + "ide." + QString::number(bus->getNumber()) + "\n"; 277 | } 278 | 279 | 280 | /****************************************************************************** 281 | * SCSI HDD * 282 | ******************************************************************************/ 283 | 284 | const char DeviceScsiHd::typeName[] = "DeviceScsiHd"; 285 | const char DeviceScsiHd::deviceName[] = "SCSI-HD"; 286 | REGISTER_DEVICE(DeviceScsiHd) 287 | 288 | DeviceScsiHd::DeviceScsiHd() 289 | : DeviceStorage(deviceName, NULL) 290 | { 291 | } 292 | 293 | DeviceScsiHd::DeviceScsiHd(const QString &img, Device *parent) 294 | : DeviceStorage(deviceName, parent) 295 | { 296 | setImage(img); 297 | } 298 | 299 | QString DeviceScsiHd::getCommandLineOption(CommandLineParameters &cmdParams) 300 | { 301 | // TODO: bus? 302 | DeviceScsiController *scsi = dynamic_cast(parent()); 303 | Q_ASSERT(scsi); 304 | if (cmdParams.getLaunchMode() == LaunchMode::NORMAL) 305 | { 306 | QString cmdFile = " -drive file=\"" + getImage() + "\"" + ",if=none,id=" 307 | + getId() + "-file"; 308 | return cmdFile + " -device scsi-hd,drive=" + getId() + "-file" 309 | + ",bus=" + scsi->getId() + ".0"; 310 | } 311 | else 312 | { 313 | QString overlay = cmdParams.getOverlayForImage(getImage()); 314 | QString cmdFile = " -drive file=\"" + overlay + "\"" + ",if=none,id=" 315 | + getId() + "-file"; 316 | 317 | return cmdFile + " -drive driver=blkreplay,if=none,image=" 318 | + getId() + "-file,id=" + getId() 319 | + "-driver -device scsi-hd,drive=" + getId() + "-driver" 320 | + ",bus=" + scsi->getId() + ".0" + ",id=" + getId(); 321 | } 322 | } 323 | 324 | bool DeviceScsiHd::isDeviceValid() 325 | { 326 | return !getImage().isEmpty(); 327 | } 328 | 329 | QString DeviceScsiHd::getDeviceInfo() 330 | { 331 | DeviceScsiController *scsi = dynamic_cast(parent()); 332 | Q_ASSERT(scsi); 333 | return "\tImage: " + getImage() + "\n" 334 | + "\tBus: " + scsi->getId() + ".0" + "\n"; 335 | } 336 | 337 | -------------------------------------------------------------------------------- /device/DeviceStorage.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICESTORAGE_H 2 | #define DEVICESTORAGE_H 3 | 4 | #include "Device.h" 5 | 6 | /*class DeviceStorage : public Device 7 | { 8 | public: 9 | DeviceStorage(const QString &n, Device *parent); 10 | };*/ 11 | 12 | class DeviceStorageController : public Device 13 | { 14 | public: 15 | DeviceStorageController() {} 16 | DeviceStorageController(const QString &n, Device *parent); 17 | 18 | virtual QString getDeviceTypeName() const = 0; 19 | }; 20 | 21 | class DeviceIdeController : public DeviceStorageController 22 | { 23 | public: 24 | static const char typeName[]; 25 | 26 | DeviceIdeController(); 27 | DeviceIdeController(Device *parent); 28 | 29 | virtual QString getDeviceTypeName() const { return typeName; } 30 | virtual BusType needsBus() const { return BusType::PCI; } 31 | 32 | virtual int getMaxCountDevices() const { return 2; } 33 | 34 | protected: 35 | virtual QString getDeviceInfo(); 36 | 37 | private: 38 | void initDefault(); 39 | static const char deviceName[]; 40 | }; 41 | 42 | class DevicePciController : public DeviceStorageController 43 | { 44 | public: 45 | static const char typeName[]; 46 | 47 | DevicePciController() { initDefault(); } 48 | DevicePciController(Device *parent); 49 | 50 | virtual QString getDeviceTypeName() const { return typeName; } 51 | virtual BusType needsBus() const { return BusType::System; } 52 | 53 | protected: 54 | virtual BusType providesBus() const { return BusType::PCI; } 55 | 56 | private: 57 | void initDefault(); 58 | }; 59 | 60 | class DeviceScsiController : public DeviceStorageController 61 | { 62 | public: 63 | static const char typeName[]; 64 | 65 | DeviceScsiController(); 66 | DeviceScsiController(Device *parent); 67 | 68 | virtual QString getDeviceTypeName() const { return typeName; } 69 | virtual BusType needsBus() const { return BusType::PCI; } 70 | #ifdef GUI 71 | virtual QWidget *getEditorForm(); 72 | #endif 73 | const QStringList &getControllers() const; 74 | void setController(const QString &name) { controller = name; } 75 | QString getCurrentController() const { return controller; } 76 | 77 | protected: 78 | virtual BusType providesBus() const { return BusType::SCSI; } 79 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 80 | virtual void saveParameters(QXmlStreamWriter &xml) const; 81 | virtual void readParameters(QXmlStreamReader &xml); 82 | virtual QString getDeviceInfo(); 83 | 84 | private: 85 | void initDefault(); 86 | static const char deviceName[]; 87 | QString controller; 88 | }; 89 | 90 | class DeviceStorage : public Device 91 | { 92 | public: 93 | DeviceStorage() {} 94 | DeviceStorage(const QString &n, Device *parent); 95 | 96 | virtual QString getDeviceTypeName() const = 0; 97 | virtual void setImage(const QString &img) { image = img; }; 98 | virtual QString getImage() const { return image; }; 99 | #ifdef GUI 100 | virtual QWidget *getEditorForm(); 101 | #endif 102 | protected: 103 | virtual void saveParameters(QXmlStreamWriter &xml) const; 104 | virtual void readParameters(QXmlStreamReader &xml); 105 | 106 | private: 107 | QString image; 108 | }; 109 | 110 | class DeviceIdeHd : public DeviceStorage 111 | { 112 | 113 | public: 114 | static const char typeName[]; 115 | 116 | DeviceIdeHd(); 117 | DeviceIdeHd(const QString &img, Device *parent); 118 | 119 | virtual QString getDeviceTypeName() const { return typeName; } 120 | virtual BusType needsBus() const { return BusType::IDE; } 121 | 122 | protected: 123 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 124 | virtual bool isDeviceValid(); 125 | virtual QString getDeviceInfo(); 126 | 127 | private: 128 | static const char deviceName[]; 129 | }; 130 | 131 | 132 | class DeviceIdeCdrom : public DeviceStorage 133 | { 134 | 135 | public: 136 | static const char typeName[]; 137 | 138 | DeviceIdeCdrom(); 139 | DeviceIdeCdrom(const QString &img, Device *parent); 140 | 141 | virtual QString getDeviceTypeName() const { return typeName; } 142 | virtual BusType needsBus() const { return BusType::IDE; } 143 | 144 | protected: 145 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 146 | virtual bool isDeviceValid(); 147 | virtual QString getDeviceInfo(); 148 | 149 | private: 150 | static const char deviceName[]; 151 | }; 152 | 153 | 154 | class DeviceScsiHd : public DeviceStorage 155 | { 156 | 157 | public: 158 | static const char typeName[]; 159 | 160 | DeviceScsiHd(); 161 | DeviceScsiHd(const QString &img, Device *parent); 162 | 163 | virtual QString getDeviceTypeName() const { return typeName; } 164 | virtual BusType needsBus() const { return BusType::SCSI; } 165 | 166 | protected: 167 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 168 | virtual bool isDeviceValid(); 169 | virtual QString getDeviceInfo(); 170 | 171 | private: 172 | static const char deviceName[]; 173 | }; 174 | 175 | #endif // DEVICESTORAGE_H 176 | -------------------------------------------------------------------------------- /device/DeviceSystem.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceSystem.h" 2 | #include "DeviceFactory.h" 3 | #include "PlatformInfo.h" 4 | #ifdef GUI 5 | #include "DeviceForm.h" 6 | #endif 7 | 8 | /****************************************************************************** 9 | * MEMORY * 10 | ******************************************************************************/ 11 | 12 | const char DeviceMemory::typeName[] = "DeviceMemory"; 13 | REGISTER_DEVICE(DeviceMemory) 14 | 15 | static const char xml_size[] = "MemorySize"; 16 | 17 | DeviceMemory::DeviceMemory(const QString &memSize, Device *parent) : 18 | Device("Memory", parent), size(memSize) 19 | { 20 | } 21 | 22 | #ifdef GUI 23 | QWidget *DeviceMemory::getEditorForm() 24 | { 25 | return new DeviceMemoryForm(this); 26 | } 27 | #endif 28 | 29 | void DeviceMemory::saveParameters(QXmlStreamWriter &xml) const 30 | { 31 | xml.writeStartElement(xml_size); 32 | xml.writeCharacters(size); 33 | xml.writeEndElement(); 34 | } 35 | 36 | void DeviceMemory::readParameters(QXmlStreamReader &xml) 37 | { 38 | xml.readNextStartElement(); 39 | Q_ASSERT(xml.name() == xml_size); 40 | size = xml.readElementText(); 41 | } 42 | 43 | QString DeviceMemory::getCommandLineOption(CommandLineParameters &cmdParams) 44 | { 45 | return " -m " + size + "M"; 46 | } 47 | 48 | QString DeviceMemory::getDeviceInfo() 49 | { 50 | return "Memory: " + size + " Mb\n"; 51 | } 52 | 53 | 54 | /****************************************************************************** 55 | * System unchanged devices * 56 | ******************************************************************************/ 57 | 58 | static const char xml_name[] = "Model"; 59 | 60 | DeviceSystem::DeviceSystem(const QString &n, Device *parent) 61 | : Device(n, parent) 62 | { 63 | } 64 | 65 | void DeviceSystem::saveParameters(QXmlStreamWriter &xml) const 66 | { 67 | xml.writeStartElement(xml_name); 68 | xml.writeCharacters(getName()); 69 | xml.writeEndElement(); 70 | } 71 | 72 | void DeviceSystem::readParameters(QXmlStreamReader &xml) 73 | { 74 | xml.readNextStartElement(); 75 | Q_ASSERT(xml.name() == xml_name); 76 | setName(xml.readElementText()); 77 | } 78 | 79 | /****************************************************************************** 80 | * MACHINE * 81 | ******************************************************************************/ 82 | 83 | const char DeviceMachine::typeName[] = "DeviceMachine"; 84 | REGISTER_DEVICE(DeviceMachine) 85 | 86 | DeviceMachine::DeviceMachine(const QString &machineName, Device *parent) : 87 | DeviceSystem("Machine", parent) 88 | { 89 | setName(machineName); 90 | } 91 | 92 | QString DeviceMachine::getCommandLineOption(CommandLineParameters &cmdParams) 93 | { 94 | return " -machine " + getName(); 95 | } 96 | 97 | QString DeviceMachine::getDeviceInfo() 98 | { 99 | return "Machine: " + getName() + "\n"; 100 | } 101 | 102 | /****************************************************************************** 103 | * CPU * 104 | ******************************************************************************/ 105 | 106 | const char DeviceCpu::typeName[] = "DeviceCpu"; 107 | REGISTER_DEVICE(DeviceCpu) 108 | 109 | DeviceCpu::DeviceCpu(const QString &cpuName, Device *parent) : 110 | DeviceSystem("CPU", parent) 111 | { 112 | setName(cpuName); 113 | } 114 | 115 | QString DeviceCpu::getCommandLineOption(CommandLineParameters &cmdParams) 116 | { 117 | return getName() == "default" ? "" : " -cpu " + getName(); 118 | } 119 | 120 | QString DeviceCpu::getDeviceInfo() 121 | { 122 | return "CPU: " + getName() + "\n"; 123 | } 124 | 125 | #ifdef GUI 126 | QWidget *DeviceCpu::getEditorForm() 127 | { 128 | return new DeviceCpuForm(this); 129 | } 130 | #endif 131 | 132 | const QStringList DeviceCpu::getCpuModels() const 133 | { 134 | PlatformInfo pi(getPathToConfig()); 135 | return pi.getCpus(); 136 | } 137 | 138 | -------------------------------------------------------------------------------- /device/DeviceSystem.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICESYSTEM_H 2 | #define DEVICESYSTEM_H 3 | 4 | #include "Device.h" 5 | 6 | class DeviceMemory : public Device 7 | { 8 | public: 9 | static const char typeName[]; 10 | 11 | DeviceMemory() {} 12 | DeviceMemory(const QString &memSize, Device *parent); 13 | 14 | virtual QString getDeviceTypeName() const { return typeName; } 15 | #ifdef GUI 16 | virtual QWidget *getEditorForm(); 17 | #endif 18 | void setSize(const QString &newSize) { size = newSize; } 19 | int getSize() const { return size.toInt(); } 20 | 21 | virtual BusType needsBus() const { return BusType::System; } 22 | 23 | protected: 24 | virtual void saveParameters(QXmlStreamWriter &xml) const; 25 | virtual void readParameters(QXmlStreamReader &xml); 26 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 27 | virtual QString getDeviceInfo(); 28 | 29 | private: 30 | QString size; /* in megabytes */ 31 | }; 32 | 33 | 34 | class DeviceSystem : public Device 35 | { 36 | public: 37 | DeviceSystem() {} 38 | DeviceSystem(const QString &n, Device *parent); 39 | 40 | virtual QString getDeviceTypeName() const = 0; 41 | virtual bool isDeviceInvisible() { return true; } 42 | virtual BusType needsBus() const { return BusType::System; } 43 | QString getName() const { return name; } 44 | 45 | protected: 46 | virtual void saveParameters(QXmlStreamWriter &xml) const; 47 | virtual void readParameters(QXmlStreamReader &xml); 48 | void setName(const QString &newName) { name = newName; } 49 | 50 | private: 51 | QString name; 52 | }; 53 | 54 | class DeviceMachine : public DeviceSystem 55 | { 56 | public: 57 | static const char typeName[]; 58 | 59 | DeviceMachine() {} 60 | DeviceMachine(const QString &machineName, Device *parent); 61 | 62 | virtual QString getDeviceTypeName() const { return typeName; } 63 | 64 | protected: 65 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 66 | virtual QString getDeviceInfo(); 67 | }; 68 | 69 | 70 | class DeviceCpu : public DeviceSystem 71 | { 72 | public: 73 | static const char typeName[]; 74 | 75 | DeviceCpu() {} 76 | DeviceCpu(const QString &cpuName, Device *parent); 77 | 78 | #ifdef GUI 79 | virtual QWidget *getEditorForm(); 80 | #endif 81 | virtual QString getDeviceTypeName() const { return typeName; } 82 | virtual bool isDeviceInvisible() { return false; } 83 | 84 | const QStringList getCpuModels() const; 85 | void setCpuModel(const QString &name) { setName(name); } 86 | 87 | protected: 88 | virtual QString getCommandLineOption(CommandLineParameters &cmdParams); 89 | virtual QString getDeviceInfo(); 90 | }; 91 | 92 | 93 | #endif // DEVICESYSTEM_H 94 | 95 | 96 | -------------------------------------------------------------------------------- /device/DeviceUsb.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceUsb.h" 2 | #include "DeviceFactory.h" 3 | 4 | // class DeviceUsbForm : public QGroupBox 5 | // { 6 | // Q_OBJECT 7 | 8 | // public: 9 | // DeviceUsbForm(DeviceUsb *dev); 10 | 11 | // private: 12 | // DeviceUsb *device; 13 | 14 | // private slots: 15 | 16 | 17 | // }; 18 | 19 | 20 | const char DeviceUsb::typeName[] = "DeviceUsb"; 21 | 22 | 23 | DeviceUsb::DeviceUsb(Device *parent) : 24 | Device("Usb", parent) 25 | { 26 | } 27 | 28 | #ifdef GUI 29 | QWidget *DeviceUsb::getEditorForm() 30 | { 31 | return NULL;//new DeviceUsbForm(this); 32 | } 33 | #endif 34 | 35 | QString DeviceUsb::getCommandLineOption() 36 | { 37 | return ""; 38 | } 39 | 40 | // DeviceUsbForm::DeviceUsbForm(DeviceUsb *dev) 41 | // : device(dev) 42 | // { 43 | 44 | // } 45 | 46 | 47 | const char DeviceUsbEhci::typeName[] = "DeviceUsbEhci"; 48 | 49 | DeviceUsbEhci::DeviceUsbEhci(Device *parent) : 50 | Device("UsbEhci", parent) 51 | { 52 | } 53 | 54 | #ifdef GUI 55 | QWidget *DeviceUsbEhci::getEditorForm() 56 | { 57 | return NULL; 58 | } 59 | #endif 60 | 61 | QString DeviceUsbEhci::getCommandLineOption() 62 | { 63 | return "-usb -device usb-ehci -device usb-host,vendorid=0x046d,productid=0x0829"; 64 | } 65 | 66 | 67 | 68 | const char DeviceUsbXhci::typeName[] = "DeviceUsbEhci"; 69 | 70 | DeviceUsbXhci::DeviceUsbXhci(Device *parent) : 71 | Device("UsbEhci", parent) 72 | { 73 | } 74 | 75 | #ifdef GUI 76 | QWidget *DeviceUsbXhci::getEditorForm() 77 | { 78 | return NULL; 79 | } 80 | #endif 81 | 82 | QString DeviceUsbXhci::getCommandLineOption() 83 | { 84 | return "-usb -device nec-usb-xhci -device usb-host,vendorid=0x046d,productid=0x0829"; 85 | } 86 | 87 | 88 | -------------------------------------------------------------------------------- /device/DeviceUsb.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICEUSB_H 2 | #define DEVICEUSB_H 3 | 4 | #include "Device.h" 5 | 6 | class DeviceUsb : public Device 7 | { 8 | public: 9 | static const char typeName[]; 10 | 11 | DeviceUsb() {} 12 | DeviceUsb(Device *parent); 13 | 14 | virtual QString getDeviceTypeName() const { return typeName; } 15 | #ifdef GUI 16 | virtual QWidget *getEditorForm(); 17 | #endif 18 | 19 | protected: 20 | virtual QString getCommandLineOption(); 21 | }; 22 | 23 | class DeviceUsbEhci : public Device 24 | { 25 | public: 26 | static const char typeName[]; 27 | 28 | DeviceUsbEhci() {} 29 | DeviceUsbEhci(Device *parent); 30 | 31 | virtual QString getDeviceTypeName() const { return typeName; } 32 | #ifdef GUI 33 | virtual QWidget *getEditorForm(); 34 | #endif 35 | 36 | protected: 37 | virtual QString getCommandLineOption(); 38 | }; 39 | 40 | class DeviceUsbXhci : public Device 41 | { 42 | public: 43 | static const char typeName[]; 44 | 45 | DeviceUsbXhci() {} 46 | DeviceUsbXhci(Device *parent); 47 | 48 | virtual QString getDeviceTypeName() const { return typeName; } 49 | #ifdef GUI 50 | virtual QWidget *getEditorForm(); 51 | #endif 52 | 53 | protected: 54 | virtual QString getCommandLineOption(); 55 | }; 56 | 57 | 58 | #endif // DEVICEUSB_H 59 | -------------------------------------------------------------------------------- /docs/Using qemu-gui.md: -------------------------------------------------------------------------------- 1 | Before work with qemu-gui you have to add qemu installation folders. You can do it by two ways: 2 | 1. Use combobox "Add qemu" 3 | 2. Use menu "Settings" -> "Set QEMU" 4 | 5 | Is necessary to choose folder with executable qemu files (qemu-system-*). 6 | 7 | ### Create virtual machine 8 | 9 | To create VM use button "Create machine". No has sense do it before adding qemu folders, because fields "Platform", "Machine" and "CPU" fill automatically during it. 10 | 11 | The window "Create Virtual Machine" contains four parameters group: 12 | - "OS information" 13 | 14 | Is necessary to fill field "Name" and if you want you can change default path to VM. 15 | 16 | Fields "OS type" and "OS version" don't use now. 17 | - "System information" 18 | 19 | Values of this fields had got from current qemu, you have to choose what you need. 20 | - "Memory size" 21 | - "Disk" 22 | - No disk 23 | - Select exist disk 24 | - Create new disk 25 | 26 | ![Create VM form](./imgs/create_vm.png) 27 | 28 | ### Edit VM settings 29 | 30 | Available devices present as a tree in the left on the form. Right click on nodes let you add new devices. 31 | 32 | Some devices have a set of options, which you can change. It include select values from lists, set values, add additional options to command line. 33 | 34 | There is a line for additional command line common qemu parameters on the bottom, if is necessary set specific options. 35 | 36 | ![VM settings form](./imgs/vm_settings.png) 37 | 38 | #### Specific command line options example 39 | 40 | Enable logfiles 41 | 42 | ` 43 | -D logfile -d in_asm 44 | ` 45 | 46 | Use specific boot option 47 | 48 | ` 49 | -kernel kernel-qemu-4.4.34-jessie 50 | ` 51 | 52 | If you make changes, all record/replay execution will be deleted, because set of devices influence on executions and they will not work. 53 | 54 | ### Record/Replay 55 | 56 | Qemu-gui allows record executions and replay it. Execution is a scenario of work system inside qemu. Execution includes all user and network interaction, interrupts, timers and other. You can replay one scenario many times and make analysis if you need. 57 | 58 | All existing executions for VM are showing on the tab "Record/Replay". 59 | 60 | Execution may be replayed only from the qemu with which it was recorded. 61 | 62 | You can set icount value and enable/disable autosnapshot function. Autospapshot needs value of period in second. 63 | 64 | ![Create execution](./imgs/recordreplay.png) 65 | 66 | ### Other 67 | 68 | If you need to use debugger, is necessary set checkbox "Debug enable". After that, the debugger should be running and connect to the simulator: 69 | 70 | `gdb -ex 'target remote :1234'` 71 | 72 | [You can read more about debugging](https://github.com/ispras/swat/blob/master/docs/ReverseDebugging.md) 73 | -------------------------------------------------------------------------------- /docs/imgs/create_vm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/docs/imgs/create_vm.png -------------------------------------------------------------------------------- /docs/imgs/recordreplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/docs/imgs/recordreplay.png -------------------------------------------------------------------------------- /docs/imgs/vm_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/docs/imgs/vm_settings.png -------------------------------------------------------------------------------- /gui/AddDeviceForm.cpp: -------------------------------------------------------------------------------- 1 | #include "AddDeviceForm.h" 2 | #include "DeviceFactory.h" 3 | #include "QemuGUI.h" 4 | 5 | 6 | AddDeviceForm::AddDeviceForm(const Device *device, QWidget *parent) 7 | { 8 | if (AddDeviceForm::objectName().isEmpty()) 9 | AddDeviceForm::setObjectName(QStringLiteral("AddDeviceForm")); 10 | resize(140, 200); 11 | setWindowTitle(QApplication::translate("AddDeviceForm", "Add device", Q_NULLPTR)); 12 | setWindowModality(Qt::WindowModality::ApplicationModal); 13 | 14 | deviceList = new QListWidget(); 15 | QPushButton *addBtn = new QPushButton("Add"); 16 | QPushButton *cancelBtn = new QPushButton("Cancel"); 17 | 18 | addBtn->setDefault(true); 19 | cancelBtn->setAutoDefault(true); 20 | 21 | QVBoxLayout *mainLay = new QVBoxLayout(this); 22 | QHBoxLayout *btnLay = new QHBoxLayout(); 23 | btnLay->addWidget(addBtn); 24 | btnLay->addWidget(cancelBtn); 25 | 26 | mainLay->addWidget(deviceList); 27 | mainLay->addLayout(btnLay); 28 | 29 | setLayout(mainLay); 30 | 31 | connect(addBtn, &QPushButton::clicked, this, &AddDeviceForm::addNewDevice); 32 | connect(cancelBtn, &QPushButton::clicked, this, &QWidget::close); 33 | connect(deviceList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), 34 | this, SLOT(addNewDeviceDblClick(QListWidgetItem *))); 35 | 36 | addDevices = DeviceFactory::getDevicesForBus(device->providesBus()); 37 | foreach(auto dev, addDevices) 38 | { 39 | deviceList->addItem(dev->getDeviceTypeName()); 40 | } 41 | pWidget = parent; 42 | } 43 | 44 | AddDeviceForm::~AddDeviceForm() 45 | { 46 | foreach(auto dev, addDevices) 47 | { 48 | delete dev; 49 | } 50 | } 51 | 52 | int AddDeviceForm::getAddDevicesCount() 53 | { 54 | return deviceList->count(); 55 | } 56 | 57 | void AddDeviceForm::addNewDeviceDblClick(QListWidgetItem *item) 58 | { 59 | addNewDevice(); 60 | } 61 | 62 | void AddDeviceForm::addDevice() 63 | { 64 | deviceList->setCurrentRow(0); 65 | show(); 66 | QemuGUI::setWindowGeometry(this, pWidget); 67 | } 68 | 69 | void AddDeviceForm::addNewDevice() 70 | { 71 | Device *newDevice = addDevices.at(deviceList->currentRow()); 72 | addDevices.removeOne(newDevice); 73 | emit deviceWantsToAdd(newDevice); 74 | close(); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /gui/AddDeviceForm.h: -------------------------------------------------------------------------------- 1 | #ifndef ADDDEVICEFORM_H 2 | #define ADDDEVICEFORM_H 3 | 4 | #include 5 | #include "Device.h" 6 | #include 7 | 8 | class AddDeviceForm : public QWidget 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | AddDeviceForm(const Device *device, QWidget *parent); 14 | ~AddDeviceForm(); 15 | 16 | int getAddDevicesCount(); 17 | 18 | public slots: 19 | void addDevice(); 20 | 21 | private: 22 | QWidget *pWidget; 23 | QListWidget *deviceList; 24 | Devices addDevices; 25 | 26 | 27 | private slots: 28 | void addNewDevice(); 29 | void addNewDeviceDblClick(QListWidgetItem *item); 30 | 31 | signals: 32 | void deviceWantsToAdd(Device *); 33 | 34 | 35 | }; 36 | 37 | #endif // ADDDEVICEFORM_H 38 | -------------------------------------------------------------------------------- /gui/ConnectionSettingsForm.cpp: -------------------------------------------------------------------------------- 1 | #include "ConnectionSettingsForm.h" 2 | 3 | ConnectionSettingsForm::ConnectionSettingsForm(QWidget *parent) 4 | : QWidget(parent) 5 | { 6 | if (ConnectionSettingsForm::objectName().isEmpty()) 7 | ConnectionSettingsForm::setObjectName(QStringLiteral("ConnectionSettings")); 8 | resize(200, 100); 9 | 10 | setWindowTitle(QApplication::translate("ConnectionSettings", "Connection settings", Q_NULLPTR)); 11 | setWindowIcon(QIcon(":Resources/qemu.png")); 12 | setWindowModality(Qt::ApplicationModal); 13 | //setWindowFlags(Qt::MSWindowsFixedSizeDialogHint); 14 | 15 | qmp_line = new QLineEdit(); 16 | monitor_line = new QLineEdit(); 17 | QDialogButtonBox *savecancel_btn = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel); 18 | 19 | qmp_line->setFixedWidth(50); 20 | monitor_line->setFixedWidth(50); 21 | qmp_line->setValidator(new QRegExpValidator(QRegExp("[1-9][0-9]*"), this)); 22 | monitor_line->setValidator(new QRegExpValidator(QRegExp("[1-9][0-9]*"), this)); 23 | qmp_line->setText(GlobalConfig::get_port_qmp()); 24 | monitor_line->setText(GlobalConfig::get_port_monitor()); 25 | 26 | QGridLayout *ports_lay = new QGridLayout(); 27 | ports_lay->addWidget(new QLabel("QMP port"), 0, 0, Qt::AlignmentFlag::AlignLeft); 28 | ports_lay->addWidget(qmp_line, 0, 1); 29 | ports_lay->addWidget(new QLabel("Monitor port"), 1, 0, Qt::AlignmentFlag::AlignLeft); 30 | ports_lay->addWidget(monitor_line, 1, 1); 31 | 32 | QVBoxLayout *main_lay = new QVBoxLayout(this); 33 | main_lay->addLayout(ports_lay); 34 | main_lay->addWidget(savecancel_btn); 35 | 36 | show(); 37 | 38 | connect(savecancel_btn, &QDialogButtonBox::accepted, this, &ConnectionSettingsForm::save_connection_settings); 39 | connect(savecancel_btn, &QDialogButtonBox::rejected, this, &QWidget::close); 40 | } 41 | 42 | ConnectionSettingsForm::~ConnectionSettingsForm() 43 | { 44 | } 45 | 46 | 47 | void ConnectionSettingsForm::save_connection_settings() 48 | { 49 | if (qmp_line->text().isEmpty() || monitor_line->text().isEmpty() || qmp_line->text() == monitor_line->text()) 50 | { 51 | QMessageBox::critical(this, "Input error", "You are wrong"); 52 | } 53 | else 54 | { 55 | GlobalConfig::set_port_qmp(qmp_line->text()); 56 | GlobalConfig::set_port_monitor(monitor_line->text()); 57 | emit done_connection_settings(qmp_line->text(), monitor_line->text()); 58 | close(); 59 | } 60 | } 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /gui/ConnectionSettingsForm.h: -------------------------------------------------------------------------------- 1 | #ifndef CONNECTIONSETTINGSFORM_H 2 | #define CONNECTIONSETTINGSFORM_H 3 | 4 | #include 5 | #include "GlobalConfig.h" 6 | 7 | class ConnectionSettingsForm : public QWidget 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | ConnectionSettingsForm(QWidget *parent = 0); 13 | ~ConnectionSettingsForm(); 14 | 15 | private: 16 | QLineEdit *qmp_line; 17 | QLineEdit *monitor_line; 18 | 19 | private slots: 20 | void save_connection_settings(); 21 | 22 | signals: 23 | void done_connection_settings(QString, QString); 24 | 25 | }; 26 | 27 | #endif //CONNECTIONSETTINGSFORM_H 28 | -------------------------------------------------------------------------------- /gui/ConsoleTab.cpp: -------------------------------------------------------------------------------- 1 | #include "ConsoleTab.h" 2 | 3 | ConsoleTab::ConsoleTab() 4 | { 5 | consoleText = new QTextEdit(); 6 | consoleText->setReadOnly(true); 7 | 8 | consoleText->setStyleSheet("background-color: black; border: 1px; \ 9 | font-family: \"Courier New\"; color: white; font-size: 14px"); 10 | 11 | QVBoxLayout *mainLay = new QVBoxLayout(); 12 | mainLay->addWidget(consoleText); 13 | 14 | setLayout(mainLay); 15 | } 16 | 17 | ConsoleTab::~ConsoleTab() 18 | { 19 | 20 | } 21 | 22 | void ConsoleTab::setTextCursor() 23 | { 24 | QTextCursor cursor(consoleText->textCursor()); 25 | cursor.movePosition(QTextCursor::End); 26 | consoleText->setTextCursor(cursor); 27 | } 28 | 29 | void ConsoleTab::addConsoleText(const QString &text) 30 | { 31 | setTextCursor(); 32 | consoleText->insertPlainText(text + "\n\n"); 33 | consoleText->ensureCursorVisible(); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /gui/ConsoleTab.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSOLETAB_H 2 | #define CONSOLETAB_H 3 | 4 | #include 5 | 6 | class ConsoleTab : public QWidget 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | ConsoleTab(); 12 | ~ConsoleTab(); 13 | 14 | 15 | private: 16 | QTextEdit *consoleText; 17 | 18 | void setTextCursor(); 19 | 20 | public slots: 21 | void addConsoleText(const QString &text); 22 | }; 23 | 24 | 25 | #endif // CONSOLETAB_H 26 | -------------------------------------------------------------------------------- /gui/CreateVMForm.h: -------------------------------------------------------------------------------- 1 | #ifndef CREATEVMFORM_H 2 | #define CREATEVMFORM_H 3 | 4 | #include 5 | #include 6 | #include "VMConfig.h" 7 | #include "QemuImgLauncher.h" 8 | #include "QemuGUICommon.h" 9 | #include "VMPropertiesForm.h" 10 | 11 | 12 | class CreateVMForm : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | CreateVMForm(); 18 | ~CreateVMForm(); 19 | 20 | private: 21 | QLineEdit *name_edit; 22 | QLineEdit *pathtovm_edit; 23 | QPushButton *pathtovm_btn; 24 | QComboBox *typeOS_combo; 25 | //QComboBox *verOS_combo; 26 | QSlider *ram_slider; 27 | QSpinBox *ram_spin; 28 | QComboBox *format_combo; 29 | QSlider *hddsize_slider; 30 | QSpinBox *hddsize_spin; 31 | QLineEdit *imageplace_edit; 32 | QPushButton *imageplace_btn; 33 | QLabel *imageplace_lbl, *format_lbl, *hddsize_lbl; 34 | QRadioButton *hdd_no_rb; 35 | QRadioButton *hdd_exist_rb; 36 | QRadioButton *hdd_new_rb; 37 | QDialogButtonBox *okcancel_btn; 38 | QLabel *error_lbl; 39 | QComboBox *machineCombo; 40 | QComboBox *cpuCombo; 41 | QComboBox *platformCombo; 42 | VMPropertiesForm *kernelForm; 43 | 44 | QString path_to_vm; 45 | QString platformName; 46 | 47 | VMConfig *configVM; 48 | QProgressDialog *imgCreationDlg; 49 | 50 | QString platformDirPath; 51 | 52 | 53 | private: 54 | void setDefaultItemColor(QComboBox *widget); 55 | void connect_signals(); 56 | void widget_placement(); 57 | void set_visible_widgets_for_new_hdd(bool isVisible); 58 | void set_visible_widgets_for_existed_hdd(bool isVisible); 59 | void show_error_message(const QString &error_text); 60 | 61 | private slots: 62 | void hdd_no(bool state); 63 | void hdd_exist(bool state); 64 | void hdd_new(bool state); 65 | void place_disk(); 66 | void create_vm(); 67 | void select_dir(); 68 | void change_path(const QString &name); 69 | QString set_path_to_vm(const QString &home_path); 70 | bool input_verification(const QString &path, const QString &name); 71 | QStringList getInformationFromQemu(const QString &cmd); 72 | 73 | private slots: 74 | void changePlatform(const QString &text); 75 | 76 | public slots: 77 | void finish_qemu_img(int exitCode); 78 | 79 | signals: 80 | void createVM_new_vm_is_complete(VMConfig *); 81 | 82 | }; 83 | 84 | #endif // CREATEVMFORM_H 85 | 86 | -------------------------------------------------------------------------------- /gui/DeviceForm.cpp: -------------------------------------------------------------------------------- 1 | #include "DeviceForm.h" 2 | #include "CommandLineParameters.h" 3 | #include "QemuGUICommon.h" 4 | 5 | DeviceForm::DeviceForm(Device *dev) : device(dev) 6 | { 7 | QGroupBox *form = this; 8 | mainLay = new QVBoxLayout(this); 9 | mainLay->setAlignment(Qt::AlignmentFlag::AlignTop); 10 | if (device->isRemovable()) 11 | { 12 | cmdWidget = new DeviceCommandLineForm(dev); 13 | mainLay->addWidget(cmdWidget); 14 | } 15 | form->setLayout(mainLay); 16 | } 17 | 18 | void DeviceForm::devFormAddWidget(QWidget *widget) 19 | { 20 | if (device->isRemovable()) 21 | { 22 | mainLay->takeAt(mainLay->count() - 1); 23 | mainLay->addWidget(widget); 24 | mainLay->addWidget(cmdWidget); 25 | } 26 | else 27 | { 28 | mainLay->addWidget(widget); 29 | } 30 | } 31 | 32 | void DeviceForm::devFormAddLayout(QLayout *layout) 33 | { 34 | if (device->isRemovable()) 35 | { 36 | mainLay->takeAt(mainLay->count() - 1); 37 | mainLay->addLayout(layout); 38 | mainLay->addWidget(cmdWidget); 39 | } 40 | else 41 | { 42 | mainLay->addLayout(layout); 43 | } 44 | } 45 | 46 | 47 | /****************************************************************************** 48 | * Additional command line options Form * 49 | ******************************************************************************/ 50 | 51 | DeviceCommandLineForm::DeviceCommandLineForm(Device *dev) 52 | : device(dev) 53 | { 54 | QGroupBox *cmdGroup = this; 55 | QPushButton *cmdBtn = new QPushButton("Command line options"); 56 | optionalLbl = new QLabel("Additional options:"); 57 | optionalLine = new QLineEdit(); 58 | cmdLine = new QTextEdit(); 59 | 60 | cmdLine->setVisible(false); 61 | optionalLbl->setVisible(false); 62 | optionalLine->setVisible(false); 63 | 64 | cmdBtn->setStyleSheet("background-color: white;"); 65 | 66 | updateCmd(); 67 | cmdLine->setReadOnly(true); 68 | cmdLine->setStyleSheet("background-color: #F0F0F0;"); 69 | 70 | optionalLine->setText(dev->getAddtionalCommandLineOption()); 71 | optionalLine->setToolTip("Use next format: \"param1=value1,param2=value2,..\""); 72 | 73 | QVBoxLayout *mainLay = new QVBoxLayout(); 74 | mainLay->addWidget(cmdBtn); 75 | mainLay->addWidget(optionalLbl); 76 | mainLay->addWidget(optionalLine); 77 | mainLay->addWidget(cmdLine); 78 | mainLay->setAlignment(Qt::AlignmentFlag::AlignTop); 79 | 80 | cmdGroup->setLayout(mainLay); 81 | 82 | connect(cmdBtn, &QPushButton::clicked, 83 | this, &DeviceCommandLineForm::showCmdLine); 84 | 85 | connect(optionalLine, &QLineEdit::editingFinished, 86 | this, &DeviceCommandLineForm::saveUserOptions); 87 | } 88 | 89 | void DeviceCommandLineForm::showCmdLine() 90 | { 91 | bool isVisible = !cmdLine->isVisible(); 92 | cmdLine->setVisible(isVisible); 93 | optionalLbl->setVisible(isVisible); 94 | optionalLine->setVisible(isVisible); 95 | } 96 | 97 | void DeviceCommandLineForm::updateCmd() 98 | { 99 | CommandLineParameters cmd; 100 | cmdLine->setPlainText("Command line: \n" + device->getCommandLine(cmd).trimmed()); 101 | } 102 | 103 | void DeviceCommandLineForm::saveUserOptions() 104 | { 105 | device->setAdditionalCommandLineOption(optionalLine->text().trimmed()); 106 | } 107 | 108 | 109 | /****************************************************************************** 110 | * Storage Device Form * 111 | ******************************************************************************/ 112 | 113 | DeviceStorageForm::DeviceStorageForm(DeviceStorage *dev) 114 | : DeviceForm(dev), device(dev) 115 | { 116 | QLineEdit *imageLine = new QLineEdit(); 117 | QPushButton *selectImageBtn = new QPushButton("..."); 118 | 119 | selectImageBtn->setFixedWidth(30); 120 | imageLine->setText(device->getImage()); 121 | imageLine->setReadOnly(true); 122 | if (device->getImage().isEmpty()) 123 | { 124 | imageLine->setStyleSheet("background: #EE756F"); 125 | } 126 | 127 | QHBoxLayout *topLay = new QHBoxLayout(); 128 | topLay->addWidget(imageLine); 129 | topLay->addWidget(selectImageBtn); 130 | devFormAddLayout(topLay); 131 | 132 | connect(selectImageBtn, &QPushButton::clicked, this, &DeviceStorageForm::editImage); 133 | connect(this, SIGNAL(newImageSet(QString)), imageLine, SLOT(setText(QString))); 134 | connect(this, SIGNAL(newDiskCompleted(QString)), imageLine, SLOT(setStyleSheet(QString))); 135 | } 136 | 137 | void DeviceStorageForm::editImage() 138 | { 139 | QString newImage = QFileDialog::getOpenFileName(nullptr, "Selecting image", 140 | "", "Images(*.qcow *.qcow2 *.img *.raw *.iso);; Other files(*.*)"); 141 | if (!newImage.isEmpty()) 142 | { 143 | emit newImageSet(newImage); 144 | emit newDiskCompleted(""); 145 | device->setImage(newImage); 146 | getCmdWidget()->updateCmd(); 147 | } 148 | } 149 | 150 | 151 | /****************************************************************************** 152 | * SCSI Controller Form * 153 | ******************************************************************************/ 154 | 155 | DeviceScsiControllerForm::DeviceScsiControllerForm(DeviceScsiController *dev) 156 | : DeviceForm(dev), device(dev) 157 | { 158 | QComboBox *controllersCombo = new QComboBox(); 159 | 160 | controllersCombo->addItems(device->getControllers()); 161 | controllersCombo->setCurrentText(device->getCurrentController()); 162 | 163 | devFormAddWidget(controllersCombo); 164 | 165 | connect(controllersCombo, SIGNAL(currentIndexChanged(const QString &)), 166 | this, SLOT(setController(const QString &))); 167 | } 168 | 169 | void DeviceScsiControllerForm::setController(const QString &name) 170 | { 171 | device->setController(name); 172 | getCmdWidget()->updateCmd(); 173 | } 174 | 175 | 176 | /****************************************************************************** 177 | * Device Memory * 178 | ******************************************************************************/ 179 | 180 | DeviceMemoryForm::DeviceMemoryForm(DeviceMemory *dev) 181 | : DeviceForm(dev), device(dev) 182 | { 183 | QLabel *memLbl = new QLabel("Size (MB)"); 184 | QSlider *sizeSlider = new QSlider(Qt::Horizontal); 185 | QSpinBox *sizeSpin = new QSpinBox(); 186 | 187 | sizeSpin->setMaximum(MIN_RAM_VALUE); 188 | sizeSpin->setMaximum(MAX_RAM_VALUE); 189 | sizeSpin->setValue(dev->getSize()); 190 | 191 | sizeSlider->setMinimum(MIN_RAM_VALUE); 192 | sizeSlider->setMaximum(MAX_RAM_VALUE); 193 | sizeSlider->setValue(dev->getSize()); 194 | 195 | QHBoxLayout *topLay = new QHBoxLayout(); 196 | topLay->addWidget(memLbl); 197 | topLay->addWidget(sizeSlider); 198 | topLay->addWidget(sizeSpin); 199 | 200 | devFormAddLayout(topLay); 201 | 202 | connect(sizeSpin, SIGNAL(valueChanged(int)), this, SLOT(sizeChanged(int))); 203 | 204 | connect(sizeSlider, &QSlider::valueChanged, sizeSpin, &QSpinBox::setValue); 205 | connect(sizeSpin, QOverload::of(&QSpinBox::valueChanged), 206 | sizeSlider, &QSlider::setValue); 207 | } 208 | 209 | void DeviceMemoryForm::sizeChanged(int val) 210 | { 211 | device->setSize(QString::number(val)); 212 | } 213 | 214 | /****************************************************************************** 215 | * Device Network Adapter * 216 | ******************************************************************************/ 217 | 218 | 219 | DeviceNetworkForm::DeviceNetworkForm(DeviceNetworkController *dev) 220 | : DeviceForm(dev), device(dev) 221 | { 222 | QComboBox *controllersCombo = new QComboBox(); 223 | netdevCombo = new QComboBox(); 224 | tapIfNameEdit = new QLineEdit(); 225 | tapIfNameLbl = new QLabel("Tap interface"); 226 | 227 | controllersCombo->addItems(device->getControllers()); 228 | controllersCombo->setCurrentText(device->getCurrentController()); 229 | netdevCombo->addItems(device->getNetdevBackend()); 230 | netdevCombo->setCurrentText(device->getCurrentNetdev()); 231 | tapIfNameEdit->setText(device->getCurrentTabIfName()); 232 | 233 | devFormAddWidget(controllersCombo); 234 | devFormAddWidget(netdevCombo); 235 | QHBoxLayout *tapIfLay = new QHBoxLayout(); 236 | tapIfLay->addWidget(tapIfNameLbl); 237 | tapIfLay->addWidget(tapIfNameEdit); 238 | devFormAddLayout(tapIfLay); 239 | 240 | setVisibleTapSetting(); 241 | 242 | connect(controllersCombo, SIGNAL(currentIndexChanged(const QString &)), 243 | this, SLOT(setController(const QString &))); 244 | connect(netdevCombo, SIGNAL(currentIndexChanged(const QString &)), 245 | this, SLOT(setNetdev(const QString &))); 246 | connect(tapIfNameEdit, SIGNAL(editingFinished()), 247 | this, SLOT(setTapIfName())); 248 | } 249 | 250 | void DeviceNetworkForm::setController(const QString &name) 251 | { 252 | device->setController(name); 253 | getCmdWidget()->updateCmd(); 254 | } 255 | 256 | void DeviceNetworkForm::setVisibleTapSetting() 257 | { 258 | bool isTap = netdevCombo->currentText() == "tap"; 259 | tapIfNameEdit->setVisible(isTap); 260 | tapIfNameLbl->setVisible(isTap); 261 | if (!isTap) 262 | { 263 | device->setTapIfName(""); 264 | } 265 | else 266 | { 267 | tapIfNameEdit->setFocus(); 268 | } 269 | } 270 | 271 | void DeviceNetworkForm::setNetdev(const QString &name) 272 | { 273 | setVisibleTapSetting(); 274 | device->setNetdev(name); 275 | getCmdWidget()->updateCmd(); 276 | } 277 | 278 | void DeviceNetworkForm::setTapIfName() 279 | { 280 | device->setTapIfName(tapIfNameEdit->text()); 281 | getCmdWidget()->updateCmd(); 282 | } 283 | 284 | /****************************************************************************** 285 | * Device Cpu * 286 | ******************************************************************************/ 287 | 288 | DeviceCpuForm::DeviceCpuForm(DeviceCpu *dev) 289 | : DeviceForm(dev), device(dev) 290 | { 291 | QLabel *cpuLbl = new QLabel("Model"); 292 | QComboBox *cpuCombo = new QComboBox(); 293 | 294 | cpuLbl->setFixedWidth(30); 295 | cpuCombo->addItems(device->getCpuModels()); 296 | cpuCombo->setCurrentText(device->getName()); 297 | 298 | QHBoxLayout *topLay = new QHBoxLayout(); 299 | topLay->addWidget(cpuLbl); 300 | topLay->addWidget(cpuCombo); 301 | 302 | devFormAddLayout(topLay); 303 | 304 | connect(cpuCombo, QOverload::of(&QComboBox::activated), 305 | [=](const QString &text) 306 | { 307 | device->setCpuModel(text); 308 | } 309 | ); 310 | } 311 | 312 | 313 | -------------------------------------------------------------------------------- /gui/DeviceForm.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICEFORM_H 2 | #define DEVICEFORM_H 3 | 4 | #include 5 | #include "DeviceStorage.h" 6 | #include "DeviceSystem.h" 7 | #include "DeviceNetwork.h" 8 | 9 | class DeviceCommandLineForm; 10 | 11 | class DeviceForm : public QGroupBox 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | DeviceForm(Device *dev); 17 | DeviceCommandLineForm *getCmdWidget() { return cmdWidget; } 18 | 19 | protected: 20 | void devFormAddWidget(QWidget *widget); 21 | void devFormAddLayout(QLayout *layout); 22 | 23 | private: 24 | Device *device; 25 | QVBoxLayout *mainLay; 26 | DeviceCommandLineForm *cmdWidget; 27 | }; 28 | 29 | 30 | class DeviceStorageForm : public DeviceForm 31 | { 32 | Q_OBJECT 33 | 34 | public: 35 | DeviceStorageForm(DeviceStorage *dev); 36 | 37 | private: 38 | DeviceStorage *device; 39 | 40 | protected slots: 41 | void editImage(); 42 | 43 | signals: 44 | void newImageSet(QString); 45 | void newDiskCompleted(QString); 46 | }; 47 | 48 | 49 | class DeviceScsiControllerForm : public DeviceForm 50 | { 51 | Q_OBJECT 52 | 53 | public: 54 | DeviceScsiControllerForm(DeviceScsiController *dev); 55 | 56 | private: 57 | DeviceScsiController *device; 58 | 59 | private slots: 60 | void setController(const QString &name); 61 | 62 | }; 63 | 64 | 65 | class DeviceCommandLineForm : public QGroupBox 66 | { 67 | Q_OBJECT 68 | 69 | public: 70 | DeviceCommandLineForm(Device *dev); 71 | void updateCmd(); 72 | 73 | private: 74 | Device *device; 75 | QTextEdit *cmdLine; 76 | QLabel *optionalLbl; 77 | QLineEdit *optionalLine; 78 | 79 | private slots: 80 | void showCmdLine(); 81 | void saveUserOptions(); 82 | }; 83 | 84 | 85 | class DeviceMemoryForm : public DeviceForm 86 | { 87 | Q_OBJECT 88 | 89 | public: 90 | DeviceMemoryForm(DeviceMemory *dev); 91 | 92 | private: 93 | DeviceMemory *device; 94 | 95 | private slots: 96 | void sizeChanged(int val); 97 | }; 98 | 99 | 100 | class DeviceNetworkForm : public DeviceForm 101 | { 102 | Q_OBJECT 103 | 104 | public: 105 | DeviceNetworkForm(DeviceNetworkController *dev); 106 | 107 | private: 108 | DeviceNetworkController *device; 109 | QLineEdit *tapIfNameEdit; 110 | QComboBox *netdevCombo; 111 | QLabel *tapIfNameLbl; 112 | 113 | void setVisibleTapSetting(); 114 | 115 | private slots: 116 | void setController(const QString &name); 117 | void setNetdev(const QString &name); 118 | void setTapIfName(); 119 | 120 | }; 121 | 122 | class DeviceCpuForm : public DeviceForm 123 | { 124 | Q_OBJECT 125 | 126 | public: 127 | DeviceCpuForm(DeviceCpu *dev); 128 | 129 | private: 130 | DeviceCpu *device; 131 | }; 132 | 133 | #endif // DEVICEFORM_H 134 | -------------------------------------------------------------------------------- /gui/QemuGUI.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMUGUI_H 2 | #define QEMUGUI_H 3 | 4 | #include 5 | #include 6 | 7 | #include "VMSettingsForm.h" 8 | #include "CreateVMForm.h" 9 | #include "RecordReplayTab.h" 10 | #include "VMConfig.h" 11 | #include "QemuLauncher.h" 12 | #include "QMPInteraction.h" 13 | #include "TerminalSettingsForm.h" 14 | #include "TerminalTab.h" 15 | #include "ConsoleTab.h" 16 | #include "ConnectionSettingsForm.h" 17 | #include "QemuRunOptions.h" 18 | 19 | enum VMState {None, Running, Stopped}; 20 | 21 | class QemuGUI : public QMainWindow 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | QemuGUI(QWidget *parent = 0); 27 | ~QemuGUI(); 28 | 29 | static void setWindowGeometry(QWidget *window, QWidget *parent); 30 | 31 | protected: 32 | bool eventFilter(QObject *target, QEvent *event); 33 | 34 | private: 35 | QemuLauncher *launch_qemu; 36 | QemuRunOptions *runOptions; 37 | 38 | VMState vm_state; 39 | QTcpSocket monitorSocket; 40 | 41 | QMenuBar *menuBar; 42 | QToolBar *mainToolBar; 43 | QToolBar *vmToolBar; 44 | QWidget *centralWidget; 45 | QStatusBar *statusBar; 46 | 47 | QDialog *runOptionsDlg; 48 | QCheckBox *debugCheckBox; 49 | QCheckBox *snapshotCheckBox; 50 | QCheckBox *qemuStoppedCheckBox; 51 | QLineEdit *cmdLineAdditionalLineEdit; 52 | QLineEdit *logfileNameLineEdit; 53 | QList logCheckBox; 54 | QString logFileName; 55 | QStringList logOptions; 56 | 57 | QAction *qemu_play; 58 | QAction *qemu_pause; 59 | QAction *qemu_stop; 60 | QAction *editVMAct; 61 | 62 | QComboBox *qemu_install_dir_combo; 63 | 64 | QListWidget *listVM; 65 | QAction *delete_act; 66 | QAction *exclude_act; 67 | 68 | QGroupBox *propBox; 69 | QTextEdit *vmInfoTextEdit; 70 | QTabWidget *tab; 71 | QWidget *tab_info; 72 | QMPInteraction *qmp; 73 | 74 | CreateVMForm *createVMWindow; 75 | RecordReplayTab *rec_replay_tab; 76 | TerminalTab *terminal_tab; 77 | ConsoleTab *consoleTab; 78 | 79 | 80 | QString qmp_port = ""; 81 | QString monitor_port = ""; 82 | 83 | LaunchMode launchMode = LaunchMode::NORMAL; 84 | 85 | private: 86 | QIcon set_button_icon_for_state(const QString &normal_icon, const QString &disable_icon); 87 | void createQemuListEditor(); 88 | void createRunOptionsDialog(); 89 | void connect_signals(); 90 | void widget_placement(); 91 | void fill_listVM_from_config(); 92 | void fill_qemu_install_dir_from_config(); 93 | void checkQemuCompatibility(); 94 | void runOptionPrepare(); 95 | 96 | public slots: 97 | void setButtonsState(bool runningState); 98 | void stop_qemu_btn_state(); 99 | void resume_qemu_btn_state(); 100 | void set_connection_settings(const QString &qmp, const QString &monitor); 101 | 102 | private slots: 103 | 104 | void currentTabChanged(int index); 105 | void refresh(); 106 | QString delete_exclude_vm(bool delete_vm); 107 | void delete_vm_ctxmenu(); 108 | void exclude_vm_ctxmenu(); 109 | void play_machine(); 110 | void play_machine(LaunchMode mode); 111 | void finish_qemu(int exitCode); 112 | void pause_machine(); 113 | void stop_machine(); 114 | void create_machine(); 115 | void add_machine(); 116 | void setRunOptions(); 117 | void edit_settings(); 118 | void listVM_item_selection_changed(); 119 | void listVM_current_item_changed(QListWidgetItem *current, QListWidgetItem *previous); 120 | void qemu_install_dir_combo_activated(int index); 121 | void set_terminal_settings(); 122 | void launch_settings(); 123 | void overlayFailed(); 124 | 125 | signals: 126 | void qmpSendCommand(QMPCommands); 127 | void monitor_connect(int); 128 | void monitor_abort(); 129 | void recordReplayEnableBtns(bool); 130 | void recordReplayStateVM(bool); 131 | void deleteRecord(); 132 | void currentQemuChanged(); 133 | 134 | }; 135 | 136 | #endif // QEMUGUI_H 137 | 138 | -------------------------------------------------------------------------------- /gui/QemuGUI.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Resources/pause.png 4 | Resources/play.png 5 | Resources/qemu.png 6 | Resources/stop.png 7 | Resources/pause_disable.png 8 | Resources/play_disable.png 9 | Resources/stop_disable.png 10 | Resources/settings.png 11 | Resources/settings_disable.png 12 | Resources/import.png 13 | Resources/import_disable.png 14 | Resources/create.png 15 | Resources/create_disable.png 16 | Resources/run_options.png 17 | Resources/run_options_mini.png 18 | Resources/replay.png 19 | 20 | 21 | -------------------------------------------------------------------------------- /gui/QemuGUICommon.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMUGUI_COMMON_H 2 | #define QEMUGUI_COMMON_H 3 | 4 | #include 5 | #include 6 | 7 | #if QT_VERSION < 0x050700 8 | template struct QOverload { 9 | template 10 | static constexpr auto of(R(C::*pmf)(Args...))->decltype(pmf) { 11 | return pmf; 12 | } 13 | }; 14 | #endif 15 | 16 | #define MAX_RAM_VALUE (32768 / 2) 17 | #define MIN_RAM_VALUE 4 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /gui/QemuInstallationsForm.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuInstallationsForm.h" 2 | #include "QemuList.h" 3 | 4 | QemuInstallationsForm::QemuInstallationsForm(QWidget *parent) 5 | : QDialog(parent) 6 | { 7 | setWindowIcon(QIcon(":Resources/qemu.png")); 8 | setWindowTitle("Qemu installation folders"); 9 | setModal(true); 10 | setAttribute(Qt::WA_DeleteOnClose); 11 | 12 | //qemu_install_dir_list = new QListWidget(); 13 | QPushButton *add_install_dir_btn = new QPushButton("Add QEMU"); 14 | add_install_dir_btn->setAutoDefault(true); 15 | QPushButton *del_install_dir_btn = new QPushButton("Delete QEMU"); 16 | del_install_dir_btn->setAutoDefault(true); 17 | 18 | QHBoxLayout *buttons_lay = new QHBoxLayout(); 19 | buttons_lay->addWidget(add_install_dir_btn); 20 | buttons_lay->addWidget(del_install_dir_btn); 21 | 22 | QVBoxLayout *layout = new QVBoxLayout(); 23 | layout->addLayout(buttons_lay); 24 | 25 | list = new QTableWidget(); 26 | layout->addWidget(list); 27 | list->setColumnCount(2); 28 | 29 | setLayout(layout); 30 | 31 | connect(add_install_dir_btn, &QPushButton::clicked, 32 | [=]() { editListItem(-1, "New installation", "", ""); } 33 | ); 34 | connect(del_install_dir_btn, SIGNAL(clicked()), 35 | this, SLOT(deleteInstallation())); 36 | connect(list, &QTableWidget::cellDoubleClicked, 37 | [=](int row, int column) 38 | { 39 | editListItem(row, "Edit installation", 40 | list->item(row, 0)->text(), 41 | list->item(row, 1)->text()); 42 | } 43 | ); 44 | 45 | reloadList(); 46 | } 47 | 48 | void QemuInstallationsForm::reloadList() 49 | { 50 | const QemuList::Items &inst = QemuList::getAllQemuInstallations(); 51 | list->setRowCount(inst.count()); 52 | list->setHorizontalHeaderLabels({"Name", "Path"}); 53 | size_t i = 0; 54 | foreach (QString name, inst.keys()) 55 | { 56 | list->setItem(i, 0, new QTableWidgetItem(name)); 57 | list->setItem(i, 1, new QTableWidgetItem(inst.value(name))); 58 | ++i; 59 | } 60 | } 61 | 62 | void QemuInstallationsForm::deleteInstallation() 63 | { 64 | if (list->currentRow() >= 0) 65 | { 66 | int answer = QMessageBox::question(this, "Deleting", "Are you sure?", 67 | QMessageBox::Yes, QMessageBox::No); 68 | if (answer == QMessageBox::Yes) 69 | { 70 | QString name = list->item(list->currentRow(), 0)->text(); 71 | QemuList::delQemuInstallation(name); 72 | reloadList(); 73 | } 74 | } 75 | } 76 | 77 | void QemuInstallationsForm::editListItem(int item, const QString &caption, 78 | const QString &name, const QString &dir) 79 | { 80 | QDialog *dlg = new QDialog(this); 81 | dlg->setWindowIcon(QIcon(":Resources/qemu.png")); 82 | dlg->setWindowTitle(caption); 83 | dlg->setModal(true); 84 | dlg->setAttribute(Qt::WA_DeleteOnClose); 85 | 86 | QHBoxLayout *topLay = new QHBoxLayout(); 87 | topLay->addWidget(new QLabel("Installation name")); 88 | nameEdit = new QLineEdit(); 89 | topLay->addWidget(nameEdit); 90 | 91 | QHBoxLayout *bottomLay = new QHBoxLayout(); 92 | bottomLay->addWidget(new QLabel("Binaries path")); 93 | pathEdit = new QLineEdit(); 94 | bottomLay->addWidget(pathEdit); 95 | QPushButton *findButton = new QPushButton("..."); 96 | findButton->setFixedWidth(30); 97 | bottomLay->addWidget(findButton); 98 | 99 | QVBoxLayout *mainLay = new QVBoxLayout(); 100 | mainLay->addLayout(topLay); 101 | mainLay->addLayout(bottomLay); 102 | QDialogButtonBox *okCancelBtn = new QDialogButtonBox(QDialogButtonBox::Ok 103 | | QDialogButtonBox::Cancel); 104 | mainLay->addWidget(okCancelBtn); 105 | 106 | dlg->setLayout(mainLay); 107 | 108 | nameEdit->setText(name); 109 | pathEdit->setText(dir); 110 | 111 | dlg->open(); 112 | 113 | connect(findButton, &QPushButton::clicked, 114 | [=]() 115 | { 116 | QString path = QFileDialog::getExistingDirectory(this, "Select Qemu directory", ""); 117 | if (path != "") 118 | { 119 | pathEdit->setText(path); 120 | } 121 | }); 122 | 123 | connect(okCancelBtn, &QDialogButtonBox::rejected, 124 | [=]() { dlg->close(); }); 125 | connect(okCancelBtn, &QDialogButtonBox::accepted, 126 | [=]() 127 | { 128 | if (nameEdit->text() != "" && pathEdit->text() != "") 129 | { 130 | if (item == -1 || nameEdit->text() != name) 131 | { 132 | if (QemuList::getQemuDir(nameEdit->text()) != "") 133 | { 134 | QMessageBox::critical(this, "Error", nameEdit->text() + " is already added"); 135 | return; 136 | } 137 | } 138 | if (item != -1) 139 | { 140 | QemuList::delQemuInstallation(name); 141 | } 142 | QemuList::addQemuInstallation(nameEdit->text(), pathEdit->text()); 143 | reloadList(); 144 | dlg->close(); 145 | } 146 | else 147 | { 148 | QMessageBox::critical(this, "Error", "Name and path should be specified"); 149 | } 150 | }); 151 | } 152 | -------------------------------------------------------------------------------- /gui/QemuInstallationsForm.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMUINSTALLATIONSFORM_H 2 | #define QEMUINSTALLATIONSFORM_H 3 | 4 | #include 5 | #include 6 | 7 | class QemuInstallationsForm : public QDialog 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | QemuInstallationsForm(QWidget *parent = 0); 13 | 14 | private: 15 | void editListItem(int item, const QString &caption, 16 | const QString &name, const QString &dir); 17 | void reloadList(); 18 | 19 | //QListWidget *qemu_install_dir_list; 20 | QTableWidget *list; 21 | // Add/Edit dialog widgets 22 | QLineEdit *nameEdit; 23 | QLineEdit *pathEdit; 24 | 25 | private slots: 26 | void deleteInstallation(); 27 | }; 28 | 29 | #endif // QEMUINSTALLATIONSFORM_H 30 | -------------------------------------------------------------------------------- /gui/RecordReplayTab.h: -------------------------------------------------------------------------------- 1 | #ifndef RECORDREPLAYTAB_H 2 | #define RECORDREPLAYTAB_H 3 | 4 | #include 5 | #include "VMConfig.h" 6 | #include "QemuLauncher.h" 7 | #include "RecordReplayParams.h" 8 | 9 | class RecordReplayTab : public QWidget 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | RecordReplayTab(QWidget *parent = 0); 15 | ~RecordReplayTab(); 16 | 17 | void setVM(VMConfig *virtualMachine); 18 | void clearVM(); 19 | 20 | const RecordReplayParams &getRecordReplayParams() const { return rrParams; } 21 | 22 | private: 23 | VMConfig *vm; 24 | QWidget *pWidget; 25 | 26 | private: 27 | void connect_signals(); 28 | void executionListConnectSignals(); 29 | void widget_placement(); 30 | void createXml(); 31 | void setCurrentDir(const QString &name); 32 | void createDialog(const QString &caption); 33 | bool checkPeriodSet(); 34 | bool checkReplayForm(); 35 | QHBoxLayout *periodLayout(int width); 36 | QHBoxLayout *overlayLayout(); 37 | QStringList getSnapshotInfo(); 38 | 39 | private: 40 | QListWidget *executionList; 41 | QPushButton *rec_btn; 42 | QPushButton *rpl_btn; 43 | QAction *renameAct; 44 | QAction *deleteAct; 45 | QAction *deleteAllAct; 46 | 47 | QDialog *replayDialog; 48 | QLineEdit *nameEdit; 49 | QSpinBox *icountSpin; 50 | QCheckBox *periodCheckBox; 51 | QLineEdit *periodLineEdit; 52 | QCheckBox *overlayCheck; 53 | QComboBox *snapshotCombo; 54 | QString commonDirRR; 55 | QString oldRRName; 56 | QString nameReplay; 57 | QString icountValue; 58 | QStringList snapshotTips; 59 | bool isNotRunning; 60 | RecordReplayParams rrParams; 61 | 62 | private slots: 63 | void record_execution(); 64 | void replay_execution(); 65 | void rename_ctxmenu(); 66 | void delete_ctxmenu(); 67 | void deleteAllCtxmenu(); 68 | void setRRNameDir(); 69 | void setPeriodSnapReplay(); 70 | void renameRRRecord(); 71 | void executionListItemClicked(QListWidgetItem *item); 72 | void autoSnapshotEnabled(int state); 73 | void setAutoSnapshotEnabled(int value); 74 | 75 | public slots: 76 | void enableBtns(bool state); 77 | void setState(bool state); 78 | void recordDeleteRecords(); 79 | void deleteRecordFolder(); 80 | void executionListItemSelectionChanged(); 81 | void executionListItemRowChanged(int currentRow); 82 | void replayCurrentQemuChanged(); 83 | bool isExecutionsExist(); 84 | 85 | signals: 86 | void startRR(LaunchMode mode); 87 | }; 88 | 89 | 90 | /****************************************************************************** 91 | * EXECUTION_LIST DELEGATE * 92 | ******************************************************************************/ 93 | 94 | class RecordRRDelegate : public QItemDelegate 95 | { 96 | Q_OBJECT 97 | 98 | public: 99 | RecordRRDelegate(QObject *parent = 0); 100 | QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, 101 | const QModelIndex &index) const; 102 | void setEditorData(QWidget *editor, const QModelIndex &index) const; 103 | void setModelData(QWidget *editor, QAbstractItemModel *model, 104 | const QModelIndex &index) const; 105 | 106 | private slots: 107 | void editingFinished(); 108 | 109 | signals: 110 | void renamingEnded(); 111 | }; 112 | 113 | #endif // RECORDREPLAYTAB_H 114 | -------------------------------------------------------------------------------- /gui/Resources/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/create.png -------------------------------------------------------------------------------- /gui/Resources/create_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/create_disable.png -------------------------------------------------------------------------------- /gui/Resources/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/import.png -------------------------------------------------------------------------------- /gui/Resources/import_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/import_disable.png -------------------------------------------------------------------------------- /gui/Resources/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/pause.png -------------------------------------------------------------------------------- /gui/Resources/pause_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/pause_disable.png -------------------------------------------------------------------------------- /gui/Resources/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/play.png -------------------------------------------------------------------------------- /gui/Resources/play_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/play_disable.png -------------------------------------------------------------------------------- /gui/Resources/qemu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/qemu.png -------------------------------------------------------------------------------- /gui/Resources/replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/replay.png -------------------------------------------------------------------------------- /gui/Resources/run_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/run_options.png -------------------------------------------------------------------------------- /gui/Resources/run_options_mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/run_options_mini.png -------------------------------------------------------------------------------- /gui/Resources/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/settings.png -------------------------------------------------------------------------------- /gui/Resources/settings_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/settings_disable.png -------------------------------------------------------------------------------- /gui/Resources/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/stop.png -------------------------------------------------------------------------------- /gui/Resources/stop_disable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ispras/qemu-gui/08650ac6b7fe040f40416e6d3fcb9082611da8c7/gui/Resources/stop_disable.png -------------------------------------------------------------------------------- /gui/TerminalSettingsForm.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuGUICommon.h" 2 | #include "TerminalSettingsForm.h" 3 | 4 | TerminalSettingsForm::TerminalSettingsForm(QTextEdit *terminal, QWidget *parent) 5 | : QWidget(parent) 6 | { 7 | if (TerminalSettingsForm::objectName().isEmpty()) 8 | TerminalSettingsForm::setObjectName(QStringLiteral("TerminalSettings")); 9 | resize(484, 214); 10 | 11 | setWindowTitle(QApplication::translate("TerminalSettings", "Terminal interface settings", Q_NULLPTR)); 12 | setWindowIcon(QIcon(":Resources/settings.png")); 13 | //setWindowModality(Qt::ApplicationModal); 14 | setWindowFlags(Qt::MSWindowsFixedSizeDialogHint); 15 | 16 | 17 | QPushButton *color_background_btn = new QPushButton("Select color", this); 18 | QPushButton *color_text_btn = new QPushButton("Select color", this); 19 | QFontComboBox *font_combo = new QFontComboBox(this); 20 | QSpinBox *font_size_spin = new QSpinBox(this); 21 | test_text = new QTextEdit(this); 22 | QDialogButtonBox *savecancel_btn = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel); 23 | 24 | QGroupBox *font_group = new QGroupBox("Text settings", this); 25 | QGroupBox *background_group = new QGroupBox("Background settings", this); 26 | 27 | QHBoxLayout *font_lay = new QHBoxLayout(); 28 | font_lay->addWidget(font_combo); 29 | font_lay->addWidget(font_size_spin); 30 | 31 | QVBoxLayout *text_lay = new QVBoxLayout(); 32 | text_lay->addLayout(font_lay); 33 | text_lay->addWidget(color_text_btn); 34 | 35 | font_group->setLayout(text_lay); 36 | 37 | QVBoxLayout *back_lay = new QVBoxLayout(); 38 | back_lay->addWidget(color_background_btn); 39 | 40 | background_group->setLayout(back_lay); 41 | 42 | QVBoxLayout *btns_lay = new QVBoxLayout(); 43 | btns_lay->addWidget(font_group); 44 | btns_lay->addWidget(background_group); 45 | btns_lay->addStretch(20); 46 | btns_lay->addWidget(savecancel_btn); 47 | 48 | QHBoxLayout *main_lay = new QHBoxLayout(this); 49 | main_lay->addLayout(btns_lay); 50 | main_lay->addWidget(test_text); 51 | 52 | font_combo->setFontFilters(QFontComboBox::FontFilter::MonospacedFonts); 53 | font_combo->setCurrentText(terminal->fontFamily()); 54 | font_size_spin->setValue(terminal->fontPointSize()); 55 | font_size_spin->setMinimum(2); 56 | // current values 57 | test_text->setFontPointSize(terminal->fontPointSize()); 58 | test_text->setFontFamily(terminal->fontFamily()); 59 | test_text->setStyleSheet(terminal->styleSheet()); 60 | test_text->setTextColor(terminal->textColor()); 61 | test_text->setText("Hello, world!"); 62 | 63 | show(); 64 | 65 | connect(color_background_btn, SIGNAL(clicked()), this, SLOT(set_background_color())); 66 | connect(color_text_btn, SIGNAL(clicked()), this, SLOT(set_text_color())); 67 | connect(font_combo, SIGNAL(currentFontChanged(const QFont &)), this, SLOT(set_test_font(const QFont &))); 68 | connect(font_size_spin, QOverload::of(&QSpinBox::valueChanged), this, &TerminalSettingsForm::set_text_size); 69 | 70 | connect(savecancel_btn, &QDialogButtonBox::accepted, this, &TerminalSettingsForm::save_terminal_interface_changes); 71 | connect(savecancel_btn, &QDialogButtonBox::rejected, this, &QWidget::close); 72 | } 73 | 74 | TerminalSettingsForm::~TerminalSettingsForm() 75 | { 76 | } 77 | 78 | 79 | void TerminalSettingsForm::set_background_color() 80 | { 81 | QColor color = QColorDialog::getColor(); 82 | if (color.isValid()) 83 | { 84 | test_text->setStyleSheet("background-color: " + color.name() + "; border: 1px"); 85 | } 86 | } 87 | 88 | void TerminalSettingsForm::set_text_color() 89 | { 90 | QColor color = QColorDialog::getColor(); 91 | if (color.isValid()) 92 | { 93 | test_text->setTextColor(color); 94 | test_text->setText("Hello, world!"); 95 | } 96 | } 97 | 98 | void TerminalSettingsForm::set_text_size(int size) 99 | { 100 | test_text->setFontPointSize(size); 101 | test_text->setText("Hello, world!"); 102 | } 103 | 104 | void TerminalSettingsForm::set_test_font(const QFont &font) 105 | { 106 | test_text->setFontFamily(font.family()); 107 | test_text->setText("Hello, world!"); 108 | } 109 | 110 | void TerminalSettingsForm::save_terminal_interface_changes() 111 | { 112 | emit save_terminal_settings(test_text); 113 | close(); 114 | } 115 | 116 | 117 | -------------------------------------------------------------------------------- /gui/TerminalSettingsForm.h: -------------------------------------------------------------------------------- 1 | #ifndef TERMINALSETTINSFORM_H 2 | #define TERMINALSETTINSFORM_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | 9 | class TerminalSettingsForm : public QWidget 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | TerminalSettingsForm(QTextEdit *terminal, QWidget *parent = 0); 15 | ~TerminalSettingsForm(); 16 | 17 | private: 18 | QTextEdit *test_text; 19 | 20 | private slots : 21 | void save_terminal_interface_changes(); 22 | void set_background_color(); 23 | void set_text_color(); 24 | void set_text_size(int size); 25 | void set_test_font(const QFont &font); 26 | 27 | public slots: 28 | 29 | signals: 30 | void save_terminal_settings(QTextEdit *); 31 | 32 | }; 33 | 34 | 35 | #endif //TERMINALSETTINSFORM_H 36 | 37 | 38 | -------------------------------------------------------------------------------- /gui/TerminalTab.cpp: -------------------------------------------------------------------------------- 1 | #include "TerminalTab.h" 2 | #include "GlobalConfig.h" 3 | 4 | TerminalTab::TerminalTab(QWidget *parent) 5 | : QWidget(parent) 6 | { 7 | terminalText = new QTextEdit(); 8 | welcomeLbl = new QLabel(" >> "); 9 | terminalCmd = new QLineEdit(); 10 | terminalCmd->installEventFilter(this); 11 | 12 | setTerminalInterface(GlobalConfig::get_terminal_backgroud(), 13 | GlobalConfig::get_terminal_text_color(), 14 | GlobalConfig::get_terminal_font_family(), 15 | GlobalConfig::get_terminal_font_size()); 16 | 17 | QHBoxLayout *cmd_lay = new QHBoxLayout(); 18 | cmd_lay->setSpacing(0); 19 | cmd_lay->addWidget(welcomeLbl); 20 | cmd_lay->addWidget(terminalCmd); 21 | 22 | QVBoxLayout *terminal_lay = new QVBoxLayout(); 23 | terminal_lay->setSpacing(1); 24 | terminal_lay->addWidget(terminalText); 25 | terminal_lay->addLayout(cmd_lay); 26 | setLayout(terminal_lay); 27 | 28 | connect(terminalCmd, SIGNAL(returnPressed()), this, SLOT(sendMonitorCommand())); 29 | connect(&monitorSocket, SIGNAL(readyRead()), this, SLOT(readTerminal())); 30 | 31 | currentCommandIndex = -1; 32 | } 33 | 34 | TerminalTab::~TerminalTab() 35 | { 36 | 37 | } 38 | 39 | 40 | void TerminalTab::setTerminalInterface(QColor bckgrnd_color, QColor text_color, 41 | const QString &font_family, int font_size) 42 | { 43 | QString color = text_color.name(); 44 | 45 | terminalText->setReadOnly(true); 46 | terminalText->setFontPointSize(font_size); 47 | terminalText->setFontFamily(font_family); 48 | terminalText->setStyleSheet("background-color: " + bckgrnd_color.name() 49 | + "; border: 1px"); 50 | terminalText->setTextColor(text_color); 51 | 52 | 53 | QFont cmd_font = terminalCmd->font(); 54 | cmd_font.setPointSize(font_size); 55 | cmd_font.setFamily(font_family); 56 | terminalCmd->setFont(cmd_font); 57 | terminalCmd->setStyleSheet("background-color: " + bckgrnd_color.name() 58 | + "; border: 1px; color: " + color + "; height: " 59 | + QString::number(font_size * 2) + "px;"); 60 | 61 | welcomeLbl->setStyleSheet("background-color: " + bckgrnd_color.name() 62 | + "; color: " + color + "; border: 1px; height: " 63 | + QString::number(font_size * 2) + "px; font: bold;"); 64 | welcomeLbl->setFont(cmd_font); 65 | 66 | QString text = terminalText->toPlainText(); 67 | terminalText->clear(); 68 | terminalText->insertPlainText(text); 69 | terminalText->ensureCursorVisible(); 70 | } 71 | 72 | QTextEdit *TerminalTab::getTerminalText() 73 | { 74 | return terminalText; 75 | } 76 | 77 | void TerminalTab::setCommmandLineFocus() 78 | { 79 | terminalCmd->setFocus(); 80 | } 81 | 82 | bool TerminalTab::eventFilter(QObject *obj, QEvent *event) 83 | { 84 | if (obj == terminalCmd) 85 | { 86 | if (event->type() == QEvent::KeyPress) 87 | { 88 | QKeyEvent* keyEvent = static_cast(event); 89 | if (keyEvent->key() == Qt::Key_Up) 90 | { 91 | if (currentCommandIndex + 1 < savedTerminalCmds.size()) 92 | { 93 | terminalCmd->setText(savedTerminalCmds.at(++currentCommandIndex)); 94 | } 95 | return true; 96 | } 97 | else if (keyEvent->key() == Qt::Key_Down) 98 | { 99 | if (currentCommandIndex - 1 >= 0) 100 | { 101 | terminalCmd->setText(savedTerminalCmds.at(--currentCommandIndex)); 102 | } 103 | else 104 | { 105 | currentCommandIndex = -1; 106 | terminalCmd->setText(""); 107 | } 108 | return true; 109 | } 110 | } 111 | return false; 112 | } 113 | return QWidget::eventFilter(obj, event); 114 | } 115 | 116 | void TerminalTab::sendMonitorCommand() 117 | { 118 | monitorSocket.write(terminalCmd->text().toLocal8Bit() + "\n"); 119 | QTextCursor cursor(terminalText->textCursor()); 120 | cursor.movePosition(QTextCursor::End); 121 | terminalText->setTextCursor(cursor); 122 | terminalText->insertPlainText(terminalCmd->text() + "\n"); 123 | savedTerminalCmds.push_front(terminalCmd->text()); 124 | terminalCmd->clear(); 125 | currentCommandIndex = -1; 126 | } 127 | 128 | void TerminalTab::terminalTab_connect(int port) 129 | { 130 | terminalText->clear(); 131 | monitorSocket.connectPort(port); 132 | } 133 | 134 | void TerminalTab::readTerminal() 135 | { 136 | QStringList terminal_answer = (QString::fromLocal8Bit(monitorSocket.readAll())).split('\n'); 137 | foreach(QString line, terminal_answer) 138 | { 139 | if (!line.contains("[D") && !line.contains("[K")) 140 | { 141 | terminalText->insertPlainText(line); 142 | } 143 | } 144 | terminalText->ensureCursorVisible(); 145 | } 146 | 147 | 148 | void TerminalTab::terminalTab_abort() 149 | { 150 | monitorSocket.abort(); 151 | } 152 | 153 | void TerminalTab::save_terminal_interface_changes(QTextEdit *test_text) 154 | { 155 | QString style = test_text->styleSheet(); 156 | QStringList style_list = style.split(QRegExp("\\W+"), QString::SkipEmptyParts); 157 | int index = style_list.indexOf("background"); 158 | 159 | setTerminalInterface(QColor("#" + style_list.at(index + 2)), test_text->textColor(), 160 | test_text->fontFamily(), test_text->fontPointSize()); 161 | GlobalConfig::set_terminal_parameters(QColor("#" + style_list.at(index + 2)), 162 | test_text->textColor(), test_text->fontFamily(), test_text->fontPointSize()); 163 | } 164 | -------------------------------------------------------------------------------- /gui/TerminalTab.h: -------------------------------------------------------------------------------- 1 | #ifndef TERMINALTAB_H 2 | #define TERMINALTAB_H 3 | 4 | #include 5 | #include 6 | #include "QemuSocket.h" 7 | 8 | 9 | class TerminalTab : public QWidget 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | TerminalTab(QWidget *parent = 0); 15 | ~TerminalTab(); 16 | 17 | protected: 18 | bool eventFilter(QObject *target, QEvent *event); 19 | 20 | private: 21 | QTextEdit *terminalText; 22 | QLabel *welcomeLbl; 23 | QLineEdit *terminalCmd; 24 | 25 | QStringList savedTerminalCmds; 26 | 27 | QemuSocket monitorSocket; 28 | 29 | int currentCommandIndex; 30 | 31 | private: 32 | void setTerminalInterface(QColor bckgrnd_color, QColor text_color, 33 | const QString &font_family, int font_size); 34 | 35 | public: 36 | QTextEdit *getTerminalText(); 37 | void setCommmandLineFocus(); 38 | 39 | private slots: 40 | void sendMonitorCommand(); 41 | void readTerminal(); 42 | 43 | public slots: 44 | void terminalTab_connect(int port); 45 | void terminalTab_abort(); 46 | void save_terminal_interface_changes(QTextEdit *test_text); 47 | 48 | }; 49 | 50 | 51 | 52 | 53 | #endif //TERMINALTAB_H 54 | -------------------------------------------------------------------------------- /gui/VMPropertiesForm.cpp: -------------------------------------------------------------------------------- 1 | #include "VMPropertiesForm.h" 2 | 3 | VMPropertiesForm::VMPropertiesForm(QWidget *parent, const QString &caption) 4 | { 5 | QGroupBox *form = this; 6 | form->setTitle(caption); 7 | 8 | kernelEdit = new QLineEdit(this); 9 | initrdEdit = new QLineEdit(this); 10 | kernelBtn = new QPushButton("..."); 11 | initrdBtn = new QPushButton("..."); 12 | 13 | const char regExpForName[] = "[A-Za-z0-9_-][A-Za-z0-9 _-s:/.~()\"]+"; 14 | kernelEdit->setValidator(new QRegExpValidator(QRegExp(regExpForName), this)); 15 | initrdEdit->setValidator(new QRegExpValidator(QRegExp(regExpForName), this)); 16 | 17 | kernelBtn->setFixedWidth(30); 18 | kernelBtn->setAutoDefault(true); 19 | initrdBtn->setFixedWidth(30); 20 | initrdBtn->setAutoDefault(true); 21 | 22 | QGridLayout *kernelLay = new QGridLayout(); 23 | kernelLay->addWidget(new QLabel("Kernel"), 0, 0); 24 | kernelLay->addWidget(kernelEdit, 0, 1); 25 | kernelLay->addWidget(kernelBtn, 0, 2); 26 | kernelLay->addWidget(new QLabel("Initial ram disk"), 1, 0); 27 | kernelLay->addWidget(initrdEdit, 1, 1); 28 | kernelLay->addWidget(initrdBtn, 1, 2); 29 | 30 | form->setLayout(kernelLay); 31 | 32 | connect(kernelBtn, SIGNAL(clicked()), this, SLOT(setSystemFile())); 33 | connect(initrdBtn, SIGNAL(clicked()), this, SLOT(setSystemFile())); 34 | } 35 | 36 | void VMPropertiesForm::setSystemFile() 37 | { 38 | QString filename = QFileDialog::getOpenFileName(this, "Select file", 39 | "", "*.*"); // what about format? 40 | if (!filename.isEmpty()) 41 | { 42 | if (sender() == kernelBtn) 43 | { 44 | kernelEdit->setText(filename); 45 | } 46 | else 47 | { 48 | initrdEdit->setText(filename); 49 | } 50 | } 51 | } 52 | 53 | QString VMPropertiesForm::getKernel() const 54 | { 55 | return kernelEdit->text(); 56 | } 57 | 58 | QString VMPropertiesForm::getInitrd() const 59 | { 60 | return initrdEdit->text(); 61 | } 62 | 63 | void VMPropertiesForm::setKernel(const QString &filename) 64 | { 65 | kernelEdit->setText(filename); 66 | } 67 | 68 | void VMPropertiesForm::setInitrd(const QString &filename) 69 | { 70 | initrdEdit->setText(filename); 71 | } 72 | 73 | -------------------------------------------------------------------------------- /gui/VMPropertiesForm.h: -------------------------------------------------------------------------------- 1 | #ifndef VMPROPERTIESFORM_H 2 | #define VMPROPERTIESFORM_H 3 | 4 | #include "QtWidgets" 5 | 6 | class VMPropertiesForm : public QGroupBox 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | VMPropertiesForm(QWidget *parent = 0, const QString &caption = ""); 12 | 13 | private: 14 | QLineEdit *kernelEdit; 15 | QPushButton *kernelBtn; 16 | QLineEdit *initrdEdit; 17 | QPushButton *initrdBtn; 18 | 19 | private slots: 20 | void setSystemFile(); 21 | 22 | public: 23 | QString getKernel() const; 24 | QString getInitrd() const; 25 | void setKernel(const QString &filename); 26 | void setInitrd(const QString &filename); 27 | 28 | 29 | }; 30 | 31 | #endif // VMPROPERTIESFORM_H 32 | 33 | -------------------------------------------------------------------------------- /gui/VMSettingsForm.cpp: -------------------------------------------------------------------------------- 1 | #include "VMSettingsForm.h" 2 | #include "GlobalConfig.h" 3 | #include "DeviceFactory.h" 4 | #include "PlatformInformationReader.h" 5 | #include "PlatformInfo.h" 6 | #include "common/FileHelpers.h" 7 | #include "config/QemuList.h" 8 | 9 | VMSettingsForm::VMSettingsForm(VMConfig *vmconf, 10 | const QString &qemuName, QWidget *parent) 11 | : QWidget(parent), vm(vmconf) 12 | { 13 | if (VMSettingsForm::objectName().isEmpty()) 14 | VMSettingsForm::setObjectName(QStringLiteral("VMSettingsForm")); 15 | resize(420, 380); 16 | setWindowTitle(QApplication::translate("VMSettingsForm", "VM Settings", Q_NULLPTR)); 17 | setWindowModality(Qt::WindowModality::ApplicationModal); 18 | setWindowIcon(QIcon(":Resources/settings.png")); 19 | 20 | deviceTree = new QTreeWidget(); 21 | savecancel_btn = new QDialogButtonBox(QDialogButtonBox::Apply 22 | | QDialogButtonBox::Save | QDialogButtonBox::Cancel); 23 | 24 | addCmdLineParamsEdit = new QLineEdit(); 25 | addCmdLineParamsEdit->setText(vm->getCmdLine()); 26 | 27 | kernelForm = new VMPropertiesForm(); 28 | kernelForm->setKernel(vm->getKernel()); 29 | kernelForm->setInitrd(vm->getInitrd()); 30 | 31 | savecancel_btn->button(QDialogButtonBox::Save)->setDefault(true); 32 | savecancel_btn->button(QDialogButtonBox::Cancel)->setAutoDefault(true); 33 | savecancel_btn->button(QDialogButtonBox::Apply)->setAutoDefault(true); 34 | 35 | deviceTree->setContextMenuPolicy(Qt::CustomContextMenu); 36 | deviceTree->setHeaderHidden(1); 37 | deviceTree->setColumnCount(1); 38 | 39 | pathToPlatformInfo = QemuList::getQemuProfilePath(qemuName) 40 | + "/" + vm->getPlatform(); 41 | 42 | addDev = NULL; 43 | addedDevices.clear(); 44 | 45 | foreach(Device *dev, vm->getSystemDevice()->getDevices()) 46 | { 47 | dev->setPathToConfig(pathToPlatformInfo); 48 | DeviceTreeItem *it = new DeviceTreeItem(dev); 49 | if (dev->isDeviceInvisible()) 50 | { 51 | delete it; 52 | } 53 | else 54 | { 55 | deviceTree->invisibleRootItem()->addChild(it); 56 | } 57 | } 58 | 59 | connect_signals(); 60 | widget_placement(); 61 | 62 | deviceTree->setItemSelected(deviceTree->itemAt(0, 0), true); 63 | show(); 64 | } 65 | 66 | VMSettingsForm::~VMSettingsForm() 67 | { 68 | delete kernelForm; 69 | } 70 | 71 | void VMSettingsForm::connect_signals() 72 | { 73 | connect(deviceTree, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), 74 | this, SLOT(deviceTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *))); 75 | 76 | connect(savecancel_btn, &QDialogButtonBox::accepted, 77 | this, &VMSettingsForm::save_settings); 78 | connect(savecancel_btn, &QDialogButtonBox::rejected, 79 | this, &VMSettingsForm::closeForm); 80 | connect(savecancel_btn->button(QDialogButtonBox::Apply), &QPushButton::clicked, 81 | this, &VMSettingsForm::applySettings); 82 | 83 | connect(deviceTree, &QTreeWidget::customContextMenuRequested, 84 | this, &VMSettingsForm::showContextMenu); 85 | 86 | connect(&menu, &QMenu::aboutToHide, this, &VMSettingsForm::menuClose); 87 | } 88 | 89 | QWidget* VMSettingsForm::emptyForm() 90 | { 91 | QGroupBox *deviceInfoGroup = new QGroupBox(); 92 | QHBoxLayout *infoLay = new QHBoxLayout(); 93 | QLabel *infoLbl = new QLabel("", deviceInfoGroup); 94 | infoLay->addStretch(50); 95 | infoLay->addWidget(infoLbl); 96 | infoLay->addStretch(50); 97 | deviceInfoGroup->setLayout(infoLay); 98 | return deviceInfoGroup; 99 | } 100 | 101 | void VMSettingsForm::closeEvent(QCloseEvent *event) 102 | { 103 | closeForm(); 104 | } 105 | 106 | void VMSettingsForm::removingDevFromDevices(Device * dev) 107 | { 108 | Device *devParent = dynamic_cast(dev->parent()); 109 | Q_ASSERT(devParent); 110 | devParent->removeDevice(dev); 111 | } 112 | 113 | bool VMSettingsForm::changesVerification() 114 | { 115 | if (kernelForm->getKernel().isEmpty() && !kernelForm->getInitrd().isEmpty()) 116 | { 117 | QMessageBox::warning(this, "Error", "Must be selected 'Kernel' file"); 118 | return false; 119 | } 120 | return true; 121 | } 122 | 123 | Device *VMSettingsForm::isDevicesValid(Device *device) 124 | { 125 | Device *retDevice = NULL; 126 | foreach(Device *dev, device->getDevices()) 127 | { 128 | if (!dev->isDeviceValid()) 129 | { 130 | retDevice = dev; 131 | } 132 | if (!retDevice) 133 | { 134 | retDevice = isDevicesValid(dev); 135 | } 136 | } 137 | return retDevice; 138 | } 139 | 140 | void VMSettingsForm::widget_placement() 141 | { 142 | splitter = new QSplitter(); 143 | splitter->addWidget(deviceTree); 144 | splitter->addWidget(emptyForm()); 145 | 146 | splitter->setSizes(QList{150, 250}); 147 | 148 | QGroupBox *addCmdLineParamsGrpoup = new QGroupBox("Additional vitrual machine options"); 149 | QVBoxLayout *addCmdLay = new QVBoxLayout(); 150 | addCmdLay->addWidget(addCmdLineParamsEdit); 151 | addCmdLineParamsGrpoup->setLayout(addCmdLay); 152 | 153 | QVBoxLayout *main = new QVBoxLayout(this); 154 | main->addWidget(splitter); 155 | main->addWidget(kernelForm); 156 | main->addWidget(addCmdLineParamsGrpoup); 157 | main->addStretch(100); 158 | main->addWidget(savecancel_btn); 159 | } 160 | 161 | bool VMSettingsForm::applySettings() 162 | { 163 | bool isExecutionList = emit isExecutionListNotEmpty(); 164 | QString message = isExecutionList ? "All recorded executions will be removed. " : ""; 165 | int answer = QMessageBox::question(this, "Saving", 166 | message + "Are you sure?", 167 | QMessageBox::Yes, QMessageBox::No); 168 | if (answer == QMessageBox::Yes && changesVerification()) 169 | { 170 | vm->setCmdLine(addCmdLineParamsEdit->text()); 171 | vm->setKernel(kernelForm->getKernel()); 172 | vm->setInitrd(kernelForm->getInitrd()); 173 | vm->save_vm_config(); 174 | FileHelpers::deleteDirectory(vm->getPathRRDir()); 175 | if (isExecutionList) 176 | { 177 | emit settingsDeleteRecords(); 178 | } 179 | emit updateVMInfo(); 180 | return true; 181 | } 182 | return false; 183 | } 184 | 185 | void VMSettingsForm::save_settings() 186 | { 187 | Device *dev = isDevicesValid(vm->getSystemDevice()); 188 | if (!dev) 189 | { 190 | if (applySettings()) 191 | { 192 | close(); 193 | } 194 | } 195 | else 196 | { 197 | QMessageBox::critical(this, "Error", 198 | "Device " + dev->getDescription() + " has invalid information"); 199 | } 200 | } 201 | 202 | void VMSettingsForm::deviceTreeItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) 203 | { 204 | DeviceTreeItem *devItem = dynamic_cast(current); 205 | Q_ASSERT(devItem); 206 | 207 | Device *dev = devItem->getDevice(); 208 | QWidget *form = dev->getEditorForm(); 209 | 210 | delete splitter->widget(1); 211 | if (form) 212 | { 213 | splitter->addWidget(form); 214 | } 215 | else 216 | { 217 | splitter->addWidget(emptyForm()); 218 | } 219 | splitter->setSizes(QList{150, 250}); 220 | } 221 | 222 | void VMSettingsForm::showContextMenu(const QPoint &pos) 223 | { 224 | QTreeWidgetItem *item = deviceTree->itemAt(pos); 225 | if (item) 226 | { 227 | deviceTree->setCurrentItem(item); 228 | 229 | DeviceTreeItem *devItem = dynamic_cast(item); 230 | Q_ASSERT(devItem); 231 | Device *dev = devItem->getDevice(); 232 | 233 | addDev = new AddDeviceForm(dev, this); 234 | addDev->setAttribute(Qt::WA_DeleteOnClose); 235 | if (addDev->getAddDevicesCount()) 236 | { 237 | QAction *addDeviceAct = new QAction("Add device", this); 238 | addDeviceAct->setStatusTip(tr("Add device")); 239 | 240 | connect(addDeviceAct, SIGNAL(triggered()), addDev, SLOT(addDevice())); 241 | connect(addDev, SIGNAL(deviceWantsToAdd(Device *)), 242 | this, SLOT(addNewDevice(Device *))); 243 | 244 | menu.addAction(addDeviceAct); 245 | } 246 | 247 | if (dev->isRemovable()) 248 | { 249 | QAction *removeDeviceAct = new QAction("Remove device", this); 250 | removeDeviceAct->setStatusTip(tr("Remove device")); 251 | connect(removeDeviceAct, SIGNAL(triggered()), this, SLOT(removeDevice())); 252 | menu.addAction(removeDeviceAct); 253 | } 254 | if (!menu.isEmpty()) 255 | { 256 | menu.exec(deviceTree->mapToGlobal(pos)); 257 | } 258 | else 259 | { 260 | delete addDev; 261 | } 262 | } 263 | /* 264 | TODO 265 | else 266 | { 267 | qDebug() << "add add add"; 268 | QAction *addDeviceAct = new QAction("Add system device (dont use it)", this); 269 | addDeviceAct->setStatusTip(tr("Add system device")); 270 | 271 | AddDeviceForm *addSystemDev = NULL;//new AddDeviceForm(QStringList({ "Usb", "...", })); 272 | addSystemDev->setAttribute(Qt::WA_DeleteOnClose); 273 | 274 | connect(addDeviceAct, SIGNAL(triggered()), addSystemDev, SLOT(addDevice())); 275 | connect(addSystemDev, SIGNAL(deviceWantsToAdd(const QString &)), 276 | this, SLOT(addNewSystemDevice(const QString &))); 277 | 278 | QMenu menu(this); 279 | menu.addAction(addDeviceAct); 280 | 281 | menu.exec(deviceTree->mapToGlobal(pos)); 282 | } 283 | */ 284 | } 285 | 286 | void VMSettingsForm::addNewDevice(Device *newDevice) 287 | { 288 | /* TODO: devices can have various count of children */ 289 | DeviceTreeItem *devItem = dynamic_cast(deviceTree->currentItem()); 290 | Q_ASSERT(devItem); 291 | Device *dev = devItem->getDevice(); 292 | newDevice->setPathToConfig(dev->getPathToConfig()); 293 | if (devItem->childCount() < dev->getMaxCountDevices()) 294 | { 295 | addedDevices.append(newDevice); 296 | dev->addDevice(newDevice); 297 | DeviceTreeItem *it = new DeviceTreeItem(newDevice); 298 | deviceTree->currentItem()->addChild(it); 299 | deviceTree->setCurrentItem(it); 300 | deviceTreeItemChanged(it, NULL); 301 | } 302 | else 303 | { 304 | QMessageBox::critical(this, "Error", "Too much devices"); 305 | } 306 | } 307 | 308 | void VMSettingsForm::addNewSystemDevice(const QString &devName) 309 | { 310 | if (QString::compare(devName, "Usb") == 0) 311 | { 312 | vm->addUsbDevice(); 313 | QTreeWidgetItem *item = new QTreeWidgetItem(); 314 | item->setText(0, "Usb"); 315 | deviceTree->invisibleRootItem()->addChild(item); 316 | } 317 | } 318 | 319 | void VMSettingsForm::removeDevice() 320 | { 321 | DeviceTreeItem *devItem = dynamic_cast(deviceTree->currentItem()); 322 | Q_ASSERT(devItem); 323 | Device *dev = devItem->getDevice(); 324 | int answer = QMessageBox::question(this, "Removing", 325 | "Device " + dev->getDescription() + " will be removed. Are you sure?", 326 | QMessageBox::Yes, QMessageBox::No); 327 | if (answer == QMessageBox::Yes) 328 | { 329 | removingDevFromDevices(dev); 330 | deviceTree->setCurrentItem(devItem->parent()); 331 | deviceTreeItemChanged(devItem->parent(), NULL); 332 | delete devItem; 333 | } 334 | } 335 | 336 | void VMSettingsForm::menuClose() 337 | { 338 | if (!menu.activeAction()) 339 | { 340 | delete addDev; 341 | } 342 | menu.clear(); 343 | } 344 | 345 | void VMSettingsForm::closeForm() 346 | { 347 | foreach(Device *dev, addedDevices) 348 | { 349 | removingDevFromDevices(dev); 350 | } 351 | addedDevices.clear(); 352 | vm->readVMConfig(); 353 | close(); 354 | } 355 | 356 | /*************************************************************************** 357 | * DeviceTreeItem * 358 | ***************************************************************************/ 359 | 360 | DeviceTreeItem::DeviceTreeItem(Device *dev) 361 | { 362 | initDevice(dev); 363 | } 364 | 365 | void DeviceTreeItem::initDevice(Device *dev) 366 | { 367 | device = dev; 368 | setText(0, device->getDescription()); 369 | foreach(Device *dev, device->getDevices()) 370 | { 371 | dev->setPathToConfig(device->getPathToConfig()); 372 | DeviceTreeItem *it = new DeviceTreeItem(dev); 373 | addChild(it); 374 | } 375 | } 376 | 377 | Device *DeviceTreeItem::getDevice() 378 | { 379 | return device; 380 | } 381 | 382 | -------------------------------------------------------------------------------- /gui/VMSettingsForm.h: -------------------------------------------------------------------------------- 1 | #ifndef VMSETTINGSFORM_H 2 | #define VMSETTINGSFORM_H 3 | 4 | #include 5 | #include "VMConfig.h" 6 | #include "AddDeviceForm.h" 7 | #include "DeviceStorage.h" 8 | #include "DeviceUsb.h" 9 | #include "VMPropertiesForm.h" 10 | 11 | class VMSettingsForm : public QWidget 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | VMSettingsForm(VMConfig *vmconf, 17 | const QString &qemuDir, QWidget *parent = 0); 18 | ~VMSettingsForm(); 19 | 20 | public slots: 21 | 22 | private: 23 | VMConfig *vm; 24 | AddDeviceForm *addDev; 25 | QList addedDevices; 26 | QString pathToPlatformInfo; 27 | 28 | QTreeWidget *deviceTree; 29 | QDialogButtonBox *savecancel_btn; 30 | 31 | VMPropertiesForm *kernelForm; 32 | QLineEdit *addCmdLineParamsEdit; 33 | QSplitter *splitter; 34 | QMenu menu; 35 | 36 | private: 37 | void connect_signals(); 38 | void widget_placement(); 39 | QWidget *emptyForm(); 40 | Device *isDevicesValid(Device *device); 41 | void closeEvent(QCloseEvent *event); 42 | void removingDevFromDevices(Device *dev); 43 | bool changesVerification(); 44 | 45 | private slots: 46 | bool applySettings(); 47 | void save_settings(); 48 | void deviceTreeItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); 49 | void showContextMenu(const QPoint &pos); 50 | void addNewDevice(Device *newDevice); 51 | void addNewSystemDevice(const QString &devName); 52 | void removeDevice(); 53 | void menuClose(); 54 | void closeForm(); 55 | 56 | signals: 57 | void settingsDeleteRecords(); 58 | void updateVMInfo(); 59 | bool isExecutionListNotEmpty(); 60 | 61 | }; 62 | 63 | class DeviceTreeItem : public QTreeWidgetItem 64 | { 65 | public: 66 | DeviceTreeItem(Device *dev); 67 | 68 | void initDevice(Device *dev); 69 | Device *getDevice(); 70 | 71 | private: 72 | Device *device; 73 | }; 74 | 75 | #endif // VMSETTINGSFORM_H 76 | -------------------------------------------------------------------------------- /gui/main.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuGUI.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QStringList paths = QCoreApplication::libraryPaths(); 7 | paths.append("."); 8 | paths.append("imageformats"); 9 | paths.append("platforms"); 10 | paths.append("sqldrivers"); 11 | QCoreApplication::setLibraryPaths(paths); 12 | 13 | QApplication a(argc, argv); 14 | QemuGUI w; 15 | w.setWindowIcon(QIcon(":Resources/qemu.png")); 16 | w.show(); 17 | return a.exec(); 18 | } 19 | -------------------------------------------------------------------------------- /platform files/arm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | virt 4 | none 5 | midway 6 | arm1026 7 | cortex-a15 8 | max 9 | 10 | -------------------------------------------------------------------------------- /platform files/i386.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | pc-i440fx-2.13 4 | pc-1.3 5 | pc-q35-2.9 6 | 486 7 | qemu32 8 | qemu64 9 | 10 | -------------------------------------------------------------------------------- /qemu/CommandLineParameters.cpp: -------------------------------------------------------------------------------- 1 | #include "CommandLineParameters.h" 2 | 3 | LaunchMode CommandLineParameters::getLaunchMode() 4 | { 5 | return mode; 6 | } 7 | 8 | QString CommandLineParameters::getNextOverlayName() 9 | { 10 | return overlayPath + "/overlay" + QString::number(diskID++) + ".ovl"; 11 | } 12 | 13 | QString CommandLineParameters::getOverlayForImage(const QString &image) 14 | { 15 | if (overlayEnabled) 16 | { 17 | images.append(image); 18 | overlays.append(getNextOverlayName()); 19 | return overlays.back(); 20 | } 21 | else 22 | { 23 | return image; 24 | } 25 | 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /qemu/CommandLineParameters.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMANDLINEPARAMETERS_H 2 | #define COMMANDLINEPARAMETERS_H 3 | 4 | #include 5 | 6 | enum class LaunchMode : int { NORMAL, RECORD, REPLAY }; 7 | 8 | class CommandLineParameters 9 | { 10 | public: 11 | CommandLineParameters(LaunchMode mode) : mode(mode), diskID(0), 12 | overlayEnabled(false) {} 13 | CommandLineParameters() : mode(LaunchMode::NORMAL), diskID(0), 14 | overlayEnabled(false) {} 15 | 16 | LaunchMode getLaunchMode(); 17 | 18 | /* record|replay */ 19 | const QStringList &getImages() { return images; } 20 | const QStringList &getOverlays() { return overlays; } 21 | void setOverlayDir(const QString &path) { overlayPath = path; } 22 | QString getOverlayForImage(const QString &image); 23 | void setOverlayEnabled(bool isEnabled) { overlayEnabled = isEnabled; } 24 | bool isOverlayEnabled() { return overlayEnabled; } 25 | 26 | private: 27 | QString getNextOverlayName(); 28 | 29 | private: 30 | LaunchMode mode; /* normal, record, replay */ 31 | QStringList images; 32 | QStringList overlays; 33 | int diskID; 34 | QString overlayPath; 35 | bool overlayEnabled; 36 | 37 | }; 38 | 39 | #endif 40 | 41 | 42 | -------------------------------------------------------------------------------- /qemu/PlatformInformationReader.cpp: -------------------------------------------------------------------------------- 1 | #include "PlatformInformationReader.h" 2 | #include "common/FileHelpers.h" 3 | #include "config/GlobalConfig.h" 4 | #include "config/QemuList.h" 5 | 6 | PlatformInformationReader::PlatformInformationReader(const QString &qemu, bool del) 7 | : qemuName(qemu), profilePath(QemuList::getQemuProfilePath(qemu)), deleteSelf(del), 8 | thread(NULL), platformInfo(nullptr) 9 | #ifdef GUI 10 | , timer(NULL) 11 | #endif 12 | { 13 | platforms = { QStringList({ "i386", "pc" }), 14 | QStringList({ "x86_64", "pc" }), 15 | QStringList({ "arm", "virt" }), 16 | QStringList({ "mips", "none" }), 17 | QStringList({ "mips64", "none" }), 18 | QStringList({ "ppc", "none" }), 19 | QStringList({ "riscv64", "none" }), 20 | }; 21 | 22 | qmp = NULL; 23 | launcher = NULL; 24 | allInfoReady = false; 25 | 26 | FileHelpers::deleteDirectory(profilePath); 27 | FileHelpers::createDirectory(profilePath); 28 | createProgressDialog(); 29 | launchQemu(); 30 | } 31 | 32 | void PlatformInformationReader::launchQemu() 33 | { 34 | allInfoReady = false; 35 | 36 | QemuRunOptions opt = QemuRunOptions::getGlobal(); 37 | opt.setQemuRunStopped(true); 38 | launcher = new QemuLauncher(qemuName, opt, 39 | platforms.first().at(0), platforms.first().at(1)); 40 | if (launcher->isQemuExist()) 41 | { 42 | platformInfo = new PlatformInfo(profilePath + "/" + platforms.first().first()); 43 | #ifdef GUI 44 | qmp = new QMPInteractionSettings(nullptr, 45 | GlobalConfig::get_port_qmp().toInt(), platformInfo); 46 | connect(qmp, SIGNAL(ready()), 47 | this, SLOT(nextRequest())); 48 | connect(this, SIGNAL(qmpShutdownQemu()), qmp, SLOT(commandShutdownQemu())); 49 | connect(this, SIGNAL(qemuMustDie()), launcher, SLOT(terminateQemu())); 50 | 51 | thread = new QThread(); 52 | launcher->moveToThread(thread); 53 | connect(thread, SIGNAL(started()), launcher, SLOT(start_qemu())); 54 | connect(launcher, SIGNAL(qemu_laucher_finished(int)), 55 | this, SLOT(finishQemu(int))); 56 | timer = new QTimer(); 57 | timer->start(10000); 58 | connect(timer, SIGNAL(timeout()), this, SLOT(timeIsOut())); 59 | platforms.removeFirst(); 60 | thread->start(); 61 | #else 62 | qDebug() << "Scanning " << platforms.first().first(); 63 | launcher->start_qemu(); 64 | qmp = new QMPInteractionSettings(nullptr, 65 | GlobalConfig::get_port_qmp().toInt(), platformInfo); 66 | qmp->connectedSocket(); 67 | qmp->commandShutdownQemu(); 68 | platformInfo->saveXml(); 69 | platforms.removeFirst(); 70 | /* Recursive */ 71 | finishQemu(0); 72 | #endif 73 | } 74 | else 75 | { 76 | qDebug() << "QEMU for platform " << platforms.first().first() << " doesn't exist"; 77 | platforms.removeFirst(); 78 | #ifdef GUI 79 | progress->setValue(progress->maximum() - platforms.count()); 80 | #endif 81 | finishQemu(QProcess::CrashExit); 82 | } 83 | } 84 | 85 | void PlatformInformationReader::createProgressDialog() 86 | { 87 | #ifdef GUI 88 | progress = new QProgressDialog("Please wait...", "", 0, platforms.count()); 89 | progress->setWindowTitle("Reading information"); 90 | progress->setWindowModality(Qt::ApplicationModal); 91 | progress->setWindowFlags(Qt::WindowCloseButtonHint); 92 | progress->setCancelButton(NULL); 93 | progress->setRange(0, platforms.count()); 94 | progress->show(); 95 | #endif 96 | } 97 | 98 | void PlatformInformationReader::timeIsOut() 99 | { 100 | emit qemuMustDie(); 101 | } 102 | 103 | void PlatformInformationReader::nextRequest() 104 | { 105 | #ifdef GUI 106 | progress->setValue(progress->maximum() - platforms.count()); 107 | #endif 108 | platformInfo->saveXml(); 109 | /* To avoid nextRequest invocation on quit */ 110 | disconnect(this, SLOT(nextRequest())); 111 | emit qmpShutdownQemu(); 112 | } 113 | 114 | void PlatformInformationReader::finishQemu(int exitCode) 115 | { 116 | #ifdef GUI 117 | delete timer; 118 | timer = NULL; 119 | #endif 120 | delete launcher; 121 | launcher = NULL; 122 | delete qmp; 123 | qmp = NULL; 124 | delete platformInfo; 125 | platformInfo = nullptr; 126 | if (!platforms.isEmpty()) 127 | { 128 | launchQemu(); 129 | } 130 | else 131 | { 132 | #ifdef GUI 133 | delete progress; 134 | #endif 135 | emit workFinish(); 136 | if (deleteSelf) 137 | delete this; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /qemu/PlatformInformationReader.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORMINFORMATIONREADER_H 2 | #define PLATFORMINFORMATIONREADER_H 3 | 4 | #include 5 | #ifdef GUI 6 | #include 7 | #endif 8 | #include "QMPInteraction.h" 9 | #include "QemuLauncher.h" 10 | #include "config/PlatformInfo.h" 11 | 12 | class PlatformInformationReader : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | PlatformInformationReader(const QString &qemu, bool del = true); 18 | 19 | private: 20 | QThread *thread; 21 | #ifdef GUI 22 | QTimer *timer; 23 | #endif 24 | QString qemuName; 25 | QString profilePath; 26 | QList platforms; 27 | QMPInteractionSettings *qmp; 28 | QemuLauncher *launcher; 29 | bool allInfoReady; 30 | bool deleteSelf; 31 | 32 | PlatformInfo *platformInfo; 33 | 34 | private: 35 | void launchQemu(); 36 | void createXml(); 37 | void createProgressDialog(); 38 | 39 | #ifdef GUI 40 | QProgressDialog *progress; 41 | #endif 42 | 43 | private slots: 44 | void nextRequest(); 45 | 46 | public slots: 47 | void timeIsOut(); 48 | void finishQemu(int exitCode); 49 | 50 | signals: 51 | void qmpShutdownQemu(); 52 | 53 | void qmpSendCommand(); 54 | 55 | void workFinish(); 56 | void qemuMustDie(); 57 | }; 58 | 59 | #endif // PLATFORM_INFORMATIONREADER_H 60 | -------------------------------------------------------------------------------- /qemu/QMPInteraction.cpp: -------------------------------------------------------------------------------- 1 | #include "QMPInteraction.h" 2 | 3 | QMPInteraction::QMPInteraction(QObject *parent) 4 | : QObject(parent) 5 | { 6 | connect(&socket, SIGNAL(readyRead()), this, SLOT(readTerminal())); 7 | prepareCommands(); 8 | } 9 | 10 | QMPInteraction::QMPInteraction(QObject *parent, int port) 11 | : QMPInteraction(parent) 12 | { 13 | connect(&socket, SIGNAL(connected()), this, SLOT(connectedSocket())); 14 | 15 | socket.connectPort(port); 16 | } 17 | 18 | QMPInteraction::~QMPInteraction() 19 | { 20 | } 21 | 22 | 23 | void QMPInteraction::prepareCommands() 24 | { 25 | cmdMap.insert(QMPCommands::Continue, { "cont", "", &QMPInteraction::continue_cb }); 26 | cmdMap.insert(QMPCommands::Stop, { "stop", "", &QMPInteraction::stop_cb }); 27 | cmdMap.insert(QMPCommands::Quit, { "quit", "", NULL }); 28 | cmdMap.insert(QMPCommands::QmpCapabilities, { "qmp_capabilities", "", &QMPInteraction::dummy_cb }); 29 | cmdMap.insert(QMPCommands::QueryStatus,{ "query-status", "", &QMPInteraction::queryStatus_cb }); 30 | cmdMap.insert(QMPCommands::QueryMachines, { "query-machines", "", 31 | &QMPInteraction::machine_cb }); 32 | cmdMap.insert(QMPCommands::QueryCpuDefinitions, { "query-cpu-definitions", "", 33 | &QMPInteraction::cpu_cb }); 34 | cmdMap.insert(QMPCommands::QomListTypes, { "qom-list-types", 35 | ",\"arguments\":{\"abstract\":true, \"implements\":\"device\"}", 36 | &QMPInteraction::listDevices_cb }); 37 | cmdMap.insert(QMPCommands::DeviceListProperties, { "device-list-properties", "?", 38 | &QMPInteraction::listProperties_cb }); 39 | } 40 | 41 | void QMPInteraction::dummy_cb(QJsonObject object) 42 | { 43 | if (!isEvent(object)) 44 | { 45 | cbQueue.pop_front(); 46 | } 47 | } 48 | 49 | bool QMPInteraction::isEvent(QJsonObject object) 50 | { 51 | QJsonValue json_command = object["event"]; 52 | if (!json_command.isNull()) 53 | { 54 | cbQueue.pop_front(); 55 | return true; 56 | } 57 | return false; 58 | } 59 | 60 | void QMPInteraction::queryStatus_cb(QJsonObject object) 61 | { 62 | QJsonValue json_command = object["return"]; 63 | if (!json_command.toObject()["running"].isNull()) 64 | { 65 | bool runStatus = json_command.toObject()["running"].toBool(); 66 | emit qemuRunningStatus(runStatus); 67 | cbQueue.pop_front(); 68 | } 69 | } 70 | 71 | void QMPInteraction::stop_cb(QJsonObject object) 72 | { 73 | if (isEvent(object)) 74 | { 75 | emit qemuStopped(); 76 | } 77 | } 78 | 79 | void QMPInteraction::continue_cb(QJsonObject object) 80 | { 81 | if (isEvent(object)) 82 | { 83 | emit qemuResumed(); 84 | } 85 | } 86 | 87 | bool QMPInteraction::whatSaidQmp(QByteArray message) 88 | { 89 | QJsonParseError err; 90 | QJsonDocument qmp_message = QJsonDocument::fromJson(message, &err); 91 | //qDebug() << qmp_message; 92 | if (qmp_message.isNull()) 93 | { 94 | return false; 95 | } 96 | QJsonObject obj = qmp_message.object(); 97 | 98 | if (!cbQueue.isEmpty()) 99 | { 100 | (this->*(cbQueue.first()))(obj); 101 | if (cbQueue.empty()) 102 | { 103 | emit ready(); 104 | } 105 | } 106 | return true; 107 | } 108 | 109 | void QMPInteraction::readTerminal() 110 | { 111 | QByteArray message = messageBegin + socket.readAll(); 112 | messageBegin.clear(); 113 | // if (!message.isEmpty()) 114 | // { 115 | // QByteArray tmp = message; 116 | // tmp.truncate(80); 117 | // qDebug() << "\n\nSocket data:\n\n" << tmp; 118 | // } 119 | QList messageBuffer = message.split('\n'); 120 | bool last = false; 121 | foreach(QByteArray message, messageBuffer) 122 | { 123 | Q_ASSERT(!last); 124 | if (!whatSaidQmp(message)) 125 | { 126 | messageBegin = message; 127 | /* is this the last one? */ 128 | last = true; 129 | } 130 | } 131 | } 132 | 133 | void QMPInteraction::connectedSocket() 134 | { 135 | commandQmp(QMPCommands::QmpCapabilities); 136 | commandQmp(QMPCommands::QueryStatus); 137 | // Send everything 138 | while (!commandsQueue.isEmpty()) 139 | { 140 | commandQmp(commandsQueue.first()); 141 | commandsQueue.removeFirst(); 142 | } 143 | } 144 | 145 | void QMPInteraction::commandQmp(QMPCommands cmd, const QString &specParams) 146 | { 147 | QmpCommand command = cmdMap.value(cmd); 148 | if (command.callback) 149 | { 150 | cbQueue.append(command.callback); 151 | } 152 | QString params = specParams.isEmpty() ? command.params : specParams; 153 | QByteArray commandAll = "{ \"execute\":\"" + command.command.toLocal8Bit() + "\"" 154 | + params.toLocal8Bit() + "}"; 155 | qDebug() << "QMP send " << commandAll; 156 | socket.write(commandAll); 157 | #ifndef GUI 158 | socket.flush(); 159 | while (!cbQueue.empty()) 160 | { 161 | socket.waitForReadyRead(-1); 162 | readTerminal(); 163 | } 164 | #endif 165 | } 166 | 167 | 168 | /****************************************************************************** 169 | * QMP Interaction Settings * 170 | ******************************************************************************/ 171 | 172 | 173 | QMPInteractionSettings::QMPInteractionSettings(QObject *parent, int port, 174 | PlatformInfo *pi) 175 | : QMPInteraction(parent), platformInfo(pi) 176 | { 177 | commandsQueue.append({ QMPCommands::QueryMachines, 178 | QMPCommands::QueryCpuDefinitions, 179 | QMPCommands::QomListTypes, 180 | }); 181 | 182 | connect(&socket, SIGNAL(connected()), this, SLOT(connectedSocket())); 183 | socket.connectPort(port); 184 | } 185 | 186 | void QMPInteractionSettings::machine_cb(QJsonObject object) 187 | { 188 | QJsonValue jv = object.value("return"); 189 | if (jv.isArray()) 190 | { 191 | QJsonArray arrMessage = jv.toArray(); 192 | for (const QJsonValue &v : arrMessage) 193 | { 194 | QString name = v.toObject()["name"].toString(); 195 | bool isDefault = v.toObject()["is-default"].toBool(); 196 | platformInfo->addMachine(name, isDefault); 197 | } 198 | cbQueue.pop_front(); 199 | } 200 | } 201 | 202 | void QMPInteractionSettings::cpu_cb(QJsonObject object) 203 | { 204 | QJsonValue jv = object.value("return"); 205 | if (jv.isArray()) 206 | { 207 | QJsonArray arrMessage = jv.toArray(); 208 | for (const QJsonValue &v : arrMessage) 209 | { 210 | QString name = v.toObject()["name"].toString(); 211 | platformInfo->addCpu(name); 212 | } 213 | cbQueue.pop_front(); 214 | } 215 | else 216 | { 217 | /* Some platforms do not provide CPU definitions */ 218 | if (object.value("error").isObject()) 219 | { 220 | cbQueue.pop_front(); 221 | } 222 | } 223 | } 224 | 225 | void QMPInteractionSettings::listDevices_cb(QJsonObject object) 226 | { 227 | QJsonValue jv = object.value("return"); 228 | if (jv.isArray()) 229 | { 230 | // Remove it, because we continue sending commands 231 | cbQueue.pop_front(); 232 | QJsonArray arrMessage = jv.toArray(); 233 | for (const QJsonValue &v : arrMessage) 234 | { 235 | bool isAbstract = v.toObject()["abstract"].toBool(); 236 | QString deviceName = v.toObject()["name"].toString(); 237 | if (!isAbstract) 238 | { 239 | devices.append(deviceName); 240 | QMPInteraction::commandQmp(QMPCommands::DeviceListProperties, 241 | getParamDevListProperties(deviceName)); 242 | } 243 | } 244 | } 245 | } 246 | 247 | void QMPInteractionSettings::listProperties_cb(QJsonObject object) 248 | { 249 | QJsonValue jv = object.value("return"); 250 | if (jv.isArray()) 251 | { 252 | QJsonArray arrMessage = jv.toArray(); 253 | for (const QJsonValue &v : arrMessage) 254 | { 255 | QString name = v.toObject()["name"].toString(); 256 | if (name == "netdev") 257 | { 258 | platformInfo->addNetdev(devices.first()); 259 | } 260 | } 261 | devices.pop_front(); 262 | cbQueue.pop_front(); 263 | } 264 | } 265 | 266 | QString QMPInteractionSettings::getParamDevListProperties(const QString &name) const 267 | { 268 | return ",\"arguments\":{\"typename\":\"" + name + "\"}"; 269 | } 270 | 271 | void QMPInteractionSettings::commandShutdownQemu() 272 | { 273 | QMPInteraction::commandQmp(QMPCommands::Quit); 274 | } 275 | -------------------------------------------------------------------------------- /qemu/QMPInteraction.h: -------------------------------------------------------------------------------- 1 | #ifndef QMPINTERACTION_H 2 | #define QMPINTERACTION_H 3 | 4 | #include 5 | #include "QemuSocket.h" 6 | #include "config/PlatformInfo.h" 7 | 8 | enum class QMPCommands : int 9 | { 10 | Continue, 11 | Stop, 12 | Quit, 13 | QmpCapabilities, 14 | QueryStatus, 15 | QueryMachines, 16 | QueryCpuDefinitions, 17 | QomListTypes, 18 | DeviceListProperties 19 | }; 20 | 21 | class QMPInteraction : public QObject 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | QMPInteraction(QObject *parent); 27 | QMPInteraction(QObject *parent, int port); 28 | ~QMPInteraction(); 29 | 30 | struct QmpCommand 31 | { 32 | QString command; 33 | QString params; 34 | void (QMPInteraction::*callback)(QJsonObject); 35 | }; 36 | 37 | void commandQmp(QMPCommands cmd, const QString &specParams = ""); 38 | 39 | protected: 40 | QemuSocket socket; 41 | QByteArray messageBegin; 42 | QList cbQueue; 43 | QMap cmdMap; 44 | QList commandsQueue; 45 | 46 | private: 47 | void dummy_cb(QJsonObject object); 48 | bool isEvent(QJsonObject object); 49 | void queryStatus_cb(QJsonObject object); 50 | void stop_cb(QJsonObject object); 51 | void continue_cb(QJsonObject object); 52 | 53 | protected: 54 | void prepareCommands(); 55 | bool whatSaidQmp(QByteArray message); 56 | virtual void machine_cb(QJsonObject object) {} 57 | virtual void cpu_cb(QJsonObject object) {} 58 | virtual void listDevices_cb(QJsonObject object) {} 59 | virtual void listProperties_cb(QJsonObject object) {} 60 | 61 | public slots: 62 | void readTerminal(); 63 | void connectedSocket(); 64 | 65 | signals : 66 | void qemuResumed(); 67 | void qemuStopped(); 68 | void qemuRunningStatus(bool runStatus); 69 | void ready(); 70 | }; 71 | 72 | 73 | class QMPInteractionSettings : public QMPInteraction 74 | { 75 | Q_OBJECT 76 | 77 | public: 78 | QMPInteractionSettings(QObject *parent, int port, PlatformInfo *pi); 79 | 80 | private: 81 | PlatformInfo *platformInfo; 82 | QStringList devices; 83 | 84 | private: 85 | virtual void machine_cb(QJsonObject object); 86 | virtual void cpu_cb(QJsonObject object); 87 | virtual void listDevices_cb(QJsonObject object); 88 | virtual void listProperties_cb(QJsonObject object); 89 | 90 | QString getParamDevListProperties(const QString &name) const; 91 | 92 | public slots: 93 | void commandShutdownQemu(); 94 | }; 95 | 96 | 97 | #endif // QMPINTERACTION_H 98 | 99 | -------------------------------------------------------------------------------- /qemu/QemuImgLauncher.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuImgLauncher.h" 2 | 3 | QemuImgLauncher::QemuImgLauncher(const QString &dir, const QString &imageFormat, 4 | const QString &imageName, QObject *parent) : 5 | QObject(parent), imageFormat(imageFormat), imageName(imageName), 6 | imageSize(0) 7 | { 8 | this->qemuImg = dir 9 | #ifdef Q_OS_WIN 10 | + "/qemu-img.exe"; 11 | #else 12 | + "/qemu-img"; 13 | #endif 14 | } 15 | 16 | QemuImgLauncher::QemuImgLauncher(const QString &qemuImg, const QString &imageFormat, 17 | const QString &imageName, int imageSize, QObject *parent) : 18 | QemuImgLauncher(qemuImg, imageFormat, imageName, parent) 19 | { 20 | this->imageSize = imageSize; 21 | } 22 | 23 | QemuImgLauncher::QemuImgLauncher(const QString &qemuImg, const QString &imageFormat, 24 | const QString &imageName, const QString &path, QObject *parent) : 25 | QemuImgLauncher(qemuImg, imageFormat, imageName, parent) 26 | { 27 | imageSize = 0; 28 | overlayName = path; 29 | } 30 | 31 | QemuImgLauncher::~QemuImgLauncher() 32 | { 33 | 34 | } 35 | 36 | void QemuImgLauncher::startQemuImg(QProcess &qemuImgProc, const QString &cmd) 37 | { 38 | qRegisterMetaType("QProcess::ExitStatus"); 39 | connect(&qemuImgProc, SIGNAL(finished(int, QProcess::ExitStatus)), 40 | this, SLOT(finish_qemu_img(int, QProcess::ExitStatus))); 41 | qemuImgProc.start(cmd); 42 | qemuImgProc.waitForFinished(-1); 43 | } 44 | 45 | void QemuImgLauncher::startQemuImgCreateOverlay() 46 | { 47 | QString cmd = "\"" + qemuImg + "\"" + " create -f qcow2 -b " + 48 | "\"" + imageName + "\" " + "\"" + overlayName + "\""; 49 | qDebug() << "create overlay: " << cmd << "----"; 50 | QProcess qemuImgProc; 51 | startQemuImg(qemuImgProc, cmd); 52 | } 53 | 54 | QStringList QemuImgLauncher::getSnapshotInformation() 55 | { 56 | QStringList info; 57 | QString cmd = "\"" + qemuImg + "\"" + " info " + "\"" + imageName + "\""; 58 | QProcess qemuImgProc; 59 | startQemuImg(qemuImgProc, cmd); 60 | while (!qemuImgProc.atEnd()) 61 | { 62 | info.append(qemuImgProc.readLine()); 63 | } 64 | if (qemuImgProc.exitCode() != 0) 65 | { 66 | qDebug() << "Cannot get information" << qemuImgProc.exitCode(); 67 | } 68 | return info; 69 | } 70 | 71 | void QemuImgLauncher::finish_qemu_img(int exitCode, QProcess::ExitStatus ExitStatus) 72 | { 73 | qDebug() << "Process is finished" << exitCode << ExitStatus; 74 | emit qemu_img_finished(exitCode); 75 | } 76 | 77 | void QemuImgLauncher::startQemuImgCreateDisk() 78 | { 79 | QString cmd = "\"" + qemuImg + "\"" + " create -f " + imageFormat + " " + 80 | imageName + " " + QString().number(imageSize) + "M"; 81 | QProcess qemuImgProc; 82 | startQemuImg(qemuImgProc, cmd); 83 | } 84 | 85 | 86 | -------------------------------------------------------------------------------- /qemu/QemuImgLauncher.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMUIMGLAUNCHER_H 2 | #define QEMUIMGLAUNCHER_H 3 | 4 | #include 5 | 6 | class QemuImgLauncher : public QObject 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | QemuImgLauncher(const QString &dir, const QString &imageFormat, 12 | const QString &imageName, QObject *parent = 0); 13 | QemuImgLauncher(const QString &dir, const QString &imageFormat, 14 | const QString &imageName, int imageSize, QObject *parent = 0); 15 | QemuImgLauncher(const QString &dir, const QString &imageFormat, 16 | const QString &imageName, const QString &path, QObject *parent = 0); 17 | ~QemuImgLauncher(); 18 | 19 | QStringList getSnapshotInformation(); 20 | 21 | private: 22 | QString qemuImg; 23 | QString imageFormat; 24 | QString imageName; 25 | int imageSize; /* in megabytes */ 26 | QString overlayName; 27 | 28 | private: 29 | void startQemuImg(QProcess &qemuImgProc, const QString &cmd); 30 | 31 | public slots: 32 | void startQemuImgCreateDisk(); 33 | void startQemuImgCreateOverlay(); 34 | void finish_qemu_img(int exitCode, QProcess::ExitStatus ExitStatus); 35 | 36 | signals: 37 | void qemu_img_finished(int); 38 | 39 | }; 40 | #endif // QEMUIMGLAUNCHER_H 41 | 42 | -------------------------------------------------------------------------------- /qemu/QemuLauncher.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuLauncher.h" 2 | #include "QemuImgLauncher.h" 3 | #include "CommandLineParameters.h" 4 | #include "config/QemuList.h" 5 | 6 | QemuLauncher::QemuLauncher(const QString &qemu, VMConfig *vm, 7 | const QemuRunOptions &runOpt, LaunchMode mode, 8 | const RecordReplayParams &rr, QObject *parent) 9 | : QObject(parent), virtual_machine(vm), mode(mode), 10 | qemuName(qemu), runOptions(runOpt), rrParams(rr) 11 | { 12 | createQemuPath(virtual_machine->getPlatform()); 13 | process = NULL; 14 | mon = runOptions.getMonitorCmd(); 15 | qmp = runOptions.getQmpCmd(); 16 | additionalOptionsCmd = runOptions.getAllAdditionalOptionsCmd(mode); 17 | } 18 | 19 | QemuLauncher::QemuLauncher(const QString &qemu, const QemuRunOptions &runOpt, 20 | const QString &platform, const QString &machine) 21 | : qemuName(qemu), mode(LaunchMode::NORMAL), runOptions(runOpt) 22 | { 23 | createQemuPath(platform); 24 | cmd = "-machine " + machine + " "; 25 | process = NULL; 26 | virtual_machine = NULL; 27 | mon = ""; 28 | qmp = runOptions.getQmpCmd(); 29 | additionalOptionsCmd = runOptions.getAllAdditionalOptionsCmd(mode); 30 | } 31 | 32 | QemuLauncher::~QemuLauncher() 33 | { 34 | } 35 | 36 | bool QemuLauncher::isQemuExist() 37 | { 38 | QFile qemuFile(qemuExePath); 39 | return qemuFile.exists(); 40 | } 41 | 42 | void QemuLauncher::createQemuPath(const QString &platform) 43 | { 44 | qemuExePath = QemuList::getQemuExecutablePath(qemuName, platform); 45 | } 46 | 47 | void QemuLauncher::start_qemu() 48 | { 49 | CommandLineParameters cmdParams(mode); 50 | process = new QProcess(); 51 | qRegisterMetaType("QProcess::ExitStatus"); 52 | connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), 53 | this, SLOT(finish_qemu(int, QProcess::ExitStatus))); 54 | recordReplay = ""; 55 | if (mode != LaunchMode::NORMAL) 56 | { 57 | cmdParams.setOverlayDir(rrParams.getCurrentDir()); 58 | cmdParams.setOverlayEnabled(rrParams.isOverlayEnabled()); 59 | QString rr = rrParams.getCommandLine(mode); 60 | recordReplay += rr; 61 | if (mode == LaunchMode::RECORD) 62 | { 63 | cmd = virtual_machine->getCommandLine(cmdParams); 64 | images = cmdParams.getImages(); 65 | overlays = cmdParams.getOverlays(); 66 | createDummyImage(); 67 | } 68 | } 69 | if (mode != LaunchMode::RECORD) 70 | { 71 | if (virtual_machine) 72 | cmd = virtual_machine->getCommandLine(cmdParams); 73 | launchQemu(); 74 | } 75 | } 76 | 77 | void QemuLauncher::createDummyImage() 78 | { 79 | QThread *thread = new QThread(); 80 | QemuImgLauncher *imgLauncher = new QemuImgLauncher(QemuList::getQemuDir(qemuName), "qcow2", 81 | rrParams.getDummyImage(), 20); 82 | 83 | imgLauncher->moveToThread(thread); 84 | connect(thread, SIGNAL(started()), imgLauncher, SLOT(startQemuImgCreateDisk())); 85 | connect(imgLauncher, SIGNAL(qemu_img_finished(int)), 86 | this, SLOT(finishCreatingDummy(int))); 87 | thread->start(); 88 | } 89 | 90 | void QemuLauncher::createOverlays() 91 | { 92 | if (images.isEmpty()) 93 | { 94 | launchQemu(); 95 | } 96 | else 97 | { 98 | QThread *thread = new QThread(); 99 | QemuImgLauncher *imgLauncher = new QemuImgLauncher(QemuList::getQemuDir(qemuName), "qcow2", 100 | images.first(), overlays.first()); 101 | images.removeFirst(); 102 | overlays.removeFirst(); 103 | 104 | imgLauncher->moveToThread(thread); 105 | connect(thread, SIGNAL(started()), imgLauncher, SLOT(startQemuImgCreateOverlay())); 106 | connect(imgLauncher, SIGNAL(qemu_img_finished(int)), 107 | this, SLOT(finishCreatingOverlay(int))); 108 | thread->start(); 109 | } 110 | } 111 | 112 | void QemuLauncher::launchQemu() 113 | { 114 | QString cmdLine = "\"" + qemuExePath + "\" " + recordReplay 115 | + cmd + mon + runOptions.getQmpCmd() + additionalOptionsCmd; 116 | qDebug() << cmdLine; 117 | emit qemuStarted(cmdLine); 118 | process->start(cmdLine); 119 | #ifdef GUI 120 | if (virtual_machine) 121 | { 122 | process->waitForFinished(-1); 123 | } 124 | else 125 | { 126 | process->waitForFinished(10000); 127 | } 128 | #endif 129 | } 130 | 131 | void QemuLauncher::finish_qemu(int exitCode, QProcess::ExitStatus ExitStatus) 132 | { 133 | qDebug() << "exit code" << exitCode << "exit status" << ExitStatus; 134 | emit qemu_laucher_finished(exitCode); 135 | } 136 | 137 | void QemuLauncher::terminateQemu() 138 | { 139 | if (process->state() == QProcess::Running) 140 | { 141 | qDebug() << "Qemu work too long. Terminated. Receiving information is not guaranteed"; 142 | process->terminate(); 143 | } 144 | } 145 | 146 | void QemuLauncher::finishCreatingDummy(int exitCode) 147 | { 148 | if (exitCode == 0) 149 | { 150 | createOverlays(); 151 | } 152 | else 153 | { 154 | emit creatingOverlayFailed(); 155 | qDebug() << "Error with dummy disk image, sorry"; 156 | } 157 | } 158 | 159 | void QemuLauncher::finishCreatingOverlay(int exitCode) 160 | { 161 | if (exitCode == 0) 162 | { 163 | createOverlays(); 164 | } 165 | else 166 | { 167 | emit creatingOverlayFailed(); 168 | qDebug() << "Error with creation overlay, sorry"; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /qemu/QemuLauncher.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMULAUNCHER_H 2 | #define QEMULAUNCHER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "VMConfig.h" 8 | #include "QemuRunOptions.h" 9 | #include "CommandLineParameters.h" 10 | #include "RecordReplayParams.h" 11 | 12 | class RecordReplayTab; 13 | 14 | class QemuLauncher : public QObject 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | QemuLauncher(const QString &qemu, VMConfig *vm, 20 | const QemuRunOptions &runOpt, LaunchMode mode, 21 | const RecordReplayParams &rr, QObject *parent = 0); 22 | QemuLauncher(const QString &qemu, const QemuRunOptions &runOpt, 23 | const QString &platform, const QString &machine); 24 | ~QemuLauncher(); 25 | bool isQemuExist(); 26 | 27 | private: 28 | QemuRunOptions runOptions; 29 | QString qemuName; 30 | QString qemuExePath; 31 | VMConfig *virtual_machine; 32 | QProcess *process; 33 | 34 | QTcpSocket monitor; 35 | QString port_qmp; 36 | QString port_monitor; 37 | LaunchMode mode; 38 | 39 | QString mon; 40 | QString qmp; 41 | QString recordReplay; 42 | QString cmd; 43 | QString additionalOptionsCmd; 44 | 45 | QStringList images; 46 | QStringList overlays; 47 | 48 | RecordReplayParams rrParams; 49 | 50 | private: 51 | void createQemuPath(const QString &platform); 52 | void createDummyImage(); 53 | void createOverlays(); 54 | void launchQemu(); 55 | 56 | private slots: 57 | void finishCreatingOverlay(int exitCode); 58 | void finishCreatingDummy(int exitCode); 59 | 60 | public slots: 61 | void start_qemu(); 62 | void finish_qemu(int exitCode, QProcess::ExitStatus ExitStatus); 63 | void terminateQemu(); 64 | 65 | signals: 66 | void qemu_laucher_finished(int exitCode); 67 | void creatingOverlayFailed(); 68 | void qemuStarted(const QString &cmdline); 69 | }; 70 | 71 | 72 | #endif // QEMULAUNCHER_H 73 | -------------------------------------------------------------------------------- /qemu/QemuRunOptions.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuRunOptions.h" 2 | #include "CommandLineParameters.h" 3 | #include "config/GlobalConfig.h" 4 | 5 | QemuRunOptions::QemuRunOptions() : 6 | logfileName(""), logOptionList({}), additionalCmdLine(""), 7 | isDebugEnable(false), isSnapshotEnable(false), isQemuRunStopped(false) 8 | { 9 | } 10 | 11 | QemuRunOptions QemuRunOptions::getGlobal() 12 | { 13 | QemuRunOptions opt; 14 | opt.qmpPort = GlobalConfig::get_port_qmp(); 15 | opt.monitorPort = GlobalConfig::get_port_monitor(); 16 | return opt; 17 | } 18 | 19 | QString QemuRunOptions::getMonitorCmd() 20 | { 21 | if (getMonitorPort().isEmpty()) 22 | { 23 | return ""; 24 | } 25 | 26 | return " -monitor \"tcp:127.0.0.1:" + getMonitorPort() + ",server,nowait\""; 27 | } 28 | 29 | QString QemuRunOptions::getQmpCmd() 30 | { 31 | if (getQmpPort().isEmpty()) 32 | { 33 | return ""; 34 | } 35 | 36 | return " -qmp \"tcp:127.0.0.1:" + getQmpPort() + ",server,nowait\""; 37 | } 38 | 39 | QString QemuRunOptions::getAllAdditionalOptionsCmd(LaunchMode mode) 40 | { 41 | QString debugCmd = (getDebugEnable() && mode != LaunchMode::RECORD) ? " -s -S" : ""; 42 | QString snapshotCmd = (getSnapshotEnable() && mode == LaunchMode::NORMAL) ? 43 | " -snapshot" : ""; 44 | QString stoppedCmd = (debugCmd.isEmpty() && getQemuRunStopped()) ? " -S" : ""; 45 | 46 | QString logOp = ""; 47 | if (!getLogfileName().isEmpty()) 48 | { 49 | logOp = " -D " + getLogfileName(); 50 | } 51 | QStringList logOptions = getOptionList(); 52 | if (logOptions.count()) 53 | { 54 | logOp += " -d "; 55 | foreach(QString op, logOptions) 56 | { 57 | logOp += (op + ","); 58 | } 59 | logOp.chop(1); 60 | } 61 | 62 | return debugCmd + snapshotCmd + stoppedCmd + " " + getAdditionalCmdLine() + logOp; 63 | } 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /qemu/QemuRunOptions.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMURUNOPTIONS_H 2 | #define QEMURUNOPTIONS_H 3 | 4 | #include 5 | 6 | enum class LaunchMode; 7 | 8 | class QemuRunOptions 9 | { 10 | public: 11 | QemuRunOptions(); 12 | 13 | static QemuRunOptions getGlobal(); 14 | 15 | void setQmpPort(const QString &port) { qmpPort = port; } 16 | QString getQmpPort() const { return qmpPort; } 17 | 18 | void setMonitorPort(const QString &port) { monitorPort = port; } 19 | QString getMonitorPort() const { return monitorPort; } 20 | 21 | void setLogfileName(const QString &name) { logfileName = name; } 22 | QString getLogfileName() const { return logfileName; } 23 | 24 | void setLogOptionList(const QStringList &options) { logOptionList = options; } 25 | QStringList getOptionList() const { return logOptionList; } 26 | 27 | void setAdditionalCmdLine(const QString &cmd) { additionalCmdLine = cmd; } 28 | QString getAdditionalCmdLine() const { return additionalCmdLine; } 29 | 30 | void setDebugEnable(bool value) { isDebugEnable = value; } 31 | bool getDebugEnable() { return isDebugEnable; } 32 | 33 | void setSnapshotEnable(bool value) { isSnapshotEnable = value; } 34 | bool getSnapshotEnable() { return isSnapshotEnable; } 35 | 36 | void setQemuRunStopped(bool value) { isQemuRunStopped = value; } 37 | bool getQemuRunStopped() { return isQemuRunStopped; } 38 | 39 | QString getMonitorCmd(); 40 | QString getQmpCmd(); 41 | QString getAllAdditionalOptionsCmd(LaunchMode mode); 42 | 43 | private: 44 | QString qmpPort; 45 | QString monitorPort; 46 | QString logfileName; 47 | QStringList logOptionList; 48 | QString additionalCmdLine; 49 | QString kernel; 50 | QString initrd; 51 | bool isDebugEnable; 52 | bool isSnapshotEnable; 53 | bool isQemuRunStopped; 54 | }; 55 | 56 | #endif // QEMURUNOPTIONS_H 57 | -------------------------------------------------------------------------------- /qemu/QemuSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "QemuSocket.h" 2 | 3 | QemuSocket::QemuSocket(QObject *parent) 4 | : QTcpSocket(parent) 5 | { 6 | connect(this, QOverload::of(&QAbstractSocket::error), 7 | this, &QemuSocket::processError); 8 | connect(this, &QAbstractSocket::disconnected, 9 | this, &QemuSocket::disconnectedPort); 10 | } 11 | 12 | void QemuSocket::tryConnect() 13 | { 14 | #ifndef GUI 15 | while (state() != QAbstractSocket::ConnectedState) 16 | { 17 | connecting = true; 18 | #endif 19 | connectToHost("127.0.0.1", port); 20 | #ifndef GUI 21 | waitForConnected(-1); 22 | connecting = false; 23 | } 24 | #endif 25 | } 26 | 27 | void QemuSocket::connectPort(int port) 28 | { 29 | if (connecting) 30 | { 31 | disconnect(); 32 | } 33 | this->port = port; 34 | connecting = true; 35 | tryConnect(); 36 | } 37 | 38 | void QemuSocket::disconnect() 39 | { 40 | connecting = false; 41 | disconnectFromHost(); 42 | } 43 | 44 | void QemuSocket::disconnectedPort() 45 | { 46 | connecting = false; 47 | } 48 | 49 | void QemuSocket::processError(QAbstractSocket::SocketError socketError) 50 | { 51 | if (socketError == QAbstractSocket::RemoteHostClosedError) 52 | { 53 | disconnect(); 54 | } 55 | #ifdef GUI 56 | if (connecting) 57 | { 58 | tryConnect(); 59 | } 60 | #endif 61 | } 62 | -------------------------------------------------------------------------------- /qemu/QemuSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMU_SOCKET_H 2 | #define QEMU_SOCKET_H 3 | 4 | #include 5 | 6 | class QemuSocket : public QTcpSocket 7 | { 8 | public: 9 | QemuSocket(QObject *parent = NULL); 10 | 11 | void connectPort(int port); 12 | void disconnect(); 13 | private: 14 | void tryConnect(); 15 | void processError(QAbstractSocket::SocketError socketError); 16 | void disconnectedPort(); 17 | 18 | private: 19 | int port; 20 | bool connecting; 21 | }; 22 | 23 | #endif 24 | --------------------------------------------------------------------------------