qvm-prefs 15 KB

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