├── docs
├── imgs
│ ├── create_vm.png
│ ├── recordreplay.png
│ └── vm_settings.png
└── Using qemu-gui.md
├── gui
├── Resources
│ ├── pause.png
│ ├── play.png
│ ├── qemu.png
│ ├── stop.png
│ ├── create.png
│ ├── import.png
│ ├── replay.png
│ ├── settings.png
│ ├── pause_disable.png
│ ├── play_disable.png
│ ├── run_options.png
│ ├── stop_disable.png
│ ├── create_disable.png
│ ├── import_disable.png
│ ├── run_options_mini.png
│ └── settings_disable.png
├── ConsoleTab.h
├── QemuGUICommon.h
├── main.cpp
├── ConnectionSettingsForm.h
├── VMPropertiesForm.h
├── QemuInstallationsForm.h
├── AddDeviceForm.h
├── TerminalSettingsForm.h
├── QemuGUI.qrc
├── ConsoleTab.cpp
├── TerminalTab.h
├── VMSettingsForm.h
├── VMPropertiesForm.cpp
├── AddDeviceForm.cpp
├── CreateVMForm.h
├── ConnectionSettingsForm.cpp
├── DeviceForm.h
├── RecordReplayTab.h
├── QemuGUI.h
├── TerminalSettingsForm.cpp
├── QemuInstallationsForm.cpp
├── TerminalTab.cpp
├── DeviceForm.cpp
└── VMSettingsForm.cpp
├── .whitesource
├── platform files
├── arm.xml
└── i386.xml
├── common
├── FileHelpers.h
└── FileHelpers.cpp
├── README.md
├── .travis.yml
├── qemu
├── QemuSocket.h
├── CommandLineParameters.cpp
├── CommandLineParameters.h
├── QemuImgLauncher.h
├── PlatformInformationReader.h
├── QemuSocket.cpp
├── QemuRunOptions.h
├── QemuRunOptions.cpp
├── QemuLauncher.h
├── QMPInteraction.h
├── QemuImgLauncher.cpp
├── PlatformInformationReader.cpp
├── QemuLauncher.cpp
└── QMPInteraction.cpp
├── .gitignore
├── device
├── DeviceBus.cpp
├── DeviceFactory.cpp
├── DeviceUsb.h
├── DeviceBus.h
├── DeviceFactory.h
├── DeviceNetwork.h
├── DeviceUsb.cpp
├── DeviceSystem.h
├── Device.h
├── Device.cpp
├── DeviceNetwork.cpp
├── DeviceSystem.cpp
├── DeviceStorage.h
└── DeviceStorage.cpp
├── config
├── PlatformInfo.h
├── QemuList.h
├── RecordReplayParams.h
├── VMConfig.h
├── GlobalConfig.h
├── PlatformInfo.cpp
├── RecordReplayParams.cpp
├── QemuList.cpp
├── VMConfig.cpp
└── GlobalConfig.cpp
├── CMakeLists.txt
├── cli
└── main.cpp
└── LICENSE
/docs/imgs/create_vm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/docs/imgs/create_vm.png
--------------------------------------------------------------------------------
/gui/Resources/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/pause.png
--------------------------------------------------------------------------------
/gui/Resources/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/play.png
--------------------------------------------------------------------------------
/gui/Resources/qemu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/qemu.png
--------------------------------------------------------------------------------
/gui/Resources/stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/stop.png
--------------------------------------------------------------------------------
/docs/imgs/recordreplay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/docs/imgs/recordreplay.png
--------------------------------------------------------------------------------
/docs/imgs/vm_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/docs/imgs/vm_settings.png
--------------------------------------------------------------------------------
/gui/Resources/create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/create.png
--------------------------------------------------------------------------------
/gui/Resources/import.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/import.png
--------------------------------------------------------------------------------
/gui/Resources/replay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/replay.png
--------------------------------------------------------------------------------
/gui/Resources/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/settings.png
--------------------------------------------------------------------------------
/gui/Resources/pause_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/pause_disable.png
--------------------------------------------------------------------------------
/gui/Resources/play_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/play_disable.png
--------------------------------------------------------------------------------
/gui/Resources/run_options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/run_options.png
--------------------------------------------------------------------------------
/gui/Resources/stop_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/stop_disable.png
--------------------------------------------------------------------------------
/gui/Resources/create_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/create_disable.png
--------------------------------------------------------------------------------
/gui/Resources/import_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/import_disable.png
--------------------------------------------------------------------------------
/gui/Resources/run_options_mini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/run_options_mini.png
--------------------------------------------------------------------------------
/gui/Resources/settings_disable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ispras/qemu-gui/HEAD/gui/Resources/settings_disable.png
--------------------------------------------------------------------------------
/.whitesource:
--------------------------------------------------------------------------------
1 | {
2 | "checkRunSettings": {
3 | "vulnerableCheckRunConclusionLevel": "failure"
4 | },
5 | "issueSettings": {
6 | "minSeverityLevel": "LOW"
7 | }
8 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | 
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 | 
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 | 
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------