qvm-prefs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. #!/usr/bin/python2
  2. # -*- encoding: utf8 -*-
  3. #
  4. # The Qubes OS Project, http://www.qubes-os.org
  5. #
  6. # Copyright (C) 2010 Joanna Rutkowska <joanna@invisiblethingslab.com>
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License
  10. # as published by the Free Software Foundation; either version 2
  11. # of the License, or (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. #
  22. #
  23. from qubes.qubes import QubesVmCollection
  24. from qubes.qubes import QubesVmLabels
  25. from qubes.qubes import QubesHost
  26. from qubes.qubes import system_path
  27. from optparse import OptionParser
  28. import subprocess
  29. import os
  30. import sys
  31. import re
  32. def do_list(vm):
  33. label_width = 19
  34. fmt="{{0:<{0}}}: {{1}}".format(label_width)
  35. print fmt.format ("name", vm.name)
  36. print fmt.format ("label", vm.label.name)
  37. print fmt.format ("type", vm.type)
  38. if vm.template is not None:
  39. print fmt.format ("template", vm.template.name)
  40. if vm.netvm is not None:
  41. print fmt.format ("netvm", vm.netvm.name)
  42. print fmt.format ("updateable", vm.updateable)
  43. print fmt.format ("autostart", vm.autostart)
  44. print fmt.format ("installed_by_rpm", vm.installed_by_rpm)
  45. print fmt.format ("include_in_backups", vm.include_in_backups)
  46. print fmt.format ("last_backup", vm.backup_timestamp)
  47. print fmt.format ("dir", vm.dir_path)
  48. print fmt.format ("config", vm.conf_file)
  49. print fmt.format ("pcidevs", vm.pcidevs)
  50. if vm.template is None:
  51. print fmt.format ("root_img", vm.root_img)
  52. if hasattr(vm, "rootcow_img") and vm.rootcow_img is not None:
  53. print fmt.format ("root_cow_img", vm.rootcow_img)
  54. if vm.template is not None:
  55. print fmt.format ("root_img", vm.template.root_img)
  56. if hasattr(vm, 'volatile_img') and vm.volatile_img is not None:
  57. print fmt.format ("root_volatile_img", vm.volatile_img)
  58. if hasattr(vm, 'private_img') and vm.private_img is not None:
  59. print fmt.format ("private_img", vm.private_img)
  60. print fmt.format ("vcpus", str(vm.vcpus))
  61. print fmt.format ("memory", vm.memory)
  62. if hasattr(vm, 'maxmem'):
  63. print fmt.format ("maxmem", vm.maxmem)
  64. print fmt.format ("MAC", "%s%s" % (vm.mac, " (auto)" if vm._mac is None else ""))
  65. if hasattr(vm, 'kernel'):
  66. if vm.uses_default_kernel:
  67. print fmt.format ("kernel", "%s (default)" % vm.kernel)
  68. else:
  69. print fmt.format ("kernel", vm.kernel)
  70. if hasattr(vm, 'kernelopts'):
  71. if vm.uses_default_kernelopts:
  72. print fmt.format ("kernelopts", "%s (default)" % vm.kernelopts)
  73. else:
  74. print fmt.format ("kernelopts", vm.kernelopts)
  75. if hasattr(vm, 'debug'):
  76. print fmt.format("debug", "on" if vm.debug else "off")
  77. if hasattr(vm, 'default_user'):
  78. print fmt.format("default_user", str(vm.default_user))
  79. if hasattr(vm, 'qrexec_installed'):
  80. print fmt.format("qrexec_installed", str(vm.qrexec_installed))
  81. if hasattr(vm, 'qrexec_timeout'):
  82. print fmt.format("qrexec_timeout", str(vm.qrexec_timeout))
  83. if hasattr(vm, 'guiagent_installed'):
  84. print fmt.format("guiagent_installed", str(vm.guiagent_installed))
  85. if hasattr(vm, 'seamless_gui_mode'):
  86. print fmt.format("seamless_gui_mode", str(vm.seamless_gui_mode))
  87. if hasattr(vm, 'drive'):
  88. print fmt.format("drive", str(vm.drive))
  89. if hasattr(vm, 'timezone'):
  90. print fmt.format("timezone", str(vm.timezone))
  91. print fmt.format ("internal", vm.internal)
  92. def set_label(vms, vm, args):
  93. if len (args) != 1:
  94. print >> sys.stderr, "Missing label name argument!"
  95. return False
  96. label = args[0]
  97. if label not in QubesVmLabels:
  98. print >> sys.stderr, "Wrong label name, supported values are the following:"
  99. for l in QubesVmLabels.values():
  100. print >> sys.stderr, "* {0}".format(l.name)
  101. return False
  102. vm.label = QubesVmLabels[label]
  103. return True
  104. def set_memory(vms, vm, args):
  105. if len (args) != 1:
  106. print >> sys.stderr, "Missing memory argument!"
  107. return False
  108. new_memory = int(args[0])
  109. if new_memory <= 0:
  110. print >>sys.stderr, "Memory size must be positive"
  111. return False
  112. qubes_host = QubesHost()
  113. if new_memory > qubes_host.memory_total/1024:
  114. print >> sys.stderr, "This host has only {0} MB of RAM".format(qubes_host.memory_total/1024)
  115. return False
  116. vm.memory = new_memory
  117. return True
  118. def set_maxmem(vms, vm, args):
  119. if len (args) != 1:
  120. print >> sys.stderr, "Missing maxmem argument!"
  121. exit (1)
  122. new_maxmem = int(args[0])
  123. if new_maxmem <= 0:
  124. print >>sys.stderr, "Memory size must be positive"
  125. return False
  126. qubes_host = QubesHost()
  127. if new_maxmem > qubes_host.memory_total/1024:
  128. print >> sys.stderr, "This host has only {0} MB of RAM".format(qubes_host.memory_total/1024)
  129. return False
  130. if new_maxmem < vm.memory:
  131. print >> sys.stderr, "WARNING: new maxmem smaller than memory property - VM will be able to use only 'maxmem' memory amount"
  132. vm.maxmem = new_maxmem
  133. return True
  134. def set_mac(vms, vm, args):
  135. if len (args) != 1:
  136. print >> sys.stderr, "Missing MAC argument!"
  137. return False
  138. if not re.match("[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}|auto", args[0]):
  139. print >> sys.stderr, "Invalid MAC argument!"
  140. print >> sys.stderr, "Possible values:"
  141. print >> sys.stderr, "1) auto"
  142. print >> sys.stderr, "2) MAC in format: XX:XX:XX:XX:XX:XX"
  143. return False
  144. mac = args[0]
  145. if mac == "auto":
  146. mac = None
  147. vm.mac = mac
  148. return True
  149. def set_pcidevs(vms, vm, args):
  150. if len (args) != 1:
  151. print >> sys.stderr, "Missing pcidevs argument!"
  152. return False
  153. if vm.is_running():
  154. print >>sys.stderr, "Cannot modify PCI devices of running VM, " \
  155. "use qvm-pci instead"
  156. return False
  157. vm.pcidevs = list(eval(args[0]))
  158. return True
  159. def set_netvm(vms, vm, args):
  160. if len (args) != 1:
  161. print >> sys.stderr, "Missing netvm name argument!"
  162. print >> sys.stderr, "Possible values:"
  163. print >> sys.stderr, "1) default"
  164. print >> sys.stderr, "2) none"
  165. print >> sys.stderr, "3) <vmaname>"
  166. return
  167. netvm = args[0]
  168. if netvm == "none":
  169. netvm = None
  170. vm.uses_default_netvm = False
  171. elif netvm == "default":
  172. netvm = vms.get_default_netvm()
  173. vm.uses_default_netvm = True
  174. else:
  175. netvm = vms.get_vm_by_name (netvm)
  176. if netvm is None:
  177. print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(netvm)
  178. return False
  179. if not netvm.is_netvm():
  180. print >> sys.stderr, "VM '{0}' is not a NetVM".format(netvm)
  181. return False
  182. vm.uses_default_netvm = False
  183. vm.netvm = netvm
  184. return True
  185. def set_kernel(vms, vm, args):
  186. if len (args) != 1:
  187. print >> sys.stderr, "Missing kernel version argument!"
  188. print >> sys.stderr, "Possible values:"
  189. print >> sys.stderr, "1) default"
  190. print >> sys.stderr, "2) none (kernels subdir in VM)"
  191. print >> sys.stderr, "3) <kernel version>, one of:"
  192. for k in os.listdir(system_path["qubes_kernels_base_dir"]):
  193. print >> sys.stderr, " -", k
  194. return False
  195. kernel = args[0]
  196. if kernel == "default":
  197. kernel = vms.get_default_kernel()
  198. vm.uses_default_kernel = True
  199. elif kernel == "none":
  200. kernel = None
  201. vm.uses_default_kernel = False
  202. else:
  203. if not os.path.exists(os.path.join(system_path["qubes_kernels_base_dir"], kernel)):
  204. print >> sys.stderr, "Kernel version {0} not installed.".format(kernel)
  205. return False
  206. vm.uses_default_kernel = False
  207. vm.kernel = kernel
  208. return True
  209. def set_template(vms, vm, args):
  210. if len (args) != 1:
  211. print >> sys.stderr, "Missing template name argument!"
  212. return False
  213. template_name = args[0];
  214. template = vms.get_vm_by_name(template_name)
  215. if template is None or template.qid not in vms:
  216. print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(template_name)
  217. return False
  218. if not template.is_template():
  219. print >> sys.stderr, "VM '{0}' is not a TemplateVM".format(template_name)
  220. return False
  221. print >> sys.stderr, "Setting template for VM '{0}' to '{1}'...".format (vm.name, template_name)
  222. vm.template = template
  223. return True
  224. def set_vcpus(vms, vm, args):
  225. if len (args) != 1:
  226. print >> sys.stderr, "Missing vcpus count argument!"
  227. return False
  228. vcpus = int(args[0])
  229. if vcpus <= 0:
  230. print >> sys.stderr, "A vcpus count must be positive."
  231. return False
  232. qubes_host = QubesHost()
  233. if vcpus > qubes_host.no_cpus:
  234. print >> sys.stderr, "This host has only {0} cpus".format(ubes_host.no_cpus)
  235. return False
  236. print >> sys.stderr, "Setting vcpus count for VM '{0}' to '{1}'...".format (vm.name, vcpus)
  237. vm.vcpus = vcpus
  238. return True
  239. def set_kernelopts(vms, vm, args):
  240. if len (args) != 1:
  241. print >> sys.stderr, "Missing kernel opts argument!"
  242. print >> sys.stderr, "Possible values:"
  243. print >> sys.stderr, "1) default"
  244. print >> sys.stderr, "2) <opts>"
  245. return False
  246. if args[0] == 'default':
  247. vm.uses_default_kernelopts = True
  248. else:
  249. vm.uses_default_kernelopts = False
  250. vm.kernelopts = args[0]
  251. return True
  252. def set_name(vms, vm, args):
  253. if len (args) != 1:
  254. print >> sys.stderr, "Missing new name!"
  255. return False
  256. if args[0] == vm.name:
  257. return False
  258. vm.set_name(args[0])
  259. return True
  260. def set_drive(vms, vm, args):
  261. if len (args) != 1:
  262. print >> sys.stderr, "Missing new drive content (file/device)!"
  263. return False
  264. if args[0] == '' or args[0].lower() == 'none':
  265. vm.drive = None
  266. else:
  267. vm.drive = args[0]
  268. return True
  269. def set_debug(vms, vm, args):
  270. if len (args) != 1:
  271. print >> sys.stderr, "Missing value (True/False or on/off)!"
  272. return False
  273. if args[0].lower() == "on":
  274. vm.debug = True
  275. elif args[0].lower() == "off":
  276. vm.debug = False
  277. else:
  278. vm.debug = bool(eval(args[0].capitalize()))
  279. return True
  280. def set_default_user(vms, vm, args):
  281. if len (args) != 1:
  282. print >> sys.stderr, "Missing user name!"
  283. return False
  284. vm.default_user = args[0]
  285. return True
  286. def set_include_in_backups(vms, vm, args):
  287. if len (args) != 1:
  288. print >> sys.stderr, "Missing value (True/False)!"
  289. return False
  290. vm.include_in_backups = bool(eval(args[0].capitalize()))
  291. return True
  292. def set_qrexec_installed(vms, vm, args):
  293. if len (args) != 1:
  294. print >> sys.stderr, "Missing value (True/False)!"
  295. return False
  296. vm.qrexec_installed = bool(eval(args[0].capitalize()))
  297. return True
  298. def set_internal(vms, vm, args):
  299. if len (args) != 1:
  300. print >> sys.stderr, "Missing value (True/False)!"
  301. return False
  302. vm.internal = bool(eval(args[0].capitalize()))
  303. return True
  304. def set_guiagent_installed(vms, vm, args):
  305. if len (args) != 1:
  306. print >> sys.stderr, "Missing value (True/False)!"
  307. return False
  308. vm.guiagent_installed = bool(eval(args[0].capitalize()))
  309. return True
  310. def set_seamless_gui_mode(vms, vm, args):
  311. if len(args) != 1:
  312. print >> sys.stderr, "Missing value (true/false)!"
  313. return False
  314. if not args[0].lower() in ['true', 'false']:
  315. print >> sys.stderr, "Invalid value, expected 'true' or 'false'"
  316. return False
  317. if args[0].lower() == 'true':
  318. vm.seamless_gui_mode = True
  319. else:
  320. vm.seamless_gui_mode = False
  321. return True
  322. def set_autostart(vms, vm, args):
  323. if len (args) != 1:
  324. print >> sys.stderr, "Missing value (True/False)!"
  325. return False
  326. vm.autostart = bool(eval(args[0].capitalize()))
  327. return True
  328. def set_qrexec_timeout(vms, vm, args):
  329. if len (args) != 1:
  330. print >> sys.stderr, "Missing timeout value (seconds)!"
  331. return False
  332. vm.qrexec_timeout = int(args[0])
  333. return True
  334. def set_timezone(vms, vm, args):
  335. if len (args) != 1:
  336. print >> sys.stderr, "Missing value ('localtime' or timeoffset in seconds)!"
  337. return False
  338. if not args[0].isdigit() and args[0].lower() == 'localtime':
  339. print >> sys.stderr, "Invalid timezone value!"
  340. return False
  341. vm.timezone = args[0]
  342. return True
  343. properties = {
  344. "include_in_backups": set_include_in_backups,
  345. "pcidevs": set_pcidevs,
  346. "label" : set_label,
  347. "netvm" : set_netvm,
  348. "maxmem" : set_maxmem,
  349. "memory" : set_memory,
  350. "kernel" : set_kernel,
  351. "template" : set_template,
  352. "vcpus" : set_vcpus,
  353. "kernelopts": set_kernelopts,
  354. "name": set_name,
  355. "drive": set_drive,
  356. "mac": set_mac,
  357. "debug": set_debug,
  358. "default_user": set_default_user,
  359. "qrexec_installed": set_qrexec_installed,
  360. "guiagent_installed": set_guiagent_installed,
  361. "seamless_gui_mode": set_seamless_gui_mode,
  362. "qrexec_timeout": set_qrexec_timeout,
  363. "timezone": set_timezone,
  364. "internal": set_internal,
  365. "autostart": set_autostart,
  366. }
  367. def do_set(vms, vm, property, args):
  368. if property not in properties.keys():
  369. print >> sys.stderr, "ERROR: Wrong property name: '{0}'".format(property)
  370. return False
  371. if not hasattr(vm, property):
  372. print >> sys.stderr, "ERROR: Property '{0}' not available for this VM".format(property)
  373. return False
  374. try:
  375. return properties[property](vms, vm, args)
  376. except Exception as err:
  377. print >> sys.stderr, "ERROR: %s" % str(err)
  378. return False
  379. def main():
  380. usage = "usage: %prog -l [options] <vm-name>\n"\
  381. "usage: %prog -s [options] <vm-name> <property> [...]\n"\
  382. "List/set various per-VM properties."
  383. parser = OptionParser (usage)
  384. parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
  385. parser.add_option ("-s", "--set", action="store_true", dest="do_set", default=False)
  386. parser.add_option ("--force-root", action="store_true", dest="force_root", default=False,
  387. help="Force to run, even with root privileges")
  388. (options, args) = parser.parse_args ()
  389. if (len (args) < 1):
  390. parser.error ("You must provide at least the vmname!")
  391. vmname = args[0]
  392. if os.geteuid() == 0:
  393. if not options.force_root:
  394. print >> sys.stderr, "*** Running this tool as root is strongly discouraged, this will lead you in permissions problems."
  395. print >> sys.stderr, "Retry as unprivileged user."
  396. print >> sys.stderr, "... or use --force-root to continue anyway."
  397. exit(1)
  398. if options.do_list and options.do_set:
  399. print >> sys.stderr, "You cannot provide -l and -s at the same time!"
  400. exit (1)
  401. if options.do_set:
  402. qvm_collection = QubesVmCollection()
  403. qvm_collection.lock_db_for_writing()
  404. qvm_collection.load()
  405. else:
  406. qvm_collection = QubesVmCollection()
  407. qvm_collection.lock_db_for_reading()
  408. qvm_collection.load()
  409. qvm_collection.unlock_db()
  410. vm = qvm_collection.get_vm_by_name(vmname)
  411. if vm is None or vm.qid not in qvm_collection:
  412. print >> sys.stderr, "A VM with the name '{0}' does not exist in the system.".format(vmname)
  413. exit(1)
  414. if options.do_set:
  415. if len (args) < 2:
  416. print >> sys.stderr, "You must specify the property you wish to set..."
  417. print >> sys.stderr, "Available properties:"
  418. for p in properties.keys():
  419. if hasattr(vm, p):
  420. print >> sys.stderr, "--> '{0}'".format(p)
  421. exit (1)
  422. property = args[1]
  423. if do_set(qvm_collection, vm, property, args[2:]):
  424. qvm_collection.save()
  425. qvm_collection.unlock_db()
  426. else:
  427. qvm_collection.unlock_db()
  428. exit(1)
  429. else:
  430. # do_list
  431. do_list(vm)
  432. main()