diff --git a/icons/run-command.png b/icons/run-command.png
new file mode 100644
index 0000000..9dcc87a
Binary files /dev/null and b/icons/run-command.png differ
diff --git a/mainwindow.ui b/mainwindow.ui
index 30cfa25..7f17ac8 100644
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -295,6 +295,7 @@
+
@@ -725,6 +726,18 @@
Size on Disk
+
+
+
+ :/run-command.png:/run-command.png
+
+
+ Run command in VM
+
+
+ Run command in the specified VM
+
+
diff --git a/qubesmanager/main.py b/qubesmanager/main.py
index 91a80c3..f99340b 100755
--- a/qubesmanager/main.py
+++ b/qubesmanager/main.py
@@ -23,6 +23,7 @@
import sys
import os
import fcntl
+import errno
import dbus
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -735,6 +736,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.context_menu.addAction(self.action_appmenus)
self.context_menu.addAction(self.action_editfwrules)
self.context_menu.addAction(self.action_updatevm)
+ self.context_menu.addAction(self.action_run_command_in_vm)
self.context_menu.addAction(self.action_set_keyboard_layout)
self.context_menu.addMenu(self.logs_menu)
self.context_menu.addMenu(self.blk_menu)
@@ -1040,6 +1042,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.action_appmenus.setEnabled(not vm.is_netvm())
self.action_editfwrules.setEnabled(vm.is_networked() and not (vm.is_netvm() and not vm.is_proxyvm()))
self.action_updatevm.setEnabled(vm.is_updateable() or vm.qid == 0)
+ self.action_run_command_in_vm.setEnabled(vm.qid != 0)
self.action_set_keyboard_layout.setEnabled(vm.qid != 0 and vm.last_running)
else:
self.action_settings.setEnabled(False)
@@ -1051,6 +1054,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
self.action_appmenus.setEnabled(False)
self.action_editfwrules.setEnabled(False)
self.action_updatevm.setEnabled(False)
+ self.action_run_command_in_vm.setEnabled(False)
self.action_set_keyboard_layout.setEnabled(False)
@@ -1401,6 +1405,47 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
thread_monitor.set_finished()
+ @pyqtSlot(name='on_action_run_command_in_vm_triggered')
+ def action_run_command_in_vm_triggered(self):
+ vm = self.get_selected_vm()
+
+ thread_monitor = ThreadMonitor()
+ thread = threading.Thread (target=self.do_run_command_in_vm, args=(vm, thread_monitor))
+ thread.daemon = True
+ thread.start()
+
+ while not thread_monitor.is_finished():
+ app.processEvents()
+ time.sleep (0.2)
+
+ if not thread_monitor.success:
+ QMessageBox.warning (None, "Error while running command", "Exception while running command:
{0}".format(thread_monitor.error_msg))
+
+
+ def do_run_command_in_vm(self, vm, thread_monitor):
+ cmd = ['kdialog', '--title', 'Qubes command entry', '--inputbox', 'Run command in '+vm.name+':']
+ kdialog = subprocess.Popen(cmd, stdout = subprocess.PIPE)
+ command_to_run = kdialog.stdout.read()
+ command_to_run = "'"+command_to_run.strip()+"'"
+ if command_to_run != "":
+ command_to_run = "qvm-run -a "+ vm.name + " " + command_to_run
+ try:
+ subprocess.check_call(command_to_run, shell=True)
+ except OSError as ex:
+ if ex.errno == errno.EINTR:
+ pass
+ else:
+ thread_monitor.set_error_msg(str(ex))
+ thread_monitor.set_finished()
+ except Exception as ex:
+ thread_monitor.set_error_msg(str(ex))
+ thread_monitor.set_finished()
+ thread_monitor.set_finished()
+
+
+
+
+
@pyqtSlot(name='on_action_set_keyboard_layout_triggered')
def action_set_keyboard_layout_triggered(self):
vm = self.get_selected_vm()
diff --git a/resources.qrc b/resources.qrc
index 0ca3594..e418cf4 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -12,6 +12,7 @@
icons/show-all-running.png
icons/mount.png
icons/log.png
+ icons/run-command.png
icons/kbd-layout.png
icons/copy.png
icons/pencil.png