mb@1
|
1 |
#!/bin/python
|
mb@1
|
2 |
import os
|
mb@1
|
3 |
import time
|
mb@1
|
4 |
import dbus
|
mb@1
|
5 |
import sys
|
mb@1
|
6 |
import subprocess
|
mb@1
|
7 |
from qubes.qubes import QubesVmCollection
|
mb@1
|
8 |
from qubes.qubes import QubesDispVmLabels
|
mb@1
|
9 |
from qubes.qubes import QubesException
|
mb@1
|
10 |
from qubes.qubes import QubesVmLabels
|
mb@1
|
11 |
from qubes.qmemman_client import QMemmanClient
|
mb@1
|
12 |
from qubes.qubesutils import block_list,block_attach,block_detach,block_detach_all,block_check_attached
|
mb@1
|
13 |
from qubes.qubesutils import kbytes_to_kmg, bytes_to_kmg
|
mb@1
|
14 |
|
mb@1
|
15 |
|
mb@1
|
16 |
notify_object = None
|
mb@1
|
17 |
current_savefile = '/var/run/qubes/current_savefile'
|
mb@1
|
18 |
current_dvm_conf = '/var/run/qubes/current_dvm.conf'
|
mb@1
|
19 |
avir_appvm_template = 'avir-template'
|
mb@1
|
20 |
avir_dvm_template = 'avir-template-dvm'
|
mb@1
|
21 |
|
mb@1
|
22 |
def get_vm_collection():
|
mb@1
|
23 |
vm_collection = QubesVmCollection()
|
mb@1
|
24 |
vm_collection.lock_db_for_reading()
|
mb@1
|
25 |
vm_collection.load()
|
mb@1
|
26 |
vm_collection.unlock_db()
|
mb@1
|
27 |
return vm_collection
|
mb@1
|
28 |
|
mb@1
|
29 |
def get_vm_by_name(vmname):
|
mb@1
|
30 |
return get_vm_collection().get_vm_by_name(vmname)
|
mb@1
|
31 |
|
mb@1
|
32 |
def gen_scanner_name():
|
mb@1
|
33 |
vm_collection = get_vm_collection()
|
mb@1
|
34 |
vms = [vm for vm in vm_collection.values()]
|
mb@1
|
35 |
vm_names = []
|
mb@1
|
36 |
for vm in vms:
|
mb@1
|
37 |
if vm.is_appvm() and vm.template.name == avir_appvm_template:
|
mb@1
|
38 |
vm_names.append (vm.name)
|
mb@1
|
39 |
print vm_names
|
mb@1
|
40 |
|
mb@1
|
41 |
ids = range(100)
|
mb@1
|
42 |
for id in ids:
|
mb@1
|
43 |
if "scanner"+str(id) not in vm_names:
|
mb@1
|
44 |
return "scanner"+str(id)
|
mb@1
|
45 |
print >> sys.stderr, "Unable to generate new scanner vm name"
|
mb@1
|
46 |
exit(1)
|
mb@1
|
47 |
|
mb@1
|
48 |
class VMFactory:
|
mb@1
|
49 |
def __init__(self):
|
mb@1
|
50 |
self.tray_notify(str="Initialized")
|
mb@1
|
51 |
|
mb@1
|
52 |
def tray_notify(self, str, timeout = 3000):
|
mb@1
|
53 |
notify_object.Notify("Qubes", 0, "red", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
|
mb@1
|
54 |
|
mb@1
|
55 |
def tray_notify_error(self, str, timeout = 3000):
|
mb@1
|
56 |
notify_object.Notify("Qubes", 0, "dialog-error", "Qubes", str, [], [], timeout, dbus_interface="org.freedesktop.Notifications")
|
mb@1
|
57 |
|
mb@1
|
58 |
def create_appvm(self):
|
mb@1
|
59 |
#generate new avir-scanner name
|
mb@1
|
60 |
scanner_vmname = gen_scanner_name()
|
mb@1
|
61 |
print "Generating new scanner vm %s " % scanner_vmname
|
mb@1
|
62 |
|
mb@1
|
63 |
#create new vscanner virtual machine from template "avir-template"
|
mb@1
|
64 |
qvm_collection = QubesVmCollection()
|
mb@1
|
65 |
qvm_collection.lock_db_for_writing()
|
mb@1
|
66 |
qvm_collection.load()
|
mb@1
|
67 |
avir_template = qvm_collection.get_vm_by_name(avir_appvm_template)
|
mb@1
|
68 |
if not avir_template.is_template():
|
mb@1
|
69 |
print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(avir_template)
|
mb@1
|
70 |
exit (1)
|
mb@1
|
71 |
vmtype = "QubesAppVm"
|
mb@1
|
72 |
|
mb@1
|
73 |
try:
|
mb@1
|
74 |
scanner_vm = qvm_collection.add_new_vm(vmtype, name=scanner_vmname, template=avir_template, label = QubesVmLabels["orange"])
|
mb@1
|
75 |
except QubesException as err:
|
mb@1
|
76 |
print >> sys.stderr, "ERROR: {0}".format(err)
|
mb@1
|
77 |
exit (1)
|
mb@1
|
78 |
|
mb@1
|
79 |
scanner_vm.memory = 512
|
mb@1
|
80 |
scanner_vm.vcpus = 2
|
mb@1
|
81 |
try:
|
mb@1
|
82 |
scanner_vm.create_on_disk(verbose=True, source_template=avir_template)
|
mb@1
|
83 |
#if options.root:
|
mb@1
|
84 |
# os.unlink(vm.root_img)
|
mb@1
|
85 |
# os.rename(options.root, vm.root_img)
|
mb@1
|
86 |
except (IOError, OSError) as err:
|
mb@1
|
87 |
print >> sys.stderr, "ERROR: {0}".format(err)
|
mb@1
|
88 |
exit (1)
|
mb@1
|
89 |
|
mb@1
|
90 |
qvm_collection.save()
|
mb@1
|
91 |
qvm_collection.unlock_db()
|
mb@1
|
92 |
return scanner_vmname
|
mb@1
|
93 |
|
mb@1
|
94 |
def start_vm(self, vmname):
|
mb@1
|
95 |
vm = get_vm_by_name(vmname)
|
mb@1
|
96 |
if vm is None or vm.qid not in get_vm_collection():
|
mb@1
|
97 |
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
mb@1
|
98 |
exit(1)
|
mb@1
|
99 |
try:
|
mb@1
|
100 |
vm.verify_files()
|
mb@1
|
101 |
xid = vm.start(verbose=True, preparing_dvm=False, start_guid=True, notify_function=None)
|
mb@1
|
102 |
except (IOError, OSError, QubesException, MemoryError) as err:
|
mb@1
|
103 |
#if options.tray:
|
mb@1
|
104 |
# tray_notify_error(str(err))
|
mb@1
|
105 |
#else:
|
mb@1
|
106 |
print >> sys.stderr, "ERROR: {0}".format(err)
|
mb@1
|
107 |
exit (1)
|
mb@1
|
108 |
|
mb@1
|
109 |
def create_dvm(self):
|
mb@1
|
110 |
qmemman_client = QMemmanClient()
|
mb@1
|
111 |
if not qmemman_client.request_memory(400*1024*1024):
|
mb@1
|
112 |
qmemman_client.close()
|
mb@1
|
113 |
errmsg = 'Not enough memory to create DVM. '
|
mb@1
|
114 |
errmsg +='Terminate some appVM and retry.'
|
mb@1
|
115 |
if os.path.exists('/usr/bin/kdialog'):
|
mb@1
|
116 |
subprocess.call(['/usr/bin/kdialog', '--sorry', errmsg])
|
mb@1
|
117 |
else:
|
mb@1
|
118 |
subprocess.call(['/usr/bin/zenity', '--warning', errmsg])
|
mb@1
|
119 |
return None
|
mb@1
|
120 |
self.tray_notify("Starting new DispVM...")
|
mb@1
|
121 |
|
mb@1
|
122 |
qvm_collection = QubesVmCollection()
|
mb@1
|
123 |
qvm_collection.lock_db_for_writing()
|
mb@1
|
124 |
qvm_collection.load()
|
mb@1
|
125 |
avir_template = qvm_collection.get_vm_by_name(avir_dvm_template)
|
mb@1
|
126 |
if avir_template is None:
|
mb@1
|
127 |
sys.stderr.write( 'Domain ' + avir_dvm_template + ' does not exist ?')
|
mb@1
|
128 |
qvm_collection.unlock_db()
|
mb@1
|
129 |
qmemman_client.close()
|
mb@1
|
130 |
return None
|
mb@1
|
131 |
label = avir_template.label
|
mb@1
|
132 |
retcode = subprocess.call(['/usr/lib/qubes/qubes_restore',
|
mb@1
|
133 |
current_savefile,
|
mb@1
|
134 |
current_dvm_conf,
|
mb@1
|
135 |
'-u', str(avir_template.default_user),
|
mb@1
|
136 |
'-c', label.color,
|
mb@1
|
137 |
'-i', label.icon_path,
|
mb@1
|
138 |
'-l', str(label.index)])
|
mb@1
|
139 |
qmemman_client.close()
|
mb@1
|
140 |
if retcode != 0:
|
mb@1
|
141 |
if os.path.exists('/usr/bin/kdialog'):
|
mb@1
|
142 |
subprocess.call(['/usr/bin/kdialog', '--sorry', 'DisposableVM creation failed, see qubes_restore.log'])
|
mb@1
|
143 |
else:
|
mb@1
|
144 |
subprocess.call(['/usr/bin/zenity', '--warning', 'DisposableVM creation failed, see qubes_restore.log'])
|
mb@1
|
145 |
qvm_collection.unlock_db()
|
mb@1
|
146 |
return None
|
mb@1
|
147 |
|
mb@1
|
148 |
f = open('/var/run/qubes/dispVM_xid', 'r');
|
mb@1
|
149 |
disp_xid = f.readline().rstrip('\n')
|
mb@1
|
150 |
disp_name = f.readline().rstrip('\n')
|
mb@1
|
151 |
disptempl = f.readline().rstrip('\n')
|
mb@1
|
152 |
f.close()
|
mb@1
|
153 |
|
mb@1
|
154 |
print >>sys.stderr, "getting vm %s" % disptempl
|
mb@1
|
155 |
avir_disptempl = qvm_collection.get_vm_by_name(disptempl);
|
mb@1
|
156 |
if avir_disptempl is None:
|
mb@1
|
157 |
sys.stderr.write( 'Domain ' + disptempl + ' does not exist ?')
|
mb@1
|
158 |
qvm_collection.unlock_db()
|
mb@1
|
159 |
return None
|
mb@1
|
160 |
|
mb@1
|
161 |
dispid = int(disp_name[4:])
|
mb@1
|
162 |
dispvm = qvm_collection.add_new_disposablevm(disp_name, avir_disptempl.template, label=label, dispid=dispid, netvm=avir_disptempl.netvm)
|
mb@1
|
163 |
print >> sys.stderr, "Waiting for the VM %s to startup...", dispvm.name
|
mb@1
|
164 |
startup_counter = 0
|
mb@1
|
165 |
startup_counter_max = 60
|
mb@1
|
166 |
while startup_counter < startup_counter_max:
|
mb@1
|
167 |
if dispvm.is_running():
|
mb@1
|
168 |
break
|
mb@1
|
169 |
shutdown_counter += 1
|
mb@1
|
170 |
time.sleep (1)
|
mb@1
|
171 |
|
mb@1
|
172 |
qvm_collection.save()
|
mb@1
|
173 |
qvm_collection.unlock_db()
|
mb@1
|
174 |
return dispvm.name
|
mb@1
|
175 |
|
mb@1
|
176 |
def stop_vm(self, vmname):
|
mb@1
|
177 |
vm = get_vm_by_name(vmname)
|
mb@1
|
178 |
if vm is None or vm.qid not in get_vm_collection():
|
mb@1
|
179 |
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
mb@1
|
180 |
exit(1)
|
mb@1
|
181 |
vm.shutdown(force=True)
|
mb@1
|
182 |
print >> sys.stderr, "Waiting for the VM %s to shutdown...", vmname
|
mb@1
|
183 |
shutdown_counter = 0
|
mb@1
|
184 |
shutdown_counter_max = 60
|
mb@1
|
185 |
while shutdown_counter < shutdown_counter_max:
|
mb@1
|
186 |
if not vm.is_running():
|
mb@1
|
187 |
return
|
mb@1
|
188 |
shutdown_counter += 1
|
mb@1
|
189 |
time.sleep (1)
|
mb@1
|
190 |
|
mb@1
|
191 |
def remove_vm(self, vmname):
|
mb@1
|
192 |
qvm_collection = QubesVmCollection()
|
mb@1
|
193 |
qvm_collection.lock_db_for_writing()
|
mb@1
|
194 |
qvm_collection.load()
|
mb@1
|
195 |
vm = qvm_collection.get_vm_by_name(vmname)
|
mb@1
|
196 |
|
mb@1
|
197 |
if vm is None or vm.qid not in qvm_collection:
|
mb@1
|
198 |
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
mb@1
|
199 |
exit(1)
|
mb@1
|
200 |
|
mb@1
|
201 |
if vm.is_running():
|
mb@1
|
202 |
print >> sys.stderr, "Cannot remove a running VM, stop it first"
|
mb@1
|
203 |
exit (1)
|
mb@1
|
204 |
|
mb@1
|
205 |
if vm.is_template():
|
mb@1
|
206 |
dependent_vms = qvm_collection.get_vms_based_on(vm.qid)
|
mb@1
|
207 |
if len(dependent_vms) > 0:
|
mb@1
|
208 |
print >> sys.stderr, "The following AppVMs use '{0}' as a template:".format(vmname)
|
mb@1
|
209 |
for vm in dependent_vms:
|
mb@1
|
210 |
print >> sys.stderr, "{name:<12} (qid={qid})".format(qid=vm.qid, name=vm.name)
|
mb@1
|
211 |
print >> sys.stderr, "Please remove those VMs first."
|
mb@1
|
212 |
exit (1)
|
mb@1
|
213 |
if qvm_collection.default_template_qid == vm.qid:
|
mb@1
|
214 |
qvm_collection.default_template_qid = None
|
mb@1
|
215 |
|
mb@1
|
216 |
try:
|
mb@1
|
217 |
vm.remove_from_disk()
|
mb@1
|
218 |
except (IOError, OSError) as err:
|
mb@1
|
219 |
print >> sys.stderr, "Warning: {0}".format(err)
|
mb@1
|
220 |
|
mb@1
|
221 |
# Do not exit, perhaps the VM files were somehow removed
|
mb@1
|
222 |
# so just remove it from Qubes DB
|
mb@1
|
223 |
qvm_collection.pop(vm.qid)
|
mb@1
|
224 |
qvm_collection.save()
|
mb@1
|
225 |
qvm_collection.unlock_db()
|
mb@1
|
226 |
|
mb@1
|
227 |
def attach_dev(self, vmname, devname):
|
mb@1
|
228 |
vm = get_vm_by_name(vmname)
|
mb@1
|
229 |
if vm is None or vm.qid not in get_vm_collection():
|
mb@1
|
230 |
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
mb@1
|
231 |
exit(1)
|
mb@1
|
232 |
print "Attaching %s to vm - %s" % (devname, vm.name)
|
mb@1
|
233 |
kwargs = {}
|
mb@1
|
234 |
kwargs['auto_detach'] = True
|
mb@1
|
235 |
try:
|
mb@1
|
236 |
backend_vm = get_vm_by_name("dom0")
|
mb@1
|
237 |
block_attach(vm, backend_vm, devname, **kwargs)
|
mb@1
|
238 |
except QubesException as e:
|
mb@1
|
239 |
print >> sys.stderr, "ERROR: %s" % str(e)
|
mb@1
|
240 |
exit(1)
|
mb@1
|
241 |
|
mb@1
|
242 |
def detach_dev(self, vmname, devname):
|
mb@1
|
243 |
vm = get_vm_by_name(vmname)
|
mb@1
|
244 |
if vm is None or vm.qid not in get_vm_collection():
|
mb@1
|
245 |
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
mb@1
|
246 |
exit(1)
|
mb@1
|
247 |
print "Detaching %s from vm - %s" % (devname, vmname)
|
mb@1
|
248 |
kwargs = {}
|
mb@1
|
249 |
#kwargs['frontend'] = "to_scan"
|
mb@1
|
250 |
try:
|
mb@1
|
251 |
block_detach(vm, **kwargs)
|
mb@1
|
252 |
except QubesException as e:
|
mb@1
|
253 |
print >> sys.stderr, "ERROR: %s" % str(e)
|
mb@1
|
254 |
sys.exit(1)
|
mb@1
|
255 |
|
mb@1
|
256 |
def scan(self, vmname):
|
mb@1
|
257 |
vm = get_vm_by_name(vmname)
|
mb@1
|
258 |
if vm is None or vm.qid not in get_vm_collection():
|
mb@1
|
259 |
print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
|
mb@1
|
260 |
exit(1)
|
mb@1
|
261 |
subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:mount /dev/xvdi /mnt/removable'])
|
mb@1
|
262 |
#subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:clamscan /mnt/removable'])
|
mb@1
|
263 |
subprocess.call(['/usr/lib/qubes/qrexec_client', '-d', vmname, 'root:umount /mnt/removable'])
|
mb@1
|
264 |
|
mb@1
|
265 |
|
mb@1
|
266 |
def main():
|
mb@1
|
267 |
global notify_object
|
mb@1
|
268 |
print >>sys.stderr, "time=%s, qfile-daemon-dvm init" % (str(time.time()))
|
mb@1
|
269 |
notify_object = dbus.SessionBus().get_object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
|
mb@1
|
270 |
vm_factory = VMFactory()
|
mb@1
|
271 |
#vmname = vm_factory.create_dvm()
|
mb@1
|
272 |
vmname = vm_factory.create_appvm()
|
mb@1
|
273 |
vm_factory.start_vm(vmname)
|
mb@1
|
274 |
vm_factory.attach_dev(vmname, "sdb")
|
mb@1
|
275 |
vm_factory.scan(vmname)
|
mb@1
|
276 |
vm_factory.detach_dev(vmname, "sdb")
|
mb@1
|
277 |
#vm_factory.stop_vm(vmname)
|
mb@1
|
278 |
#vm_factory.remove_vm(vmname)
|
mb@1
|
279 |
|
mb@1
|
280 |
main()
|